diff --git a/docs/help_docs/chinese/index.html b/docs/help_docs/chinese/index.html index 4a0b7a65..03037193 100644 --- a/docs/help_docs/chinese/index.html +++ b/docs/help_docs/chinese/index.html @@ -2681,9 +2681,10 @@
All-in-one Browser Automation Framework:Web Crawling / Testing / Scraping / Stealth
\ud83d\ude80 Start | \ud83c\udff0 Features | \ud83d\udcda Examples | \ud83c\udf9b\ufe0f Options | \ud83c\udf20 Scripts | \ud83d\udcf1 Mobile \ud83d\udcd8 APIs | \ud83d\udd21 Formats | \ud83d\udcca Dashboard | \ud83d\udd34 Recorder | \ud83d\uddfe Locales | \ud83c\udf10 Grid \ud83c\udf96\ufe0f GUI | \ud83d\udcf0 TestPage | \ud83d\uddc2\ufe0f CasePlans | \ud83d\udc64 UC Mode | \ud83e\uddec Hybrid | \ud83d\udcbb Farm \ud83d\udc41\ufe0f How | \ud83d\ude9d Migrate | \u267b\ufe0f Templates | \ud83d\ude89 NodeGUI | \ud83d\udcf6 Charts | \ud83d\ude8e Tours \ud83e\udd16 CI/CD | \ud83d\udd79\ufe0f JSMgr | \ud83c\udf0f Translator | \ud83c\udf9e\ufe0f Presenter | \ud83d\udec2 Dialog | \ud83d\uddbc\ufe0f Visual
\ud83d\udcda Learn from over 200 examples in the SeleniumBase/examples/ folder.
\ud83d\udc64 Note that SeleniumBase UC Mode / Stealth Mode has its own ReadMe.
\u2139\ufe0f Scripts can be called via python
, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover & collect tests automatically).
\ud83d\udcd7 Here's my_first_test.py, which tests login, shopping, and checkout:
pytest my_first_test.py\n
pytest
uses --chrome
by default unless set differently.
\ud83d\udcd7 Here's test_coffee_cart.py, which verifies an e-commerce site:
pytest test_coffee_cart.py --demo\n
(--demo
mode slows down tests and highlights actions)
\ud83d\udcd7 Here's test_demo_site.py, which covers several actions:
pytest test_demo_site.py\n
Easy to type, click, select, toggle, drag & drop, and more.
(For more examples, see the SeleniumBase/examples/ folder.)
Explore the README:
\ud83d\udca1 SeleniumBase is a Python framework for browser automation and testing. SeleniumBase uses Selenium/WebDriver APIs and incorporates test-runners such as pytest
, pynose
, and behave
to provide organized structure, test discovery, test execution, test state (eg. passed, failed, or skipped), and command-line options for changing default settings (eg. browser selection). With raw Selenium, you would need to set up your own options-parser for configuring tests from the command-line.
\ud83d\udca1 SeleniumBase's driver manager gives you more control over automatic driver downloads. (Use --driver-version=VER
with your pytest
run command to specify the version.) By default, SeleniumBase will download a driver version that matches your major browser version if not set.
\ud83d\udca1 SeleniumBase automatically detects between CSS Selectors and XPath, which means you don't need to specify the type of selector in your commands (but optionally you could).
\ud83d\udca1 SeleniumBase methods often perform multiple actions in a single method call. For example, self.type(selector, text)
does the following:1. Waits for the element to be visible.2. Waits for the element to be interactive.3. Clears the text field.4. Types in the new text.5. Presses Enter/Submit if the text ends in \"\\n\"
.With raw Selenium, those actions require multiple method calls.
\ud83d\udca1 SeleniumBase uses default timeout values when not set: \u2705 self.click(\"button\")
With raw Selenium, methods would fail instantly (by default) if an element needed more time to load: \u274c self.driver.find_element(by=\"css selector\", value=\"button\").click()
(Reliable code is better than unreliable code.)
\ud83d\udca1 SeleniumBase lets you change the explicit timeout values of methods: \u2705 self.click(\"button\", timeout=10)
With raw Selenium, that requires more code: \u274c WebDriverWait(driver, 10).until(EC.element_to_be_clickable(\"css selector\", \"button\")).click()
(Simple code is better than complex code.)
\ud83d\udca1 SeleniumBase gives you clean error output when a test fails. With raw Selenium, error messages can get very messy.
\ud83d\udca1 SeleniumBase gives you the option to generate a dashboard and reports for tests. It also saves screenshots from failing tests to the ./latest_logs/
folder. Raw Selenium does not have these options out-of-the-box.
\ud83d\udca1 SeleniumBase includes desktop GUI apps for running tests, such as SeleniumBase Commander for pytest
and SeleniumBase Behave GUI for behave
.
\ud83d\udca1 SeleniumBase has its own Recorder / Test Generator for creating tests from manual browser actions.
\ud83d\udca1 SeleniumBase comes with test case management software, (\"CasePlans\"), for organizing tests and step descriptions.
\ud83d\udca1 SeleniumBase includes tools for building data apps, (\"ChartMaker\"), which can generate JavaScript from Python.
\ud83d\udcda Learn about different ways of writing tests:
\ud83d\udcd8\ud83d\udcdd Here's test_simple_login.py, which uses BaseCase
class inheritance, and runs with pytest or pynose. (Use self.driver
to access Selenium's raw driver
.)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass TestSimpleLogin(BaseCase):\n def test_simple_login(self):\n self.open(\"seleniumbase.io/simple/login\")\n self.type(\"#username\", \"demo_user\")\n self.type(\"#password\", \"secret_pass\")\n self.click('a:contains(\"Sign in\")')\n self.assert_exact_text(\"Welcome!\", \"h1\")\n self.assert_element(\"img#image1\")\n self.highlight(\"#image1\")\n self.click_link(\"Sign out\")\n self.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd7\ud83d\udcdd Here's a test from sb_fixture_tests.py, which uses the sb
pytest
fixture. Runs with pytest. (Use sb.driver
to access Selenium's raw driver
.)
def test_sb_fixture_with_no_class(sb):\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd9\ud83d\udcdd Here's raw_login_sb.py, which uses the SB
Context Manager. Runs with pure python
. (Use sb.driver
to access Selenium's raw driver
.)
from seleniumbase import SB\n\nwith SB() as sb:\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd4\ud83d\udcdd Here's raw_login_context.py, which uses the DriverContext
Manager. Runs with pure python
. (The driver
is an improved version of Selenium's raw driver
, with more methods.)
from seleniumbase import DriverContext\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd4\ud83d\udcdd Here's raw_login_driver.py, which uses the Driver
Manager. Runs with pure python
. (The driver
is an improved version of Selenium's raw driver
, with more methods.)
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
\ud83d\udcd5\ud83d\udcdd Here's login_app.feature, which uses behave-BDD Gherkin syntax. Runs with behave
. (Learn about the SeleniumBase behave-BDD integration)
Feature: SeleniumBase scenarios for the Simple App\n\n Scenario: Verify the Simple App (Login / Logout)\n Given Open \"seleniumbase.io/simple/login\"\n And Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Click 'a:contains(\"Sign in\")'\n And Assert exact text \"Welcome!\" in \"h1\"\n And Assert element \"img#image1\"\n And Highlight \"#image1\"\n And Click link \"Sign out\"\n And Assert text \"signed out\" in \"#top_message\"\n
Set up Python & Git: \ud83d\udd35 Add Python and Git to your System PATH.
\ud83d\udd35 Using a Python virtual env is recommended.
Install SeleniumBase:You can install seleniumbase
from PyPI or GitHub:
\ud83d\udd35 How to install seleniumbase
from PyPI:
pip install seleniumbase\n
--upgrade
OR -U
to upgrade SeleniumBase.)--force-reinstall
to upgrade indirect packages.)pip3
if multiple versions of Python are present.)\ud83d\udd35 How to install seleniumbase
from a GitHub clone:
git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install -e .\n
\ud83d\udd35 How to upgrade an existing install from a GitHub clone:
git pull\npip install -e .\n
\ud83d\udd35 Type seleniumbase
or sbase
to verify that SeleniumBase was installed successfully:
______ __ _ ____ \n / ____/__ / /__ ____ (_)_ ______ ___ / _ \\____ ________ \n \\__ \\/ _ \\/ / _ \\/ __ \\/ / / / / __ `__ \\ / /_) / __ \\/ ___/ _ \\\n ___/ / __/ / __/ / / / / /_/ / / / / / // /_) / (_/ /__ / __/\n/____/\\___/_/\\___/_/ /_/_/\\__,_/_/ /_/ /_//_____/\\__,_/____/\\___/ \n------------------------------------------------------------------\n\n * USAGE: \"seleniumbase [COMMAND] [PARAMETERS]\"\n * OR: \"sbase [COMMAND] [PARAMETERS]\"\n\nCOMMANDS:\n get / install [DRIVER] [OPTIONS]\n methods (List common Python methods)\n options (List common pytest options)\n behave-options (List common behave options)\n gui / commander [OPTIONAL PATH or TEST FILE]\n behave-gui (SBase Commander for Behave)\n caseplans [OPTIONAL PATH or TEST FILE]\n mkdir [DIRECTORY] [OPTIONS]\n mkfile [FILE.py] [OPTIONS]\n mkrec / codegen [FILE.py] [OPTIONS]\n recorder (Open Recorder Desktop App.)\n record (If args: mkrec. Else: App.)\n mkpres [FILE.py] [LANG]\n mkchart [FILE.py] [LANG]\n print [FILE] [OPTIONS]\n translate [SB_FILE.py] [LANG] [ACTION]\n convert [WEBDRIVER_UNITTEST_FILE.py]\n extract-objects [SB_FILE.py]\n inject-objects [SB_FILE.py] [OPTIONS]\n objectify [SB_FILE.py] [OPTIONS]\n revert-objects [SB_FILE.py] [OPTIONS]\n encrypt / obfuscate\n decrypt / unobfuscate\n download server (Get Selenium Grid JAR file)\n grid-hub [start|stop] [OPTIONS]\n grid-node [start|stop] --hub=[HOST/IP]\n * (EXAMPLE: \"sbase get chromedriver latest\") *\n\n Type \"sbase help [COMMAND]\" for specific command info.\n For info on all commands, type: \"seleniumbase --help\".\n Use \"pytest\" for running tests.\n
\ud83d\udd35 Downloading webdrivers: \u2705 SeleniumBase automatically downloads webdrivers as needed, such as chromedriver
.
*** chromedriver to download = 121.0.6167.85 (Latest Stable) \n\nDownloading chromedriver-mac-arm64.zip from:\nhttps://storage.googleapis.com/chrome-for-testing-public/121.0.6167.85/mac-arm64/chromedriver-mac-arm64.zip ...\nDownload Complete!\n\nExtracting ['chromedriver'] from chromedriver-mac-arm64.zip ...\nUnzip Complete!\n\nThe file [chromedriver] was saved to:\n/Users/michael/github/SeleniumBase/seleniumbase/drivers/chromedriver\n\nMaking [chromedriver 121.0.6167.85] executable ...\n[chromedriver 121.0.6167.85] is now ready for use!\n
Basic Example / Usage: \ud83d\udd35 If you've cloned SeleniumBase, you can run tests from the examples/ folder.
Here's my_first_test.py:
cd examples/\npytest my_first_test.py\n
Here's the code for my_first_test.py:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n def test_swag_labs(self):\n self.open(\"https://www.saucedemo.com\")\n self.type(\"#user-name\", \"standard_user\")\n self.type(\"#password\", \"secret_sauce\\n\")\n self.assert_element(\"div.inventory_list\")\n self.assert_exact_text(\"Products\", \"span.title\")\n self.click('button[name*=\"backpack\"]')\n self.click(\"#shopping_cart_container a\")\n self.assert_exact_text(\"Your Cart\", \"span.title\")\n self.assert_text(\"Backpack\", \"div.cart_item\")\n self.click(\"button#checkout\")\n self.type(\"#first-name\", \"SeleniumBase\")\n self.type(\"#last-name\", \"Automation\")\n self.type(\"#postal-code\", \"77123\")\n self.click(\"input#continue\")\n self.assert_text(\"Checkout: Overview\")\n self.assert_text(\"Backpack\", \"div.cart_item\")\n self.assert_text(\"29.99\", \"div.inventory_item_price\")\n self.click(\"button#finish\")\n self.assert_exact_text(\"Thank you for your order!\", \"h2\")\n self.assert_element('img[alt=\"Pony Express\"]')\n self.js_click(\"a#logout_sidebar_link\")\n self.assert_element(\"div#login_button_container\")\n
self.open(url) # Navigate the browser window to the URL.\nself.type(selector, text) # Update the field with the text.\nself.click(selector) # Click the element with the selector.\nself.click_link(link_text) # Click the link containing text.\nself.go_back() # Navigate back to the previous URL.\nself.select_option_by_text(dropdown_selector, option)\nself.hover_and_click(hover_selector, click_selector)\nself.drag_and_drop(drag_selector, drop_selector)\nself.get_text(selector) # Get the text from the element.\nself.get_current_url() # Get the URL of the current page.\nself.get_page_source() # Get the HTML of the current page.\nself.get_attribute(selector, attribute) # Get element attribute.\nself.get_title() # Get the title of the current page.\nself.switch_to_frame(frame) # Switch into the iframe container.\nself.switch_to_default_content() # Leave the iframe container.\nself.open_new_window() # Open a new window in the same browser.\nself.switch_to_window(window) # Switch to the browser window.\nself.switch_to_default_window() # Switch to the original window.\nself.get_new_driver(OPTIONS) # Open a new driver with OPTIONS.\nself.switch_to_driver(driver) # Switch to the browser driver.\nself.switch_to_default_driver() # Switch to the original driver.\nself.wait_for_element(selector) # Wait until element is visible.\nself.is_element_visible(selector) # Return element visibility.\nself.is_text_visible(text, selector) # Return text visibility.\nself.sleep(seconds) # Do nothing for the given amount of time.\nself.save_screenshot(name) # Save a screenshot in .png format.\nself.assert_element(selector) # Verify the element is visible.\nself.assert_text(text, selector) # Verify text in the element.\nself.assert_exact_text(text, selector) # Verify text is exact.\nself.assert_title(title) # Verify the title of the web page.\nself.assert_downloaded_file(file) # Verify file was downloaded.\nself.assert_no_404_errors() # Verify there are no broken links.\nself.assert_no_js_errors() # Verify there are no JS errors.\n
\ud83d\udd35 For the complete list of SeleniumBase methods, see: Method Summary
Fun Facts / Learn More:\u2705 SeleniumBase automatically handles common WebDriver actions such as launching web browsers before tests, saving screenshots during failures, and closing web browsers after tests.
\u2705 SeleniumBase lets you customize tests via command-line options.
\u2705 SeleniumBase uses simple syntax for commands. Example:
self.type(\"input\", \"dogs\\n\") # (The \"\\n\" presses ENTER)\n
Most SeleniumBase scripts can be run with pytest
, pynose
, or pure python
. Not all test runners can run all test formats. For example, tests that use the sb
pytest fixture can only be run with pytest
. (See Syntax Formats) There's also a Gherkin test format that runs with behave.
pytest coffee_cart_tests.py --rs\npytest test_sb_fixture.py --demo\npytest test_suite.py --rs --html=report.html --dashboard\n\npynose basic_test.py --mobile\npynose test_suite.py --headless --report --show-report\n\npython raw_sb.py\npython raw_test_scripts.py\n\nbehave realworld.feature\nbehave calculator.feature -D rs -D dashboard\n
\u2705 pytest
includes automatic test discovery. If you don't specify a specific file or folder to run, pytest
will automatically search through all subdirectories for tests to run based on the following criteria:
test_
or end with _test.py
.test_
.With a SeleniumBase pytest.ini file present, you can modify default discovery settings. The Python class name can be anything because seleniumbase.BaseCase
inherits unittest.TestCase
to trigger autodiscovery.
\u2705 You can do a pre-flight check to see which tests would get discovered by pytest
before the actual run:
pytest --co -q\n
\u2705 You can be more specific when calling pytest
or pynose
on a file:
pytest [FILE_NAME.py]::[CLASS_NAME]::[METHOD_NAME]\n\npynose [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]\n
\u2705 No More Flaky Tests! SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (up to a timeout limit). This means you no longer need random time.sleep()
statements in your scripts.
\u2705 SeleniumBase supports all major browsers and operating systems:
Browsers: Chrome, Edge, Firefox, and Safari.
Systems: Linux/Ubuntu, macOS, and Windows.
\u2705 SeleniumBase works on all popular CI/CD platforms:
\u2705 SeleniumBase includes an automated/manual hybrid solution called MasterQA to speed up manual testing with automation while manual testers handle validation.
\u2705 SeleniumBase supports running tests while offline (assuming webdrivers have previously been downloaded when online).
\u2705 For a full list of SeleniumBase features, Click Here.
Demo Mode / Debugging:\ud83d\udd35 Demo Mode helps you see what a test is doing. If a test is moving too fast for your eyes, run it in Demo Mode to pause the browser briefly between actions, highlight page elements being acted on, and display assertions:
pytest my_first_test.py --demo\n
\ud83d\udd35 time.sleep(seconds)
can be used to make a test wait at a specific spot:
import time; time.sleep(3) # Do nothing for 3 seconds.\n
\ud83d\udd35 Debug Mode with Python's built-in pdb library helps you debug tests:
import pdb; pdb.set_trace()\nimport pytest; pytest.set_trace()\nbreakpoint() # Shortcut for \"import pdb; pdb.set_trace()\"\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
)
\ud83d\udd35 To pause an active test that throws an exception or error, (and keep the browser window open while Debug Mode begins in the console), add --pdb
as a pytest
option:
pytest test_fail.py --pdb\n
\ud83d\udd35 To start tests in Debug Mode, add --trace
as a pytest
option:
pytest test_coffee_cart.py --trace\n
\ud83d\udd35 Command-line Options: \u2705 Here are some useful command-line options that come with pytest
:
-v # Verbose mode. Prints the full name of each test and shows more details.\n-q # Quiet mode. Print fewer details in the console output when running tests.\n-x # Stop running the tests after the first failure is reached.\n--html=report.html # Creates a detailed pytest-html report after tests finish.\n--co | --collect-only # Show what tests would get run. (Without running them)\n--co -q # (Both options together!) - Do a dry run with full test names shown.\n-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)\n-s # See print statements. (Should be on by default with pytest.ini present.)\n--junit-xml=report.xml # Creates a junit-xml report after tests finish.\n--pdb # If a test fails, enter Post Mortem Debug Mode. (Don't use with CI!)\n--trace # Enter Debug Mode at the beginning of each test. (Don't use with CI!)\n-m=MARKER # Run tests with the specified pytest marker.\n
\u2705 SeleniumBase provides additional pytest
command-line options for tests:
--browser=BROWSER # (The web browser to use. Default: \"chrome\".)\n--chrome # (Shortcut for \"--browser=chrome\". On by default.)\n--edge # (Shortcut for \"--browser=edge\".)\n--firefox # (Shortcut for \"--browser=firefox\".)\n--safari # (Shortcut for \"--browser=safari\".)\n--settings-file=FILE # (Override default SeleniumBase settings.)\n--env=ENV # (Set the test env. Access with \"self.env\" in tests.)\n--account=STR # (Set account. Access with \"self.account\" in tests.)\n--data=STRING # (Extra test data. Access with \"self.data\" in tests.)\n--var1=STRING # (Extra test data. Access with \"self.var1\" in tests.)\n--var2=STRING # (Extra test data. Access with \"self.var2\" in tests.)\n--var3=STRING # (Extra test data. Access with \"self.var3\" in tests.)\n--variables=DICT # (Extra test data. Access with \"self.variables\".)\n--user-data-dir=DIR # (Set the Chrome user data directory to use.)\n--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)\n--server=SERVER # (The Selenium Grid server/IP used for tests.)\n--port=PORT # (The Selenium Grid port used by the test server.)\n--cap-file=FILE # (The web browser's desired capabilities to use.)\n--cap-string=STRING # (The web browser's desired capabilities to use.)\n--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)\n--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)\n--proxy-bypass-list=STRING # (\";\"-separated hosts to bypass, Eg \"*.foo.com\")\n--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)\n--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)\n--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)\n--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)\n--agent=STRING # (Modify the web browser's User-Agent string.)\n--mobile # (Use the mobile device emulator while running tests.)\n--metrics=STRING # (Set mobile metrics: \"CSSWidth,CSSHeight,PixelRatio\".)\n--chromium-arg=\"ARG=N,ARG2\" # (Set Chromium args, \",\"-separated, no spaces.)\n--firefox-arg=\"ARG=N,ARG2\" # (Set Firefox args, comma-separated, no spaces.)\n--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)\n--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)\n--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)\n--disable-features=\"F1,F2\" # (Disable features, comma-separated, no spaces.)\n--binary-location=PATH # (Set path of the Chromium browser binary to use.)\n--driver-version=VER # (Set the chromedriver or uc_driver version to use.)\n--sjw # (Skip JS Waits for readyState to be \"complete\" or Angular to load.)\n--pls=PLS # (Set pageLoadStrategy on Chrome: \"normal\", \"eager\", or \"none\".)\n--headless # (Run tests in headless mode. The default arg on Linux OS.)\n--headless2 # (Use the new headless mode, which supports extensions.)\n--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)\n--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)\n--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)\n--interval=SECONDS # (The autoplay interval for presentations & tour steps)\n--start-page=URL # (The starting URL for the web browser when tests begin.)\n--archive-logs # (Archive existing log files instead of deleting them.)\n--archive-downloads # (Archive old downloads instead of deleting them.)\n--time-limit=SECONDS # (Safely fail any test that exceeds the time limit.)\n--slow # (Slow down the automation. Faster than using Demo Mode.)\n--demo # (Slow down and visually see test actions as they occur.)\n--demo-sleep=SECONDS # (Set the wait time after Slow & Demo Mode actions.)\n--highlights=NUM # (Number of highlight animations for Demo Mode actions.)\n--message-duration=SECONDS # (The time length for Messenger alerts.)\n--check-js # (Check for JavaScript errors after page loads.)\n--ad-block # (Block some types of display ads from loading.)\n--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)\n--block-images # (Block images from loading during tests.)\n--do-not-track # (Indicate to websites that you don't want to be tracked.)\n--verify-delay=SECONDS # (The delay before MasterQA verification checks.)\n--ee | --esc-end # (Lets the user end the current test via the ESC key.)\n--recorder # (Enables the Recorder for turning browser actions into code.)\n--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)\n--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)\n--rec-print # (If the Recorder is enabled, prints output after tests end.)\n--disable-js # (Disable JavaScript on websites. Pages might break!)\n--disable-csp # (Disable the Content Security Policy of websites.)\n--disable-ws # (Disable Web Security on Chromium-based browsers.)\n--enable-ws # (Enable Web Security on Chromium-based browsers.)\n--enable-sync # (Enable \"Chrome Sync\" on websites.)\n--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)\n--uc-cdp-events # (Capture CDP events when running in \"--undetected\" mode.)\n--log-cdp # (\"goog:loggingPrefs\", {\"performance\": \"ALL\", \"browser\": \"ALL\"})\n--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)\n--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)\n--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)\n--dash-title=STRING # (Set the title shown for the generated dashboard.)\n--enable-3d-apis # (Enables WebGL and 3D APIs.)\n--swiftshader # (Chrome \"--use-gl=angle\" / \"--use-angle=swiftshader-webgl\")\n--incognito # (Enable Chrome's Incognito mode.)\n--guest # (Enable Chrome's Guest mode.)\n--dark # (Enable Chrome's Dark mode.)\n--devtools # (Open Chrome's DevTools when the browser opens.)\n--rs | --reuse-session # (Reuse browser session for all tests.)\n--rcs | --reuse-class-session # (Reuse session for tests in class.)\n--crumbs # (Delete all cookies between tests reusing a session.)\n--disable-beforeunload # (Disable the \"beforeunload\" event on Chrome.)\n--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)\n--maximize # (Start tests with the browser window maximized.)\n--screenshot # (Save a screenshot at the end of each test.)\n--no-screenshot # (No screenshots saved unless tests directly ask it.)\n--visual-baseline # (Set the visual baseline for Visual/Layout tests.)\n--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)\n--external-pdf # (Set Chromium \"plugins.always_open_pdf_externally\":True.)\n--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)\n--list-fail-page # (After each failing test, list the URL of the failure.)\n
(See the full list of command-line option definitions here. For detailed examples of command-line options, see customizing_test_runs.md)
\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. Those logs will get moved to archived_logs/
if you add --archive_logs to command-line options, or have ARCHIVE_EXISTING_LOGS
set to True in settings.py, otherwise log files with be cleaned up at the start of the next test run. The test_suite.py
collection contains tests that fail on purpose so that you can see how logging works.
cd examples/\n\npytest test_suite.py --chrome\n\npytest test_suite.py --firefox\n
An easy way to override seleniumbase/config/settings.py is by using a custom settings file. Here's the command-line option to add to tests: (See examples/custom_settings.py) --settings_file=custom_settings.py
(Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
\ud83d\udd35 To pass additional data from the command-line to tests, add --data=\"ANY STRING\"
. Inside your tests, you can use self.data
to access that.
\ud83d\udd35 When running tests with pytest
, you'll want a copy of pytest.ini in your root folders. When running tests with pynose
, you'll want a copy of setup.cfg in your root folders. These files specify default configuration details for tests. Test folders should also include a blank init.py file to allow your test files to import other files from that folder.
\ud83d\udd35 sbase mkdir DIR
creates a folder with config files and sample tests:
sbase mkdir ui_tests\n
That new folder will have these files:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 my_first_test.py\n\u251c\u2500\u2500 parameterized_test.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 test_demo_site.py\n\u2514\u2500\u2500 boilerplates/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 base_test_case.py\n \u251c\u2500\u2500 boilerplate_test.py\n \u251c\u2500\u2500 classic_obj_test.py\n \u251c\u2500\u2500 page_objects.py\n \u251c\u2500\u2500 sb_fixture_test.py\n \u2514\u2500\u2500 samples/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 google_objects.py\n \u251c\u2500\u2500 google_test.py\n \u251c\u2500\u2500 sb_swag_test.py\n \u2514\u2500\u2500 swag_labs_test.py\n
ProTip\u2122: You can also create a boilerplate folder without any sample tests in it by adding -b
or --basic
to the sbase mkdir
command:
sbase mkdir ui_tests --basic\n
That new folder will have these files:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u2514\u2500\u2500 setup.cfg\n
Of those files, the pytest.ini
config file is the most important, followed by a blank __init__.py
file. There's also a setup.cfg
file (for pynose). Finally, the requirements.txt
file can be used to help you install seleniumbase into your environments (if it's not already installed).
Let's try an example of a test that fails:
\"\"\" test_fail.py \"\"\"\nfrom seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n\n def test_find_army_of_robots_on_xkcd_desert_island(self):\n self.open(\"https://xkcd.com/731/\")\n self.assert_element(\"div#ARMY_OF_ROBOTS\", timeout=1) # This should fail\n
You can run it from the examples/
folder like this:
pytest test_fail.py\n
\ud83d\udd35 You'll notice that a logs folder, \"latest_logs\", was created to hold information about the failing test, and screenshots. During test runs, past results get moved to the archived_logs folder if you have ARCHIVE_EXISTING_LOGS set to True in settings.py, or if your run tests with --archive-logs
. If you choose not to archive existing logs, they will be deleted and replaced by the logs of the latest test run.
\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py test_image_saving.py --dashboard --rs --headless\n
Generating Test Reports: \ud83d\udd35 pytest
HTML Reports: \u2705 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\u2705 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\u2705 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest html reports in Jenkins, you may need to configure Jenkins settings for the html to render correctly. This is due to Jenkins CSP changes.
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
\ud83d\udd35 pynose
Reports: The --report
option gives you a fancy report after your test suite completes.
pynose test_suite.py --report\n
(NOTE: You can add --show-report
to immediately display pynose reports after the test suite completes. Only use --show-report
when running tests locally because it pauses the test run.)
behave
Dashboard & Reports: (The behave_bdd/ folder can be found in the examples/ folder.)
behave behave_bdd/features/ -D dashboard -D headless\n
You can also use --junit
to get .xml
reports for each behave
feature. Jenkins can use these files to display better reporting for your tests.
behave behave_bdd/features/ --junit -D rs -D headless\n
\ud83d\udd35 Allure Reports: See: https://allurereport.org/docs/pytest/
SeleniumBase no longer includes allure-pytest
as part of installed dependencies. If you want to use it, install it first:
pip install allure-pytest\n
Now your tests can create Allure results files, which can be processed by Allure Reports.
pytest test_suite.py --alluredir=allure_results\n
Using a Proxy Server: If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add --proxy=IP_ADDRESS:PORT
as an argument on the command line.
pytest proxy_test.py --proxy=IP_ADDRESS:PORT\n
If the proxy server that you wish to use requires authentication, you can do the following (Chromium only):
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n
SeleniumBase also supports SOCKS4 and SOCKS5 proxies:
pytest proxy_test.py --proxy=\"socks4://IP_ADDRESS:PORT\"\n\npytest proxy_test.py --proxy=\"socks5://IP_ADDRESS:PORT\"\n
To make things easier, you can add your frequently-used proxies to PROXY_LIST in proxy_list.py, and then use --proxy=KEY_FROM_PROXY_LIST
to use the IP_ADDRESS:PORT of that key.
pytest proxy_test.py --proxy=proxy1\n
Changing the User-Agent: \ud83d\udd35 If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add --agent=\"USER AGENT STRING\"
as an argument on the command-line.
pytest user_agent_test.py --agent=\"Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU\"\n
Handling Pop-Up Alerts: \ud83d\udd35 self.accept_alert()
automatically waits for and accepts alert pop-ups. self.dismiss_alert()
automatically waits for and dismisses alert pop-ups. On occasion, some methods like self.click(SELECTOR)
might dismiss a pop-up on its own because they call JavaScript to make sure that the readyState
of the page is complete
before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call self.find_element(SELECTOR).click()
instead, (which will let the pop-up remain on the screen), and then use self.accept_alert()
to accept the pop-up (more on that here). If pop-ups are intermittent, wrap code in a try/except block.
\ud83d\udd35 Learn about SeleniumBase Interactive Walkthroughs (in the examples/tour_examples/
folder). It's great for prototyping a website onboarding experience.
--with-s3-logging
on the command-line when running your tests.pytest [YOUR_TEST_FILE.py] --with-db-reporting --with-s3-logging\n
Detailed Method Specifications and Examples: \ud83d\udd35 Navigating to a web page: (and related commands)
self.open(\"https://xkcd.com/378/\") # This method opens the specified page.\n\nself.go_back() # This method navigates the browser to the previous page.\n\nself.go_forward() # This method navigates the browser forward in history.\n\nself.refresh_page() # This method reloads the current page.\n\nself.get_current_url() # This method returns the current page URL.\n\nself.get_page_source() # This method returns the current page source.\n
ProTip\u2122: You can use the self.get_page_source()
method with Python's find()
command to parse through HTML to find something specific. (For more advanced parsing, see the BeautifulSoup example.)
source = self.get_page_source()\nhead_open_tag = source.find('<head>')\nhead_close_tag = source.find('</head>', head_open_tag)\neverything_inside_head = source[head_open_tag+len('<head>'):head_close_tag]\n
\ud83d\udd35 Clicking:
To click an element on the page:
self.click(\"div#my_id\")\n
ProTip\u2122: In most web browsers, you can right-click on a page and select Inspect Element
to see the CSS selector details that you'll need to create your own scripts.
\ud83d\udd35 Typing Text:
self.type(selector, text)
# updates the text from the specified element with the specified value. An exception is raised if the element is missing or if the text field is not editable. Example:
self.type(\"input#id_value\", \"2012\")\n
You can also use self.add_text()
or the WebDriver .send_keys()
command, but those won't clear the text box first if there's already text inside.
\ud83d\udd35 Getting the text from an element on a page:
text = self.get_text(\"header h2\")\n
\ud83d\udd35 Getting the attribute value from an element on a page:
attribute = self.get_attribute(\"#comic img\", \"title\")\n
\ud83d\udd35 Asserting existence of an element on a page within some number of seconds:
self.wait_for_element_present(\"div.my_class\", timeout=10)\n
(NOTE: You can also use: self.assert_element_present(ELEMENT)
)
\ud83d\udd35 Asserting visibility of an element on a page within some number of seconds:
self.wait_for_element_visible(\"a.my_class\", timeout=5)\n
(NOTE: The short versions of that are self.find_element(ELEMENT)
and self.assert_element(ELEMENT)
. The find_element()
version returns the element.)
Since the line above returns the element, you can combine that with .click()
as shown below:
self.find_element(\"a.my_class\", timeout=5).click()\n\n# But you're better off using the following statement, which does the same thing\nself.click(\"a.my_class\") # DO IT THIS WAY!\n
ProTip\u2122: You can use dots to signify class names (Ex: div.class_name
) as a simplified version of div[class=\"class_name\"]
within a CSS selector.
You can also use *=
to search for any partial value in a CSS selector as shown below:
self.click('a[name*=\"partial_name\"]')\n
\ud83d\udd35 Asserting visibility of text inside an element on a page within some number of seconds:
self.assert_text(\"Make it so!\", \"div#trek div.picard div.quotes\")\nself.assert_text(\"Tea. Earl Grey. Hot.\", \"div#trek div.picard div.quotes\", timeout=3)\n
(NOTE: self.find_text(TEXT, ELEMENT)
and self.wait_for_text(TEXT, ELEMENT)
also do this. For backwards compatibility, older method names were kept, but the default timeout may be different.)
\ud83d\udd35 Asserting Anything:
self.assert_true(var1 == var2)\n\nself.assert_false(var1 == var2)\n\nself.assert_equal(var1, var2)\n
\ud83d\udd35 Useful Conditional Statements: (with creative examples)
\u2753 is_element_visible(selector):
(visible on the page)
if self.is_element_visible('div#warning'):\n print(\"Red Alert: Something bad might be happening!\")\n
\u2753 is_element_present(selector):
(present in the HTML)
if self.is_element_present('div#top_secret img.tracking_cookie'):\n self.contact_cookie_monster() # Not a real SeleniumBase method\nelse:\n current_url = self.get_current_url()\n self.contact_the_nsa(url=current_url, message=\"Dark Zone Found\") # Not a real SeleniumBase method\n
def is_there_a_cloaked_klingon_ship_on_this_page():\n if self.is_element_present(\"div.ships div.klingon\"):\n return not self.is_element_visible(\"div.ships div.klingon\")\n return False\n
\u2753 is_text_visible(text, selector):
(text visible on element)
if self.is_text_visible(\"You Shall Not Pass!\", \"h1\"):\n self.open(\"https://www.youtube.com/watch?v=3xYXUeSmb-Y\")\n
\u25b6\ufe0f Click for a longer example of is_text_visible():
def get_mirror_universe_captain_picard_superbowl_ad(superbowl_year):\n selector = \"div.superbowl_%s div.commercials div.transcript div.picard\" % superbowl_year\n if self.is_text_visible(\"Yes, it was I who summoned you all here.\", selector):\n return \"Picard Paramount+ Superbowl Ad 2020\"\n elif self.is_text_visible(\"Commander, signal the following: Our Network is Secure!\"):\n return \"Picard Mirror Universe iboss Superbowl Ad 2018\"\n elif self.is_text_visible(\"For the Love of Marketing and Earl Grey Tea!\", selector):\n return \"Picard Mirror Universe HubSpot Superbowl Ad 2015\"\n elif self.is_text_visible(\"Delivery Drones... Engage\", selector):\n return \"Picard Mirror Universe Amazon Superbowl Ad 2015\"\n elif self.is_text_visible(\"Bing it on Screen!\", selector):\n return \"Picard Mirror Universe Microsoft Superbowl Ad 2015\"\n elif self.is_text_visible(\"OK Glass, Make it So!\", selector):\n return \"Picard Mirror Universe Google Superbowl Ad 2015\"\n elif self.is_text_visible(\"Number One, I've Never Seen Anything Like It.\", selector):\n return \"Picard Mirror Universe Tesla Superbowl Ad 2015\"\n elif self.is_text_visible(\"Let us make sure history never forgets the name ... Facebook\", selector):\n return \"Picard Mirror Universe Facebook Superbowl Ad 2015\"\n elif self.is_text_visible(\"\"\"With the first link, the chain is forged.\n The first speech censored, the first thought forbidden,\n the first freedom denied, chains us all irrevocably.\"\"\", selector):\n return \"Picard Mirror Universe Wikimedia Superbowl Ad 2015\"\n else:\n raise Exception(\"Reports of my assimilation are greatly exaggerated.\")\n
\u2753 is_link_text_visible(link_text):
if self.is_link_text_visible(\"Stop! Hammer time!\"):\n self.click_link(\"Stop! Hammer time!\")\n
\ud83d\udd35 Switching Tabs: If your test opens up a new tab/window, you can switch to it. (SeleniumBase automatically switches to new tabs that don't open to about:blank
URLs.)
self.switch_to_window(1) # This switches to the new tab (0 is the first one)\n
\ud83d\udd35 How to handle iframes: \ud83d\udd35 iframes follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
self.switch_to_frame(\"iframe\")\n# ... Now perform actions inside the iframe\nself.switch_to_parent_frame() # Exit the current iframe\n
To exit from multiple iframes, use self.switch_to_default_content()
. (If inside a single iframe, this has the same effect as self.switch_to_parent_frame()
.)
self.switch_to_frame('iframe[name=\"frame1\"]')\nself.switch_to_frame('iframe[name=\"frame2\"]')\n# ... Now perform actions inside the inner iframe\nself.switch_to_default_content() # Back to the main page\n
\ud83d\udd35 You can also use a context manager to act inside iframes:
with self.frame_switch(\"iframe\"):\n # ... Now perform actions while inside the code block\n# You have left the iframe\n
This also works with nested iframes:
with self.frame_switch('iframe[name=\"frame1\"]'):\n with self.frame_switch('iframe[name=\"frame2\"]'):\n # ... Now perform actions while inside the code block\n # You are now back inside the first iframe\n# You have left all the iframes\n
\ud83d\udd35 How to execute custom jQuery scripts: jQuery is a powerful JavaScript library that allows you to perform advanced actions in a web browser. If the web page you're on already has jQuery loaded, you can start executing jQuery scripts immediately. You'd know this because the web page would contain something like the following in the HTML:
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js\"></script>\n
\ud83d\udd35 It's OK if you want to use jQuery on a page that doesn't have it loaded yet. To do so, run the following command first:
self.activate_jquery()\n
\u25b6\ufe0f Here are some examples of using jQuery in your scripts. (click to expand) self.execute_script(\"jQuery, window.scrollTo(0, 600)\") # Scrolling the page\n\nself.execute_script(\"jQuery('#annoying-widget').hide()\") # Hiding elements on a page\n\nself.execute_script(\"jQuery('#hidden-widget').show(0)\") # Showing hidden elements on a page\n\nself.execute_script(\"jQuery('#annoying-button a').remove()\") # Removing elements on a page\n\nself.execute_script(\"jQuery('%s').mouseover()\" % (mouse_over_item)) # Mouse-over elements on a page\n\nself.execute_script(\"jQuery('input#the_id').val('my_text')\") # Fast text input on a page\n\nself.execute_script(\"jQuery('div#dropdown a.link').click()\") # Click elements on a page\n\nself.execute_script(\"return jQuery('div#amazing')[0].text\") # Returns the css \"text\" of the element given\n\nself.execute_script(\"return jQuery('textarea')[2].value\") # Returns the css \"value\" of the 3rd textarea element on the page\n
(Most of the above commands can be done directly with built-in SeleniumBase methods.) \ud83d\udd35 How to handle a restrictive CSP: \u2757 Some websites have a restrictive Content Security Policy to prevent users from loading jQuery and other external libraries onto their websites. If you need to use jQuery or another JS library on those websites, add --disable-csp
as a pytest
command-line option to load a Chromium extension that bypasses the CSP.
start_page = \"https://xkcd.com/465/\"\ndestination_page = \"https://github.com/seleniumbase/SeleniumBase\"\nself.open(start_page)\nreferral_link = '''<a class='analytics test' href='%s'>Free-Referral Button!</a>''' % destination_page\nself.execute_script('''document.body.innerHTML = \\\"%s\\\"''' % referral_link)\nself.click(\"a.analytics\") # Clicks the generated button\n
(Due to popular demand, this traffic generation example has been included in SeleniumBase with the self.generate_referral(start_page, end_page)
and the self.generate_traffic(start_page, end_page, loops)
methods.) \ud83d\udd35 How to use deferred asserts: Let's say you want to verify multiple different elements on a web page in a single test, but you don't want the test to fail until you verified several elements at once so that you don't have to rerun the test to find more missing elements on the same page. That's where deferred asserts come in. Here's an example:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass DeferredAssertTests(BaseCase):\n def test_deferred_asserts(self):\n self.open(\"https://xkcd.com/993/\")\n self.wait_for_element(\"#comic\")\n self.deferred_assert_element('img[alt=\"Brand Identity\"]')\n self.deferred_assert_element('img[alt=\"Rocket Ship\"]') # Will Fail\n self.deferred_assert_element(\"#comicmap\")\n self.deferred_assert_text(\"Fake Item\", \"ul.comicNav\") # Will Fail\n self.deferred_assert_text(\"Random\", \"ul.comicNav\")\n self.deferred_assert_element('a[name=\"Super Fake !!!\"]') # Will Fail\n self.deferred_assert_exact_text(\"Brand Identity\", \"#ctitle\")\n self.deferred_assert_exact_text(\"Fake Food\", \"#comic\") # Will Fail\n self.process_deferred_asserts()\n
deferred_assert_element()
and deferred_assert_text()
will save any exceptions that would be raised. To flush out all the failed deferred asserts into a single exception, make sure to call self.process_deferred_asserts()
at the end of your test method. If your test hits multiple pages, you can call self.process_deferred_asserts()
before navigating to a new page so that the screenshot from your log files matches the URL where the deferred asserts were made.
If you need access to any commands that come with standard WebDriver, you can call them directly like this:
self.driver.delete_all_cookies()\ncapabilities = self.driver.capabilities\nself.driver.find_elements(\"partial link text\", \"GitHub\")\n
(In general, you'll want to use the SeleniumBase versions of methods when available.)
\ud83d\udd35 How to retry failing tests automatically:You can use pytest --reruns=NUM
to retry failing tests that many times. Add --reruns-delay=SECONDS
to wait that many seconds between retries. Example:
pytest --reruns=1 --reruns-delay=1\n
You can use the @retry_on_exception()
decorator to retry failing methods. (First import: from seleniumbase import decorators
). To learn more about SeleniumBase decorators, click here.
\"Catch bugs in QA before deploying code to Production!\"
Wrap-UpIf you see something, say something!
https://github.com/mdmintz
"}, {"location": "examples/ReadMe/", "title": "\ud83d\udcda Running Example Tests", "text": ""}, {"location": "examples/ReadMe/#example-tests", "title": "Example Tests", "text": "./latest_logs/
.(NOTE: Some example tests fail on purpose to demonstrate logging features.)
Example tests with run commands to help you get started:Run an example test: (Default option: --chrome
)
pytest my_first_test.py\n
Here's one way of changing the browser to Firefox:
pytest my_first_test.py --firefox\n
Another example test for a web page that has lots of different HTML items:
pytest test_demo_site.py\n
Run an example test in --demo
mode: (highlight assertions)
pytest test_swag_labs.py --demo\n
Run test_coffee_cart.py to test the Coffee Cart app:
pytest test_coffee_cart.py --demo\n
Run a Wordle-solver example:
pytest wordle_test.py\n
Run an example test in --headless
mode: (invisible browser)
pytest my_first_test.py --headless\n
Run an example test using Chrome's mobile device emulator: (default settings)
pytest test_swag_labs.py --mobile\n
Run an example test in --demo
mode: (highlight assertions)
pytest test_xkcd.py --demo\n
Run a test suite with verbose output: (see more details)
pytest test_suite.py -v\n
Run a test suite using multiple parallel processes (-n=NUM
):
pytest test_suite.py -n=8\n
Run a parameterized test: (Generates multiple tests from one)
pytest parameterized_test.py -v\n
Run a test suite and generate a SeleniumBase Dashboard:
pytest test_suite.py --dashboard\n
Run a test suite and generate a pytest
report:
pytest test_suite.py --html=report.html\n
Run a failing test: (See the latest_logs/
folder for logs and screenshots)
pytest test_fail.py\n
Run a failing test that activates pdb
debug mode on failure:
pytest test_fail.py --pdb -s\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
)
Run a test suite that demonstrates the use of pytest
markers:
pytest -m marker_test_suite -v\n
Run a test suite that reuses the browser session between tests:
pytest test_suite.py --rs\n
Run an example test demonstrating the rate_limited
Python decorator:
pytest rate_limiting_test.py\n
Run an example test that demonstrates how to upload a file to a website:
pytest upload_file_test.py\n
\ud83c\udf96\ufe0f SeleniumBase Commander is a GUI for pytest
:
sbase gui\n
SeleniumBase tests can also be run with pynose
:
pynose my_first_test.py\n
Run an example test suite and generate a pynose
test report:
pynose test_suite.py --report --show-report\n
Run an example test using a pynose
configuration file:
pynose my_first_test.py --config=example_config.cfg\n
For more advanced run commands, such as using a proxy server, see ../help_docs/customizing_test_runs.md
If you just need to perform some quick website verification on various devices, you can use the SeleniumBase Device Farm. Just plug in a website URL, and it will display how the website looks on four different devices:
To make things easier, here's a simple GUI program that allows you to run a few example tests by pressing a button:
python gui_test_runner.py\n
(The newer SeleniumBase Commander improves on that.)
"}, {"location": "examples/behave_bdd/ReadMe/", "title": "\ud83d\udc1d Behave-BDD ReadMe", "text": ""}, {"location": "examples/behave_bdd/ReadMe/#behave-test-runner-for-seleniumbase", "title": "\ud83d\udc1d Behave test runner for SeleniumBase \ud83d\udc1d", "text": "
\ud83d\udc1d (Utilizes the Behave BDD Python library. For more info, see the Behave tutorial and read about Behave's Gherkin model.)
\ud83d\udc1d Behave examples with SeleniumBase: SeleniumBase/examples/behave_bdd
> cd examples/behave_bdd/\n> behave features/realworld.feature -T -D dashboard -k\n\nDashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n********************************************************************************\nFeature: SeleniumBase scenarios for the RealWorld App # features/realworld.feature:1\n\n Scenario: Verify RealWorld App (log in / sign out) # features/realworld.feature:3\n Given Open \"seleniumbase.io/realworld/login\" # ../../sbase/steps.py:10\n And Clear Session Storage # ../../sbase/steps.py:669\n When Type \"demo_user\" into \"#username\" # ../../sbase/steps.py:40\n And Type \"secret_pass\" into \"#password\" # ../../sbase/steps.py:40\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\" # ../../sbase/steps.py:322\n Then Assert exact text \"Welcome!\" in \"h1\" # ../../sbase/steps.py:157\n And Highlight \"img#image1\" # ../../sbase/steps.py:184\n And Click 'a:contains(\"This Page\")' # ../../sbase/steps.py:27\n And Save screenshot to logs # ../../sbase/steps.py:239\n When Click link \"Sign out\" # ../../sbase/steps.py:195\n Then Assert element 'a:contains(\"Sign in\")' # ../../sbase/steps.py:120\n And Assert text \"You have been signed out!\" # ../../sbase/steps.py:145\n \u2705 Scenario Passed!\n\n- Dashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n--- LogPath: /Users/michael/github/SeleniumBase/examples/behave_bdd/latest_logs/\n==================================================================================\n1 feature passed, 0 failed, 0 skipped\n1 scenario passed, 0 failed, 0 skipped\n12 steps passed, 0 failed, 0 skipped, 0 undefined\nTook 0m4.682s\n
\ud83d\udc1d Another example, which uses higher-level Behave steps to simplify the .feature
file:
> cd examples/behave_bdd/\n> behave features/calculator.feature:61 -T -D dashboard -k\n\nDashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n********************************************************************************\nFeature: SeleniumBase scenarios for the Calculator App # features/calculator.feature:1\n\n Background: # features/calculator.feature:3\n\n Scenario: 7.0 \u00d7 (3 + 3) = 42 # features/calculator.feature:49\n Given Open the Calculator App # features/steps/calculator.py:4\n When Press C # features/steps/calculator.py:9\n And Press 7 # features/steps/calculator.py:79\n And Press . # features/steps/calculator.py:104\n And Press 0 # features/steps/calculator.py:94\n And Press \u00d7 # features/steps/calculator.py:29\n And Press ( # features/steps/calculator.py:14\n And Press 3 # features/steps/calculator.py:59\n And Press + # features/steps/calculator.py:39\n And Press 3 # features/steps/calculator.py:59\n And Press ) # features/steps/calculator.py:19\n Then Verify output is \"7.0\u00d7(3+3)\" # features/steps/calculator.py:135\n When Press = # features/steps/calculator.py:44\n Then Verify output is \"42\" # features/steps/calculator.py:135\n \u2705 Scenario Passed!\n\n- Dashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n--- LogPath: /Users/michael/github/SeleniumBase/examples/behave_bdd/latest_logs/\n==================================================================================\n1 feature passed, 0 failed, 0 skipped\n1 scenario passed, 0 failed, 8 skipped\n14 steps passed, 0 failed, 60 skipped, 0 undefined\nTook 0m1.672s\n
\ud83d\udc1d\u26aa With the Dashboard enabled, you'll get one of these:
"}, {"location": "examples/behave_bdd/ReadMe/#behave-gherkin-files", "title": "\ud83d\udc1d Behave-Gherkin files", "text": "\ud83d\udc1d The *.feature
files can use any step seen from:
behave --steps-catalog\n
\ud83d\udc1d SeleniumBase includes several pre-made Behave steps, which you can use by creating a Python file with the following line in your features/steps/
directory:
from seleniumbase.behave import steps # noqa\n
\ud83d\udc1d Inside your features/environment.py
file, you should have the following:
from seleniumbase import BaseCase\nfrom seleniumbase.behave import behave_sb\nbehave_sb.set_base_class(BaseCase) # Accepts a BaseCase subclass\nfrom seleniumbase.behave.behave_sb import before_all # noqa\nfrom seleniumbase.behave.behave_sb import before_feature # noqa\nfrom seleniumbase.behave.behave_sb import before_scenario # noqa\nfrom seleniumbase.behave.behave_sb import before_step # noqa\nfrom seleniumbase.behave.behave_sb import after_step # noqa\nfrom seleniumbase.behave.behave_sb import after_scenario # noqa\nfrom seleniumbase.behave.behave_sb import after_feature # noqa\nfrom seleniumbase.behave.behave_sb import after_all # noqa\n
\ud83d\udc1d If you've already created a subclass of BaseCase
with custom methods, you can swap BaseCase
in with your own subclass, which will allow you to easily use your own custom methods in your Behave step definitions.
\ud83d\udc1d Here's an example Python file in the features/steps/
folder:
from behave import step\n\n\n@step(\"Open the Swag Labs Login Page\")\ndef go_to_swag_labs(context):\n sb = context.sb\n sb.open(\"https://www.saucedemo.com\")\n sb.clear_local_storage()\n\n\n@step(\"Login to Swag Labs with {user}\")\ndef login_to_swag_labs(context, user):\n sb = context.sb\n sb.type(\"#user-name\", user)\n sb.type(\"#password\", \"secret_sauce\\n\")\n\n\n@step(\"Verify that the current user is logged in\")\ndef verify_logged_in(context):\n sb = context.sb\n sb.assert_element(\"#header_container\")\n sb.assert_element(\"#react-burger-menu-btn\")\n sb.assert_element(\"#shopping_cart_container\")\n\n\n@step('Add \"{item}\" to cart')\ndef add_item_to_cart(context, item):\n sb = context.sb\n sb.click('div.inventory_item:contains(\"%s\") button[name*=\"add\"]' % item)\n
\ud83d\udc1d A *.feature
file could look like this:
Feature: SeleniumBase scenarios for the Swag Labs App\n\n Background:\n Given Open the Swag Labs Login Page\n\n Scenario: User can order a backpack from the store\n When Login to Swag Labs with standard_user\n Then Verify that the current user is logged in\n And Save price of \"Backpack\" to <item_price>\n When Add \"Backpack\" to Cart\n Then Verify shopping cart badge shows 1 item(s)\n When Click on shopping cart icon\n And Click Checkout\n And Enter checkout info: First, Last, 12345\n And Click Continue\n Then Verify 1 \"Backpack\"(s) in cart\n And Verify cost of \"Backpack\" is <item_price>\n And Verify item total is $29.99\n And Verify tax amount is $2.40\n And Verify total cost is $32.39\n When Click Finish\n Then Verify order complete\n When Logout from Swag Labs\n Then Verify on Login page\n
\ud83d\udc1d Here's another example of a *.feature
file:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert text \"Welcome!\" in \"h1\"\n And Highlight element \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n When Click link \"Sign out\"\n Then Assert element 'a:contains(\"Sign in\")'\n And Assert text \"You have been signed out!\"\n
\ud83d\udc1d If there's a test failure, that's easy to spot:
Feature: SeleniumBase scenarios for the Fail Page # features/fail_page.feature:1\n\n Scenario: Fail test on purpose to see what happens # features/fail_page.feature:3\n When Open the Fail Page # features/steps/fail_page.py:4\n Then Fail test on purpose # features/steps/fail_page.py:9\n Assertion Failed: This test fails on purpose!\n Captured stdout:\n >>> STEP FAILED: (#2) Fail test on purpose\n Class / Feature: SeleniumBase scenarios for the Fail Page\n Test / Scenario: Fail test on purpose to see what happens\n\n \u274c Scenario Failed!\n
\ud83d\udc1d\ud83c\udf96\ufe0f For convenience, the SeleniumBase Behave GUI lets you run behave
scripts from a Desktop app.
\ud83d\udc1d\ud83c\udf96\ufe0f To launch it, call sbase behave-gui
or sbase gui-behave
:
sbase behave-gui\n* Starting the SeleniumBase Behave Commander GUI App...\n
\ud83d\udc1d\ud83c\udf96\ufe0f You can customize the tests that show up there:
sbase behave-gui # all tests\nsbase behave-gui -i=calculator # tests with \"calculator\" in the name\nsbase behave-gui features/ # tests located in the \"features/\" folder\nsbase behave-gui features/calculator.feature # tests in that feature\n
To learn more about SeleniumBase, check out the Docs Site: All the code is on GitHub:
"}, {"location": "examples/chart_maker/ReadMe/", "title": "\ud83d\udcf6 Chart Maker", "text": ""}, {"location": "examples/chart_maker/ReadMe/#chartmaker", "title": "\ud83d\udcca ChartMaker \ud83d\udcf6 ChartMaker API", "text": "
SeleniumBase ChartMaker lets you use Python to generate HTML charts.
(Click to see a presentation with multiple charts)
Here's how to run a simple pie chart presentation from GitHub => seleniumbase/SeleniumBase/examples/chart_maker:
cd examples/chart_maker\npytest my_chart.py\n
Here's the code for that pie chart presentation (GitHub => seleniumbase/SeleniumBase/examples/chart_maker/my_chart.py):
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker(self):\n self.create_presentation()\n self.create_pie_chart(title=\"Automated Tests\")\n self.add_data_point(\"Passed\", 7, color=\"#95d96f\")\n self.add_data_point(\"Untested\", 2, color=\"#eaeaea\")\n self.add_data_point(\"Failed\", 1, color=\"#f1888f\")\n self.add_slide(\"<p>Pie Chart</p>\" + self.extract_chart())\n self.begin_presentation(filename=\"my_chart.html\")\n
Here's how to run an example presentation with multiple charts:
cd examples/chart_maker\npytest chart_presentation.py\n
Here are screenshots from the examples:
Here's a line chart example:from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker(self):\n self.create_presentation()\n self.create_line_chart(\n title=\"Time Outside\", subtitle=\"Last Week\", unit=\"Minutes\")\n self.add_data_point(\"Sun\", 5)\n self.add_data_point(\"Mon\", 10)\n self.add_data_point(\"Tue\", 20)\n self.add_data_point(\"Wed\", 40)\n self.add_data_point(\"Thu\", 80)\n self.add_data_point(\"Fri\", 65)\n self.add_data_point(\"Sat\", 50)\n self.add_slide(\"<p>Line Chart</p>\" + self.extract_chart())\n self.begin_presentation(filename=\"line_chart.html\", interval=8)\n
This example is from test_line_chart.py, which you can run from the examples/chart_maker
folder with the following command:
pytest test_line_chart.py\n
Because that presentation above has an interval
set to 8
, it will automatically advance to the next slide after 8 seconds. (Or exit if there are no more slides.)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker_presentation(self):\n self.create_presentation(theme=\"sky\")\n\n self.create_pie_chart(title=\"Automated Tests\")\n self.add_data_point(\"Passed\", 7, color=\"#95d96f\")\n self.add_data_point(\"Untested\", 2, color=\"#eaeaea\")\n self.add_data_point(\"Failed\", 1, color=\"#f1888f\")\n self.add_slide(\"<p>Pie Chart</p>\" + self.extract_chart())\n\n self.create_bar_chart(title=\"Language\")\n self.add_data_point(\"Python\", 33, color=\"Orange\")\n self.add_data_point(\"JavaScript\", 27, color=\"Teal\")\n self.add_data_point(\"HTML + CSS\", 21, color=\"Purple\")\n self.add_slide(\"<p>Bar Chart</p>\" + self.extract_chart())\n\n self.create_column_chart(title=\"Colors\")\n self.add_data_point(\"Red\", 10, color=\"Red\")\n self.add_data_point(\"Green\", 25, color=\"Green\")\n self.add_data_point(\"Blue\", 15, color=\"Blue\")\n self.add_slide(\"<p>Column Chart</p>\" + self.extract_chart())\n\n self.create_line_chart(title=\"Last Week's Data\")\n self.add_data_point(\"Sun\", 5)\n self.add_data_point(\"Mon\", 10)\n self.add_data_point(\"Tue\", 20)\n self.add_data_point(\"Wed\", 40)\n self.add_data_point(\"Thu\", 80)\n self.add_data_point(\"Fri\", 65)\n self.add_data_point(\"Sat\", 50)\n self.add_slide(\"<p>Line Chart</p>\" + self.extract_chart())\n\n self.begin_presentation(filename=\"chart_presentation.html\")\n
Here's how to run that example:
cd examples/chart_maker\npytest chart_presentation.py\n
(Press the Right Arrow to advance to the next slide in that chart presentation)
(Click to see a live example of that presentation)
Multi-Series charts can also be created. Try the available examples to learn more.
self.create_pie_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript pie chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_bar_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript bar chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_column_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript column chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_line_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True):\n\"\"\" Creates a JavaScript line chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n zero - If True, the y-axis always starts at 0. (Default: False).\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_area_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True):\n\"\"\" Creates a JavaScript area chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n zero - If True, the y-axis always starts at 0. (Default: False).\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
If creating multiple charts at the same time, you can pass the chart_name
parameter to distinguish between different charts.
self.add_data_point(label, value, color=None, chart_name=None):\n\"\"\" Add a data point to a SeleniumBase-generated chart.\n @Params\n label - The label name for the data point.\n value - The numeric value of the data point.\n color - The HTML color of the data point.\n Can be an RGB color. Eg: \"#55ACDC\".\n Can also be a named color. Eg: \"Teal\".\n chart_name - If creating multiple charts,\n use this to select which one.\n\"\"\"\n
Adding a new data series to an existing chart: self.add_series_to_chart(self, data_name=None, chart_name=None):\n\"\"\" Add a new data series to an existing chart.\n This allows charts to have multiple data sets.\n @Params\n data_name - Set the series name. Useful for multi-series charts.\n chart_name - If creating multiple charts,\n use this to select which one.\n\"\"\"\n
Saving a chart to a file: self.save_chart(chart_name=None, filename=None):\n\"\"\" Saves a SeleniumBase-generated chart to a file for later use.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n filename - The name of the HTML file that you wish to\n save the chart to. (filename must end in \".html\")\n\"\"\"\n
The full HTML of the chart is saved to the saved_charts/
folder.
self.extract_chart(chart_name=None):\n\"\"\" Extracts the HTML from a SeleniumBase-generated chart.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n\"\"\"\n
Displaying a chart in the browser window: self.display_chart(chart_name=None, filename=None):\n\"\"\" Displays a SeleniumBase-generated chart in the browser window.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n filename - The name of the HTML file that you wish to\n save the chart to. (filename must end in \".html\")\n interval - The delay time for auto-advancing charts. (in seconds)\n If set to 0 (default), auto-advancing is disabled.\n\"\"\"\n
All methods have the optional chart_name
argument, which is only needed when storing multiple charts at the same time.
SeleniumBase Dialog Boxes let your users provide input in the middle of automation scripts.
cd examples/dialog_boxes\npytest test_dialog_boxes.py\n
Here's a code snippet from that: self.open(\"https://xkcd.com/1920/\")\nskip_button = [\"SKIP\", \"red\"] # Can be a [text, color] list or tuple.\nbuttons = [\"Fencing\", \"Football\", \"Metaball\", \"Go/Chess\", skip_button]\nmessage = \"Choose a sport:\"\nchoice = self.get_jqc_button_input(message, buttons)\nif choice == \"Fencing\":\n self.open(\"https://xkcd.com/1424/\")\n
choice = self.get_jqc_button_input(\"Ready?\", [\"YES\", \"NO\"])\nprint(choice) # This prints \"YES\" or \"NO\"\n\n# You may want to customize the color of buttons\nbuttons = [(\"YES\", \"green\"), (\"NO\", \"red\")]\nchoice = self.get_jqc_button_input(\"Ready?\", buttons)\n
Here's a simple form with an input field: text = self.get_jqc_text_input(\"Enter text:\", [\"Search\"])\nprint(text) # This prints the text entered\n
This form has an input field and buttons: message = \"Type your name and choose a language:\"\nbuttons = [\"Python\", \"JavaScript\"]\ntext, choice = self.get_jqc_form_inputs(message, buttons)\nprint(\"Your name is: %s\" % text)\nprint(\"You picked %s!\" % choice)\n
You can customize options if you want: # Themes: bootstrap, modern, material, supervan, light, dark, seamless\noptions = [(\"theme\", \"modern\"), (\"width\", \"50%\")]\nself.get_jqc_text_input(\"You Won!\", [\"OK\"], options)\n
Default options can be set with set_jqc_theme()
: self.set_jqc_theme(\"light\", color=\"green\", width=\"38%\")\n\n# To reset jqc theme settings to factory defaults\nself.reset_jqc_theme()\n
All methods for Dialog Boxes: self.get_jqc_button_input(message, buttons, options=None)\n\nself.get_jqc_text_input(message, button=None, options=None)\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\nself.set_jqc_theme(theme, color=None, width=None)\n\nself.reset_jqc_theme()\n\nself.activate_jquery_confirm() # Automatic for jqc methods\n
Detailed method summaries for Dialog Boxes: self.get_jqc_button_input(message, buttons, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the text of the button clicked.\nIf running in headless mode, the last button text is returned.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbuttons: A list of tuples for text and color.\n Example: [(\"Yes!\", \"green\"), (\"No!\", \"red\")]\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.get_jqc_text_input(message, button=None, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the text submitted by the input.\nIf running in headless mode, the text returned is \"\" by default.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbutton: A 2-item list or tuple for text and color. Or just the text.\n Example: [\"Submit\", \"blue\"] -> (default button if not specified)\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the input/button texts as tuple.\nIf running in headless mode, returns the (\"\", buttons[-1][0]) tuple.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbuttons: A list of tuples for text and color.\n Example: [(\"Yes!\", \"green\"), (\"No!\", \"red\")]\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.set_jqc_theme(theme, color=None, width=None)\n\"\"\" Sets the default jquery-confirm theme and width (optional).\nAvailable themes: \"bootstrap\", \"modern\", \"material\", \"supervan\",\n \"light\", \"dark\", and \"seamless\".\nAvailable colors: (This sets the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\nWidth can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.reset_jqc_theme()\n\"\"\" Resets the jqc theme settings to factory defaults. \"\"\"\n\nself.activate_jquery_confirm() # Automatic for jqc methods\n\"\"\" See https://craftpip.github.io/jquery-confirm/ for usage. \"\"\"\n
\u2705 \ud83d\udec2 Automated/Manual Hybrid Mode (MasterQA) MasterQA uses SeleniumBase Dialog Boxes to speed up manual testing by having automation perform all the browser actions while the manual tester handles validation. See the MasterQA GitHub page for examples.
"}, {"location": "examples/example_logs/ReadMe/", "title": "\ud83d\udcca Dashboard / Reports", "text": ""}, {"location": "examples/example_logs/ReadMe/#logs-the-dashboard-and-reports", "title": "Logs, The Dashboard, and Reports", "text": "\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. If --archive-logs
is specified (or if ARCHIVE_EXISTING_LOGS is set to True in settings.py), test logs will also get archived to the archived_logs/
folder. Otherwise, the log files will be cleaned out when the next test run begins (by default).
pytest test_fail.py\n
(Log files in SeleniumBase/examples/example_logs were generated when test_fail.py ran and failed.)
Examples of expected log files generated during failures:
In addition to log files, you can also generate dashboards and test reports.
The SeleniumBase Dashboard:\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python 3's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py test_image_saving.py --dashboard --rs --headless\n
Pytest Reports: \ud83d\udd35 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\ud83d\udd35 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\ud83d\udd35 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest-html
reports in Jenkins, you may need to configure Jenkins settings for the HTML to render correctly. This is due to Jenkins CSP changes. That setting can be changed from Manage Jenkins
> Script Console
by running:
System.setProperty(\"hudson.model.DirectoryBrowserSupport.CSP\", \"\")\n
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
pynose Test Reports: The pynose
--report
option gives you a fancy report after your tests complete.
pynose test_suite.py --report\n
(NOTE: You can add --show-report
to immediately display pynose reports after the test suite completes. Only use --show-report
when running tests locally because it pauses the test run.)
(The behave_bdd/ folder can be found in the examples/ folder.)
behave behave_bdd/features/ -D dashboard -D headless\n
You can also use --junit
to get .xml
reports for each Behave feature. Jenkins can use these files to display better reporting for your tests.
behave behave_bdd/features/ --junit -D rs -D headless\n
"}, {"location": "examples/master_qa/ReadMe/", "title": "\ud83d\udec2 MasterQA Mode", "text": "MasterQA combines automation with manual verification steps. Here's code from basic_masterqa_test_0.py:
from seleniumbase import MasterQA\n\nclass MasterQATests(MasterQA):\n def test_masterqa(self):\n self.open(\"https://xkcd.com/1700/\")\n self.verify(\"Do you see a webcomic?\")\n self.open(\"https://seleniumbase.io/demo_page\")\n self.highlight('table')\n self.verify(\"Do you see elements in a table?\")\n self.open(\"https://seleniumbase.io/devices/\")\n self.highlight(\"div.mockup-wrapper\")\n self.verify(\"Do you see 4 computer devices?\")\n
After each automation checkpoint, a pop-up window will ask the user questions for each verification command.
When the test run completes, as seen from this longer example, you'll reach the results page that appears after answering all the verification questions. (Failed verifications generate links to screenshots and log files.)
You may have noticed the Incomplete Test Runs
row on the results page. If the value for that is not zero, it means that one of the automated steps failed. This could happen if you tell your script to perform an action on an element that doesn't exist. Now that we're mixing automation with manual QA, it's good to tell apart the failures from each. The results_table CSV file contains a spreadsheet with the details of each failure (if any) for both manual and automated steps.
How to run the example tests from scratch:
git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase\npip install .\ncd examples/master_qa\npytest basic_masterqa_test_0.py\npytest masterqa_test_1.py\n
At the end of your test run, you'll receive a report with results, screenshots, and log files. Close the Results Page window when you're done.
Check out masterqa_test_1.py to learn how to write your own MasterQA tests:
You'll notice that tests are written the same way as regular SeleniumBase tests, with the key difference being a different import: from seleniumbase import MasterQA
rather than from seleniumbase import BaseCase
. Now your Python test class will import MasterQA
instead of BaseCase
.
To add a manual verification step, use self.verify()
in the code after each part of your test that needs a manual verification step. If you want to include a custom question, add text inside that call (in quotes). Example:
self.verify()\n\nself.verify(\"Can you find the moon?\")\n
MasterQA is powered by SeleniumBase, the most advanced open-source automation framework on the Planet.
"}, {"location": "examples/presenter/ReadMe/", "title": "\ud83c\udf9e\ufe0f Presentation Maker", "text": ""}, {"location": "examples/presenter/ReadMe/#presenter", "title": "\ud83d\udcd1 Presenter \ud83c\udf9e\ufe0f", "text": "SeleniumBase Presenter (slide-maker) lets you use Python to generate HTML presentations.
Here's a sample presentation:
(Click on the image/GIF for the actual presentation)
(Here's the code for that presentation)
Slides can include HTML, code, images, and iframes.
Here's how to run the example presentation:
cd examples/presenter\npytest my_presentation.py\n
Here's a presentation with a chart:
(Click on the image/GIF for the actual presentation)
(Here's the code for that presentation)
Here's how to run that example:
cd examples/presenter\npytest core_presentation.py\n
Creating a new presentation: self.create_presentation(name=None, theme=\"serif\", transition=\"default\")\n\"\"\" Creates a Reveal-JS presentation that you can add slides to.\n @Params\n name - If creating multiple presentations at the same time,\n use this to specify the name of the current presentation.\n theme - Set a theme with a unique style for the presentation.\n Valid themes: \"serif\" (default), \"sky\", \"white\", \"black\",\n \"simple\", \"league\", \"moon\", \"night\",\n \"beige\", \"blood\", and \"solarized\".\n transition - Set a transition between slides.\n Valid transitions: \"none\" (default), \"slide\", \"fade\",\n \"zoom\", \"convex\", and \"concave\".\n\"\"\"\n
If creating multiple presentations at the same time, you can pass the name
parameter to distinguish between different presentations. Notes are disabled by default. You can enable notes by specifying: show_notes=True
self.add_slide(content=None, image=None, code=None, iframe=None,\n content2=None, notes=None, transition=None, name=None)\n\"\"\" Allows the user to add slides to a presentation.\n @Params\n content - The HTML content to display on the presentation slide.\n image - Attach an image (from a URL link) to the slide.\n code - Attach code of any programming language to the slide.\n Language-detection will be used to add syntax formatting.\n iframe - Attach an iFrame (from a URL link) to the slide.\n content2 - HTML content to display after adding an image or code.\n notes - Additional notes to include with the slide.\n ONLY SEEN if show_notes is set for the presentation.\n transition - Set a transition between slides. (overrides previous)\n Valid transitions: \"none\" (default), \"slide\", \"fade\",\n \"zoom\", \"convex\", and \"concave\".\n name - If creating multiple presentations at the same time,\n use this to select the presentation to add slides to.\n\"\"\"\n
Running a presentation: self.begin_presentation(\n filename=\"my_presentation.html\", show_notes=False, interval=0)\n\"\"\" Begin a Reveal-JS Presentation in the web browser.\n @Params\n name - If creating multiple presentations at the same time,\n use this to select the one you wish to add slides to.\n filename - The name of the HTML file that you wish to\n save the presentation to. (filename must end in \".html\")\n show_notes - When set to True, the Notes feature becomes enabled,\n which allows presenters to see notes next to slides.\n interval - The delay time between autoplaying slides. (in seconds)\n If set to 0 (default), autoplay is disabled.\n\"\"\"\n
Before the presentation is run, the full HTML is saved to the saved_presentations/
folder.
All methods have the optional name
argument, which is only needed if you're creating multiple presentations at once.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyPresenterClass(BaseCase):\n def test_presenter(self):\n self.create_presentation(theme=\"serif\")\n self.add_slide(\n '<h1>Welcome</h1><br />\\n'\n '<h3>Press the <b>Right Arrow</b></h3>')\n self.add_slide(\n '<h3>SeleniumBase Presenter</h3><br />\\n'\n '<img width=\"240\" src=\"https://seleniumbase.io/img/logo3a.png\" />'\n '<span style=\"margin:144px;\" />'\n '<img src=\"https://seleniumbase.io/other/python_3d_logo.png\" />'\n '<br /><br />\\n<h4>Create presentations with <b>Python</b></h4>')\n self.add_slide(\n '<h3>Make slides using <b>HTML</b>:</h3><br />\\n'\n '<table style=\"padding:10px;border:4px solid black;font-size:50;\">'\n '\\n<tr style=\"background-color:CDFFFF;\">\\n'\n '<th>Row ABC</th><th>Row XYZ</th></tr>\\n'\n '<tr style=\"background-color:DCFDDC;\">'\n '<td>Value ONE</td><td>Value TWO</td></tr>\\n'\n '<tr style=\"background-color:DFDFFB;\">\\n'\n '<td>Value THREE</td><td>Value FOUR</td></tr>\\n'\n '</table><br />\\n<h4>(HTML <b>table</b> example)</h4>')\n self.add_slide(\n '<h3>Keyboard Shortcuts:</h3>\\n'\n '<table style=\"padding:10px;border:4px solid black;font-size:30;'\n 'background-color:FFFFDD;\">\\n'\n '<tr><th>Key</th><th>Action</th></tr>\\n'\n '<tr><td><b>=></b></td><td>Next Slide (N also works)</td></tr>\\n'\n '<tr><td><b><=</b></td><td>Previous Slide (P also works)</td></tr>'\n '\\n<tr><td>F</td><td>Full Screen Mode</td></tr>\\n'\n '<tr><td>O</td><td>Overview Mode Toggle</td></tr>\\n'\n '<tr><td>esc</td><td>Exit Full Screen / Overview Mode</td></tr>\\n'\n '<tr><td><b>.</b></td><td>Pause/Resume Toggle</td></tr>\\n'\n '<tr><td>space</td><td>Next Slide (alternative)</td></tr></table>')\n self.add_slide(\n '<h3>Add <b>images</b> to slides:</h3>',\n image=\"https://seleniumbase.github.io/other/seagulls.jpg\")\n self.add_slide(\n '<h3>Add <b>code</b> to slides:</h3>',\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n 'class MyTestClass(BaseCase):\\n\\n'\n ' def test_basics(self):\\n'\n ' self.open(\"https://store.xkcd.com/search\")\\n'\n ' self.type(\\'input[name=\"q\"]\\', \"xkcd book\\\\n\")\\n'\n ' self.assert_text(\"xkcd: volume 0\", \"h3\")\\n'\n ' self.open(\"https://xkcd.com/353/\")\\n'\n ' self.assert_title(\"xkcd: Python\")\\n'\n ' self.assert_element(\\'img[alt=\"Python\"]\\')\\n'\n ' self.click(\\'a[rel=\"license\"]\\')\\n'\n ' self.assert_text(\"free to copy and reuse\")\\n'\n ' self.go_back()\\n'\n ' self.click_link(\"About\")\\n'\n ' self.assert_exact_text(\"xkcd.com\", \"h2\")'))\n self.add_slide(\n \"<h3>Highlight <b>code</b> in slides:</h3>\",\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n '<mark>class MyTestClass(BaseCase):</mark>\\n\\n'\n ' def test_basics(self):\\n'\n ' self.open(\"https://store.xkcd.com/search\")\\n'\n ' self.type(\\'input[name=\"q\"]\\', \"xkcd book\\\\n\")\\n'\n ' self.assert_text(\"xkcd: volume 0\", \"h3\")'))\n self.add_slide(\n '<h3>Add <b>iFrames</b> to slides:</h3>',\n iframe=\"https://seleniumbase.io/demo_page\")\n self.add_slide(\n '<h3>Getting started is <b>easy</b>:</h3>',\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n 'class MyPresenterClass(BaseCase):\\n\\n'\n ' def test_presenter(self):\\n'\n ' self.create_presentation(theme=\"serif\")\\n'\n ' self.add_slide(\"Welcome to Presenter!\")\\n'\n ' self.add_slide(\\n'\n ' \"Add code to slides:\",\\n'\n ' code=(\\n'\n ' \"from seleniumbase import BaseCase\\\\n\\\\n\"\\n'\n ' \"class MyPresenterClass(BaseCase):\\\\n\\\\n\"\\n'\n ' \" def test_presenter(self):\\\\n\"\\n'\n ' \" self.create_presentation()\\\\n\"))\\n'\n ' self.begin_presentation(\\n'\n ' filename=\"demo.html\", show_notes=True)'))\n self.add_slide(\n '<h3>Include <b>notes</b> with slides:</h3><br />',\n code=('self.add_slide(\"[Your HTML goes here]\",\\n'\n ' code=\"[Your software code goes here]\",\\n'\n ' content2=\"[Additional HTML goes here]\",\\n'\n ' notes=\"[Attached speaker notes go here]\"\\n'\n ' \"[Note A! -- Note B! -- Note C! ]\")'),\n notes='<h2><ul><li>Note A!<li>Note B!<li>Note C!<li>Note D!</h2>',\n content2=\"<h4>(Notes can include HTML tags)</h4>\")\n self.add_slide(\n '<h3>Multiple <b>themes</b> available:</h3>',\n code=(\n 'self.create_presentation(theme=\"serif\")\\n\\n'\n 'self.create_presentation(theme=\"sky\")\\n\\n'\n 'self.create_presentation(theme=\"simple\")\\n\\n'\n 'self.create_presentation(theme=\"white\")\\n\\n'\n 'self.create_presentation(theme=\"moon\")\\n\\n'\n 'self.create_presentation(theme=\"black\")\\n\\n'\n 'self.create_presentation(theme=\"night\")\\n\\n'\n 'self.create_presentation(theme=\"beige\")\\n\\n'\n 'self.create_presentation(theme=\"league\")'))\n self.add_slide(\n '<h2><b>The End</b></h2>',\n image=\"https://seleniumbase.github.io/img/sb_logo_10.png\")\n self.begin_presentation(\n filename=\"presenter.html\", show_notes=True, interval=0)\n
That example is from my_presentation.py, which you can run from the examples/presenter
folder with the following command:
pytest my_presentation.py\n
Saving a presentation: If you want to save the presentation you created as an HTML file, use:
self.save_presentation(filename=\"my_presentation.html\", show_notes=True)\n
Presentations automatically get saved when calling:
self.begin_presentation(show_notes=True)\n
Special abilities: If you want to highlight multiple lines at different times in the same slide with the <mark>
/ </mark>
tags, you can use the new <mk-0>
-</mk-0>
, <mk-1>
-</mk-1>
tags, which will generate multiple HTML slides from one Python slide.
Example:
self.add_slide(\n code=(\n <p><mk-0>Highlight this on the 1st generated slide</mk-0></p>\n <p><mk-1>Highlight this on the 2nd generated slide</mk-1></p>\n <p><mk-2>Highlight this on the 3rd generated slide</mk-2></p>\n <p><mk-3>Highlight this on the 4th generated slide</mk-3></p>\n )\n)\n
Those should automatically get converted to <mark>
... </mark>
on their turn:
Eg. First generated slide:
<p><mark>Highlight this on the first generated slide</mark></p>\n<p>Highlight this on the second generated slide</p>\n<p>Highlight this on the third generated slide</p>\n<p>Highlight this on the fourth generated slide></p>\n
Eg. Second generated slide:
<p>Highlight this on the first generated slide</p>\n<p><mark>Highlight this on the second generated slide</mark></p>\n<p>Highlight this on the third generated slide</p>\n<p>Highlight this on the fourth generated slide></p>\n
Etc...
"}, {"location": "examples/tour_examples/ReadMe/", "title": "\ud83d\ude8e Tour Maker", "text": ""}, {"location": "examples/tour_examples/ReadMe/#interactive-product-tours", "title": "Interactive Product Tours \ud83d\ude8e", "text": "Increase SaaS Product Adoption by 10x or more.
IntroJS, Bootstrap Tour, DriverJS, Shepherd, and Hopscotch.
A tour demo: (with autoplay)
SeleniumBase maps_introjs_tour.py
cd examples/tour_examples\npytest maps_introjs_tour.py --interval=1\n
Here's a longer version:
SeleniumBase google_tour.py
cd examples/tour_examples\npytest google_tour.py\n
(From GitHub => SeleniumBase/examples/tour_examples)
"}, {"location": "examples/tour_examples/ReadMe/#creating-a-new-tour", "title": "Creating a new tour", "text": ""}, {"location": "examples/tour_examples/ReadMe/#to-create-a-tour-utilizing-the-shepherd-library-use-one-of-the-following", "title": "To create a tour utilizing the Shepherd Library, use one of the following", "text": "self.create_shepherd_tour()
OR
self.create_tour(theme=\"shepherd\")
You can pass a custom theme to change the look & feel of Shepherd tours. Valid themes for Shepherd Tours are dark
, light
/ arrows
, default
, square
, and square-dark
.
self.create_bootstrap_tour()
OR
self.create_tour(theme=\"bootstrap\")
self.create_introjs_tour()
OR
self.create_tour(theme=\"introjs\")
self.create_driverjs_tour()
OR
self.create_tour(theme=\"driverjs\")
self.create_hopscotch_tour()
OR
self.create_tour(theme=\"hopscotch\")
self.add_tour_step(message, css_selector, title, alignment, theme)
With the self.add_tour_step()
method, you must first pass a message to display. You can then specify a web element to attach to (by using CSS selectors). If no element is specified, the tour step will tether to the top of the screen by default. You can also add an optional title above the message to display with the tour step, as well as change the theme for that step (Shepherd tours only), and even specify the alignment (which is the side of the element that you want the tour message to tether to).
You can play a tour by calling:
self.play_tour(interval)
If you specify an interval
(optional), the tour will automatically walk through each step after that many seconds have passed.
All methods have the optional name
argument, which is only needed if you're creating multiple tours at once. Then, when you're adding a step or playing a tour, SeleniumBase knows which tour you're referring too. You can avoid using the name
arg for multiple tours if you play a tour before creating a new one.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTourClass(BaseCase):\n\n def test_google_tour(self):\n self.open('https://google.com/ncr')\n self.wait_for_element('input[title=\"Search\"]')\n self.hide_elements(\"iframe\")\n\n self.create_tour(theme=\"dark\")\n self.add_tour_step(\"Welcome to Google!\", title=\"SeleniumBase Tours\")\n self.add_tour_step(\"Type in your query here.\", '[title=\"Search\"]')\n self.play_tour()\n\n self.highlight_type('input[title=\"Search\"]', \"Google\")\n self.wait_for_element('[role=\"listbox\"]') # Wait for autocomplete\n\n self.create_tour(theme=\"light\")\n self.add_tour_step(\"Then click to search.\", '[value=\"Google Search\"]')\n self.add_tour_step(\"Or press [ENTER] after entry.\", '[title=\"Search\"]')\n self.play_tour()\n
"}, {"location": "examples/tour_examples/ReadMe/#that-code-is-from-google_tourpy-which-you-can-run-from-the-tour_examples-folder-with-the-following-command", "title": "That code is from google_tour.py, which you can run from the tour_examples/
folder with the following command", "text": "pytest google_tour.py\n
"}, {"location": "examples/tour_examples/ReadMe/#exporting-a-tour", "title": "Exporting a Tour", "text": "If you want to save the tour you created as a JavaScript file, use:
self.export_tour()
OR
self.export_tour(name=None, filename=\"my_tour.js\")
(name
is optional unless you gave custom names to your tours when you created them. filename
is the name of the file to save the JavaScript to.) Once you've exported your tour, you can use it outside of SeleniumBase. You can even copy the tour's JavaScript code to the Console of your web browser to play the tour from there (you need to be on the correct web page for it to work).
Automated Visual Regression Testing can help you detect when the layout of a web page has changed. Instead of comparing pixels from screenshots, layout differences can be detected by comparing HTML tags and attributes with a baseline. If a change is detected, it could mean that something broke, the web page was redesigned, or dynamic content changed.
To handle automated visual testing, SeleniumBase uses the self.check_window()
method, which can set visual baselines for comparison and then compare the latest versions of web pages to the existing baseline.
The first time a test calls self.check_window()
with a unique name
parameter, the visual baseline is set, which means a folder is created with the following files:
After the first time self.check_window()
is called, later calls will compare the HTML tags and attributes of the latest window to the ones from the first call (or to the ones from the call when the baseline was last reset). Additionally, a latest.png
screenshot is saved in the same folder, which can help you determine if/when the existing baseline needs to be reset.
Here's an example call:
self.check_window(name=\"first_test)\", level=3)\n
On the first run (or if the baseline is being set/reset) the \"level\" doesn't matter because that's only used for comparing the current layout to the existing baseline.
Here's how the level system works:
As shown, Level-3 is the most strict, Level-1 is the least strict. If the comparisons from the latest window to the existing baseline don't match, the current test will fail, except for Level-0 checks, which print Level-3 results without failing the test.
You can reset the visual baseline on the command line by adding the following parameter at runtime:
--visual_baseline\n
As long as --visual_baseline
is used on the command line while running tests, the self.check_window()
method cannot fail because it will rebuild the visual baseline rather than comparing the html tags of the latest run to the existing baseline. If there are any expected layout changes to a website that you're testing, you'll need to reset the baseline to prevent unnecessary failures.
self.check_window()
will fail with \"Page Domain Mismatch Failure\" if the domain of the current URL doesn't match the domain of the baseline URL.
If you want to use self.check_window()
to compare a web page to a later version of itself in the same test, add the baseline=True
parameter to your first self.check_window()
call to use that as the baseline. (This only makes sense if you're calling self.check_window()
more than once with the same \"name\" parameter in the same test.)
Automated Visual Testing with self.check_window()
is not very effective for websites that have dynamic content because that changes the layout and structure of web pages. For those pages, you're much better off using regular SeleniumBase functional testing, unless you can remove the dynamic content before performing the comparison, (such as by using self.ad_block()
to remove dynamic ad content on a web page).
Example usage of self.check_window()
with different levels:
self.check_window(name=\"testing\", level=0)\n self.check_window(name=\"xkcd_home\", level=1)\n self.check_window(name=\"github_page\", level=2)\n self.check_window(name=\"wikipedia_page\", level=3)\n\n self.check_window(name=\"helloworld\", baseline=True)\n ### Do something that may change the web page\n self.check_window(name=\"helloworld\", level=3)\n
Here's an example where clicking a button makes a hidden element visible:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_applitools_layout_change_failure(self):\n self.open('https://applitools.com/helloworld?diff1')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"helloworld\", baseline=True)\n # Click a button that changes the text of an element\n self.click('a[href=\"?diff1\"]')\n # Click a button that makes a hidden element visible\n self.click(\"button\")\n self.check_window(name=\"helloworld\", level=3)\n
Here's the output of that: (Text changes do not impact visual comparisons)
AssertionError:\nFirst differing element 39:\n['div', [['class', ['section', 'hidden-section', 'image-section']]]]\n['div', [['class', ['section', 'image-section']]]]\n\n- ['div', [['class', ['section', 'hidden-section', 'image-section']]]],\n? ------------------\n+ ['div', [['class', ['section', 'image-section']]]],\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
Here's an example where a button is removed from a web page:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_python_home_layout_change_failure(self):\n self.open('https://python.org/')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"python_home\", baseline=True)\n # Remove the \"Donate\" button\n self.remove_element('a.donate-button')\n self.check_window(name=\"python_home\", level=3)\n
Here's the output of that:
AssertionError:\nFirst differing element 33:\n['a', [['class', ['donate-button']], ['href', '/psf/donations/']]]\n['div', [['class', ['options-bar']]]]\n\n- ['a', [['class', ['donate-button']], ['href', '/psf/donations/']]],\n- 'display: list-item; opacity: 0.995722;']]],\n? -------------------\n+ 'display: list-item;']]],\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
Here's the side_by_side.html
file for that, (from the ./latest_logs/
folder), which shows a visual comparison of the two screenshots as a result of the missing \"Donate\" button:
Here's another example, where a web site logo is resized:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_xkcd_layout_change_failure(self):\n self.open('https://xkcd.com/554/')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"xkcd_554\", baseline=True)\n # Change height: (83 -> 130) , Change width: (185 -> 120)\n self.set_attribute('[alt=\"xkcd.com logo\"]', \"height\", \"130\")\n self.set_attribute('[alt=\"xkcd.com logo\"]', \"width\", \"120\")\n self.check_window(name=\"xkcd_554\", level=3)\n
Here's the output of that:
AssertionError:\nFirst differing element 22:\n['img[30 chars]['height', '83'], ['src', '/s/0b7742.png'], ['width', '185']]]\n['img[30 chars]['height', '130'], ['src', '/s/0b7742.png'], ['width', '120']]]\n\n- ['height', '83'],\n? ^\n+ ['height', '130'],\n? ^ +\n- ['width', '185']]],\n? ^^\n+ ['width', '120']]],\n? ^^\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
To run the example (from examples/visual_testing/) with a pytest HTML Report, use:
pytest test_layout_fail.py --html=report.html\n
Here's what the pytest HTML Report looks like:
In conclusion, open source automated visual testing tools are being built directly into test frameworks, and this trend is growing. Just like many years ago when free Wi-Fi at coffee shops replaced Internet cafes that charged money for Internet access, open source tools for visual testing will replace their paid counterparts in time. You'll remember this next time you're sipping your Starbucks\u00ae Pumpkin Spice Latte with your free Internet access, instead of paying for Internet at cybercafes.
"}, {"location": "help_docs/ReadMe/", "title": "\ud83d\udcd1 Table of Contents", "text": ""}, {"location": "help_docs/ReadMe/#help-docs", "title": "Help Docs", "text": "\ud83d\ude80 Start | \ud83d\udcca Dashboard \ud83c\udff0 Features | \ud83c\udf9b\ufe0f Options \ud83d\udcda Examples | \ud83d\udcf1 Emulator \ud83c\udf20 Console Scripts | \ud83c\udf10 Grid \ud83d\udcd8 Methods / APIs | \ud83d\ude8e Tours \ud83d\udd21 Syntax Formats | \ud83e\udd16 CI/CD \u267b\ufe0f Boilerplates | \ud83d\uddfe Locale Codes \ud83d\udd79\ufe0f JS Manager | \ud83d\uddbc\ufe0f Visual Testing \ud83c\udf0f Translator | \ud83d\udec2 Dialog Boxes \ud83d\udd34 Recorder | \ud83d\udcbb Device Farm \ud83c\udf9e\ufe0f Slides | \ud83d\udcf6 Chart Maker \ud83c\udf96\ufe0f GUI | \ud83d\udc64 UC Mode
Table of Contents (seleniumbase.io) Features List Command Line Tutorial Usage Examples Demo Page for Tests How SeleniumBase Works Installing Python, Pip, & Git Python Virtual Env Tutorial SeleniumBase Installation Webdriver Installation Verify Webdriver Works Console Scripts Tutorial The Dashboard Recorder Mode pytest Commander Method Summary Syntax Formats Behave BDD Behave Commander Mobile Device Testing Case Plans Chart Maker Language Translations Language Locale Codes JS Package Manager Tour Maker Presentation Maker Handling iframes Undetected Mode (UC Mode) MySQL Installation Overview Using the Selenium Grid Browser Desired Capabilities Safari Driver Detailed Info Seeing Hidden Files on macOS Case Studies Demo Pages / Web Examples Coffee Cart (Test Page) Demo Page (Test Page) Simple App (Test Page) MFA Login (Test Page) TinyMCE (Test Page) Error Page (Test Page) Drag & Drop (Test Page) Device Farm (Virtual) HTML Playground Page SeleniumBase in iframe Page with broken links Shadow DOM/Root W3Schools iframes W3Schools file upload W3Schools doubleclick W3Schools drag & drop W3Schools checkboxes W3Schools radio buttons Presentations Presenter Demo Core Presentation Chart Maker Demo Python Virtual Envs GitHub Pages (seleniumbase.dev) Features List Command Line Tutorial Usage Examples How SeleniumBase Works Installing Python, Pip, & Git Python Virtual Env Tutorial SeleniumBase Installation Webdriver Installation Verify Webdriver Works Console Scripts Tutorial The Dashboard Recorder Mode pytest Commander Syntax Formats Behave BDD Behave Commander Mobile Device Testing Method Summary (API Ref) Case Plans Language Translations Language Locale Codes JS Package Manager Tour Examples Presentation Maker Chart Maker Handling iframes MySQL Installation Overview Using the Selenium Grid Browser Desired Capabilities Safari Driver Detailed Info Seeing Hidden Files on macOS Case Studies"}, {"location": "help_docs/behave_gui/", "title": "\ud83d\udc1d Behave-BDD GUI App", "text": ""}, {"location": "help_docs/behave_gui/#seleniumbase-behave-gui-commander", "title": "SeleniumBase Behave GUI / Commander \ud83d\udc1d\ud83c\udf96\ufe0f", "text": "
\ud83d\udc1d\ud83c\udf96\ufe0f The SeleniumBase Behave GUI lets you run behave
scripts from a Desktop GUI.
\ud83d\udc1d\ud83c\udf96\ufe0f To launch it, call sbase behave-gui
or sbase gui-behave
:
> sbase behave-gui\n* Starting the SeleniumBase Behave Commander GUI App...\n
\ud83d\udc1d\ud83c\udf96\ufe0f SeleniumBase Behave GUI loads the same tests that are found by:
behave -d\n
\ud83d\udc1d\ud83c\udf96\ufe0f You can customize which tests are loaded by passing additional args:
sbase behave-gui [OPTIONAL PATH or TEST FILE]\n
\ud83d\udc1d\ud83c\udf96\ufe0f Here are examples of customizing test collection:
sbase behave-gui # all tests\nsbase behave-gui -i=calculator # tests with \"calculator\" in the name\nsbase behave-gui features/ # tests located in the \"features/\" folder\nsbase behave-gui features/calculator.feature # tests in that feature\n
\ud83d\udc1d\ud83c\udf96\ufe0f Once launched, you can further customize which tests to run and what settings to use. There are various controls for changing settings, modes, and other \"behave\" command line options that are specific to SeleniumBase. You can also set additional options that don't have a visible toggle. When you're ready to run the selected tests with the specified options, click on the Run Selected Tests
button.
\ud83d\udc1d\u26aa With the Dashboard enabled, you'll get one of these:
To learn more about SeleniumBase, check out the Docs Site:All the code is on GitHub:
"}, {"location": "help_docs/case_plans/", "title": "\ud83d\uddc2\ufe0f Case Plans", "text": ""}, {"location": "help_docs/case_plans/#seleniumbase-case-plans", "title": "SeleniumBase Case Plans \ud83d\uddc2\ufe0fSummary of existing Case Plans", "text": "
\ud83d\uddc2\ufe0f SeleniumBase Case Plans is Test Case Management Software that uses Markdown tables for displaying test plans directly in GitHub (and other source code management systems that support Markdown format).
\ud83d\uddc2\ufe0f The case_summary.md
file is generated from individual Case Plans that exist in the case_plans/
folders of your repository. (See the example below to learn how the Case Summary file may look.)
Example of a case_summary.md
file:
basic_test.py::MyTestClass::test_basics
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | | 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | | 4 | Remove the ``Backpack`` from the cart. | The ``Backpack`` is no longer in the cart. | | 5 | Log out from the website. | Logout was successful. | \ud83d\udd35 list_assert_test.py::MyTestClass::test_assert_list_of_elements
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/demo_page. | | | 2 | Use ``self.assert_elements_present(\"head\", \"style\", \"script\")`` to verify that multiple elements are present in the HTML. | The assertion is successful. | | 3 | Use ``self.assert_elements(\"h1\", \"h2\", \"h3\")`` to verify that multiple elements are visible. | The assertion is successful. | | 4 | Use ``self.assert_elements([\"#myDropdown\", \"#myButton\", \"#svgRect\"])`` to verify that multiple elements are visible. | The assertion is successful. | \u2b55 locale_code_test.py::LocaleCodeTests::test_locale_code
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Perform Action 1 | Verify Action 1 | | 2 | Perform Action 2 | Verify Action 2 | \ud83d\udd35 my_first_test.py::MyTestClass::test_swag_labs
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | | 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | | 4 | Click on the ``CHECKOUT`` button. Enter user details and click ``CONTINUE``. | The ``Backpack`` is seen in the cart on the ``CHECKOUT: OVERVIEW`` page. | | 5 | Click on the ``FINISH`` button. | There is a ``Thank You`` message and a ``Pony Express`` delivery logo. | | 6 | Log out from the website. | Logout was successful. | \u2b55 proxy_test.py::ProxyTests::test_proxy
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Perform Action 1 | Verify Action 1 | | 2 | Perform Action 2 | Verify Action 2 | \ud83d\udd35 shadow_root_test.py::ShadowRootTest::test_shadow_root
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/other/shadow_dom. Click each tab and verify the text contained within the Shadow Root sections. | Tab 1 text: ``Content Panel 1`` Tab 2 text: ``Content Panel 2`` Tab 3 text: ``Content Panel 3`` | \ud83d\udea7 test_agent.py::UserAgentTests::test_user_agent
test_calculator.py::CalculatorTests::test_6_times_7_plus_12_equals_54
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/apps/calculator. Perform the following calculation: ``6 \u00d7 7 + 12`` | The output is ``54`` after pressing ``=`` | \ud83d\udd35 test_demo_site.py::DemoSiteTests::test_demo_site
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/demo_page | | | 2 | Assert the title of the current web page. Assert that a given element is visible on the page. Assert that a text substring appears in an element's text. | The assertions were successful. | | 3 | Type text into various text fields and then verify. | The assertions were successful. | | 4 | Verify that a hover dropdown link changes page text. | The assertion was successful. | | 5 | Verify that a button click changes text on the page. | The assertion was successful. | | 6 | Verify that an SVG element is located on the page. | The assertion was successful. | | 7 | Verify that a slider control updates a progress bar. | The assertion was successful. | | 8 | Verify that a \"select\" option updates a meter bar. | The assertion was successful. | | 9 | Assert an element located inside an iFrame. | The assertion was successful. | | 10 | Assert text located inside an iFrame. | The assertion was successful. | | 11 | Verify that clicking a radio button selects it. | The assertion was successful. | | 12 | Verify that clicking an empty checkbox makes it selected. | The assertion was successful. | | 13 | Verify clicking on multiple elements with one call. | The assertions were successful. | | 14 | Verify that clicking an iFrame checkbox selects it. | The assertions were successful. | | 15 | Verify that Drag and Drop works. | The assertion was successful. | | 16 | Assert link text. | The assertion was successful. | | 17 | Verify clicking on link text. | The action was successful. | | 18 | Assert exact text in an element. | The assertion was successful. | | 19 | Highlight a page element. | The action was successful. | | 20 | Verify that Demo Mode works. | The assertion was successful. | \ud83d\udd35 test_login.py::SwagLabsLoginTests::test_swag_labs_login
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Log out from the website. | Logout was successful. | \ud83d\udd35 test_mfa_login.py::TestMFALogin::test_mfa_login
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/realworld/login Enter credentials and Sign In. | Sign In was successful. | | 2 | Click the ``This Page`` button. Save a screenshot to the logs. | | | 3 | Click to Sign Out | Sign Out was successful. | \ud83d\uddc2\ufe0f Before you can generate a case_summary.md
file that includes your existing Case Plans, first you'll need to select which existing tests you want to create boilerplate Case Plans from. For that, you can use the SeleniumBase Case Plans GUI:
sbase caseplans\n
\ud83d\uddc2\ufe0f Once you are running the Case Plans GUI, select the existing tests that need Case Plans, and then click: Generate boilerplate Case Plans for selected tests missing them
. For each selected test that didn't already have a Case Plan file, one will be generated. Each new Case Plan file starts with default boilerplate code with a Markdown table. Eg:
``proxy_test.py::ProxyTests::test_proxy``\n---\n| # | Step Description | Expected Result |\n| - | ---------------- | --------------- |\n| 1 | Perform Action 1 | Verify Action 1 |\n| 2 | Perform Action 2 | Verify Action 2 |\n
\ud83d\uddc2\ufe0f When rendered as a Markdown table, the result looks like this:
"}, {"location": "help_docs/case_plans/#proxy_testpyproxyteststest_proxy", "title": "proxy_test.py::ProxyTests::test_proxy
", "text": "# Step Description Expected Result 1 Perform Action 1 Verify Action 1 2 Perform Action 2 Verify Action 2 \ud83d\uddc2\ufe0f Markdown tables are flexible, but must be constructed correctly to be displayed. For a Markdown table to render, it's important that you place pipes (|
), dashes (-
), and spaces in the correct locations. If you want a line break in a step, use <br />
. If you want an empty step, put a space between pipes, eg: | |
.
\ud83d\uddc2\ufe0f Here's an example of a Case Plan for my_first_test.py:
"}, {"location": "help_docs/case_plans/#my_first_testpymytestclasstest_swag_labs", "title": "my_first_test.py::MyTestClass::test_swag_labs
", "text": "# Step Description Expected Result 1 Log in to https://www.saucedemo.com with standard_user
. Login was successful. 2 Click on the Backpack
ADD TO CART
button. The button text changed to REMOVE
. 3 Click on the cart icon. The Backpack
is seen in the cart. 4 Click on the CHECKOUT
button. Enter user details and click CONTINUE
. The Backpack
is seen in the cart on the CHECKOUT: OVERVIEW
page. 5 Click on the FINISH
button. There is a Thank you
message. 6 Log out from the website. Logout was successful. \ud83d\uddc2\ufe0f After you've created some Case Plans, you can use the Generate Summary of existing Case Plans
button in the Case Plans GUI to generate the Case Plans Summary file.
\ud83d\uddc2\ufe0f The generated Case Plans summary file, case_summary.md
, gets created in the same location where the Case Plans GUI was launched. This is NOT the same location where individual Case Plan boilerplates are generated, which is in the case_plans/
folders. The case_plans/
folders are generated where individual tests live, which means that if you have your tests in multiple folders, then you could also have multiple case_plans/
folders. A case_summary.md
file may look like this when rendered:
\ud83d\uddc2\ufe0f When calling sbase caseplans
, you can provide additional arguments to limit the tests that appear in the list. The same discovery rules apply as when using pytest
. Eg:
sbase caseplans\nsbase caseplans -k agent\nsbase caseplans -m marker2\nsbase caseplans test_suite.py\nsbase caseplans offline_examples/\n
To learn more about SeleniumBase, check out the Docs Site: All the code is on GitHub:
"}, {"location": "help_docs/commander/", "title": "\ud83c\udf96\ufe0f GUI / Commander", "text": ""}, {"location": "help_docs/commander/#seleniumbase-commander", "title": "SeleniumBase Commander \ud83c\udf96\ufe0f", "text": "
\ud83c\udf96\ufe0f SeleniumBase Commander lets you run pytest
scripts from a Desktop GUI.
\ud83c\udf96\ufe0f To launch it, call sbase commander
or sbase gui
:
sbase gui\n* Starting the SeleniumBase Commander Desktop App...\n
\ud83c\udf96\ufe0f SeleniumBase Commander loads the same tests that are found by:
pytest --co -q\n
\ud83c\udf96\ufe0f You can customize which tests are loaded by passing additional args:
sbase commander [OPTIONAL PATH or TEST FILE]\nsbase gui [OPTIONAL PATH or TEST FILE]\n
\ud83c\udf96\ufe0f Here are examples of customizing test collection:
sbase gui\nsbase gui -k agent\nsbase gui -m marker2\nsbase gui test_suite.py\nsbase gui offline_examples/\n
\ud83c\udf96\ufe0f Once launched, you can further customize which tests to run and what settings to use. There are various controls for changing settings, modes, and other pytest command line options that are specific to SeleniumBase. You can also set additional options that don't have a visible toggle. When you're ready to run the selected tests with the specified options, click on the Run Selected Tests
button.
All the code is on GitHub:
"}, {"location": "help_docs/customizing_test_runs/", "title": "\ud83c\udf9b\ufe0f Command Line Options", "text": ""}, {"location": "help_docs/customizing_test_runs/#pytest-options-for-seleniumbase", "title": "pytest options for SeleniumBase", "text": "
\ud83c\udf9b\ufe0f SeleniumBase's pytest plugin lets you customize test runs from the CLI (Command-Line Interface), which adds options for setting/enabling the browser type, Dashboard Mode, Demo Mode, Headless Mode, Mobile Mode, Multi-threading Mode, Recorder Mode, reuse-session mode, proxy config, user agent config, browser extensions, html-report mode, and more.
\ud83c\udf9b\ufe0f Here are some examples of configuring tests, which can be run from the examples/ folder:
# Run a test in Chrome (default browser)\npytest my_first_test.py\n\n# Run a test in Firefox\npytest test_swag_labs.py --firefox\n\n# Run a test in Demo Mode (highlight assertions)\npytest test_demo_site.py --demo\n\n# Run a test in Headless Mode (invisible browser)\npytest test_demo_site.py --headless\n\n# Run tests multi-threaded using [n] threads\npytest test_suite.py -n4\n\n# Reuse the browser session for all tests (\"--reuse-session\")\npytest test_suite.py --rs\n\n# Reuse the browser session, but erase cookies between tests\npytest test_suite.py --rs --crumbs\n\n# Create a real-time dashboard for test results\npytest test_suite.py --dashboard\n\n# Create a pytest html report after tests are done\npytest test_suite.py --html=report.html\n\n# Activate Debug Mode on failures (\"c\" to continue)\npytest test_fail.py --pdb -s\n\n# Rerun failing tests more times\npytest test_suite.py --reruns=1\n\n# Activate Debug Mode as the test begins (\"n\": next. \"c\": continue)\npytest test_null.py --trace -s\n\n# Activate Recorder/Debug Mode as the test begins (\"c\" to continue)\npytest test_null.py --recorder --trace -s\n\n# Pass extra data into tests (retrieve by calling self.data)\npytest my_first_test.py --data=\"ABC,DEF\"\n\n# Run tests on a local Selenium Grid\npytest test_suite.py --server=\"127.0.0.1\"\n\n# Run tests on a remote Selenium Grid\npytest test_suite.py --server=IP_ADDRESS --port=4444\n\n# Run tests on a remote Selenium Grid with authentication\npytest test_suite.py --server=USERNAME:KEY@IP_ADDRESS --port=80\n\n# Run tests through a proxy server\npytest proxy_test.py --proxy=IP_ADDRESS:PORT\n\n# Run tests through a proxy server with authentication\npytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n\n# Run tests while setting the web browser's User Agent\npytest user_agent_test.py --agent=\"USER-AGENT-STRING\"\n\n# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"360,640,2\"\n\n# Run a test with an option to evade bot-detection services\npytest verify_undetected.py --uc\n\n# Run tests while changing SeleniumBase default settings\npytest my_first_test.py --settings-file=custom_settings.py\n
\ud83c\udf9b\ufe0f You can interchange pytest
with nosetests
for most tests, but using pytest
is recommended. (chrome
is the default browser if not specified.)
\ud83c\udf9b\ufe0f If you're using pytest
for running tests outside of the SeleniumBase repo, you'll want a copy of pytest.ini at the base of the new folder structure. If using nosetests
, the same applies for setup.cfg.
\ud83c\udf9b\ufe0f Here are some useful command-line options that come with pytest
:
-v # Verbose mode. Prints the full name of each test and shows more details.\n-q # Quiet mode. Print fewer details in the console output when running tests.\n-x # Stop running the tests after the first failure is reached.\n--html=report.html # Creates a detailed pytest-html report after tests finish.\n--co | --collect-only # Show what tests would get run. (Without running them)\n--co -q # (Both options together!) - Do a dry run with full test names shown.\n-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)\n-s # See print statements. (Should be on by default with pytest.ini present.)\n--junit-xml=report.xml # Creates a junit-xml report after tests finish.\n--pdb # If a test fails, enter Post Mortem Debug Mode. (Don't use with CI!)\n--trace # Enter Debug Mode at the beginning of each test. (Don't use with CI!)\n-m=MARKER # Run tests with the specified pytest marker.\n
\ud83c\udf9b\ufe0f SeleniumBase provides additional pytest
command-line options for tests:
--browser=BROWSER # (The web browser to use. Default: \"chrome\".)\n--chrome # (Shortcut for \"--browser=chrome\". On by default.)\n--edge # (Shortcut for \"--browser=edge\".)\n--firefox # (Shortcut for \"--browser=firefox\".)\n--safari # (Shortcut for \"--browser=safari\".)\n--settings-file=FILE # (Override default SeleniumBase settings.)\n--env=ENV # (Set the test env. Access with \"self.env\" in tests.)\n--account=STR # (Set account. Access with \"self.account\" in tests.)\n--data=STRING # (Extra test data. Access with \"self.data\" in tests.)\n--var1=STRING # (Extra test data. Access with \"self.var1\" in tests.)\n--var2=STRING # (Extra test data. Access with \"self.var2\" in tests.)\n--var3=STRING # (Extra test data. Access with \"self.var3\" in tests.)\n--variables=DICT # (Extra test data. Access with \"self.variables\".)\n--user-data-dir=DIR # (Set the Chrome user data directory to use.)\n--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)\n--server=SERVER # (The Selenium Grid server/IP used for tests.)\n--port=PORT # (The Selenium Grid port used by the test server.)\n--cap-file=FILE # (The web browser's desired capabilities to use.)\n--cap-string=STRING # (The web browser's desired capabilities to use.)\n--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)\n--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)\n--proxy-bypass-list=STRING # (\";\"-separated hosts to bypass, Eg \"*.foo.com\")\n--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)\n--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)\n--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)\n--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)\n--agent=STRING # (Modify the web browser's User-Agent string.)\n--mobile # (Use the mobile device emulator while running tests.)\n--metrics=STRING # (Set mobile metrics: \"CSSWidth,CSSHeight,PixelRatio\".)\n--chromium-arg=\"ARG=N,ARG2\" # (Set Chromium args, \",\"-separated, no spaces.)\n--firefox-arg=\"ARG=N,ARG2\" # (Set Firefox args, comma-separated, no spaces.)\n--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)\n--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)\n--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)\n--disable-features=\"F1,F2\" # (Disable features, comma-separated, no spaces.)\n--binary-location=PATH # (Set path of the Chromium browser binary to use.)\n--driver-version=VER # (Set the chromedriver or uc_driver version to use.)\n--sjw # (Skip JS Waits for readyState to be \"complete\" or Angular to load.)\n--pls=PLS # (Set pageLoadStrategy on Chrome: \"normal\", \"eager\", or \"none\".)\n--headless # (Run tests in headless mode. The default arg on Linux OS.)\n--headless2 # (Use the new headless mode, which supports extensions.)\n--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)\n--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)\n--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)\n--interval=SECONDS # (The autoplay interval for presentations & tour steps)\n--start-page=URL # (The starting URL for the web browser when tests begin.)\n--archive-logs # (Archive existing log files instead of deleting them.)\n--archive-downloads # (Archive old downloads instead of deleting them.)\n--time-limit=SECONDS # (Safely fail any test that exceeds the time limit.)\n--slow # (Slow down the automation. Faster than using Demo Mode.)\n--demo # (Slow down and visually see test actions as they occur.)\n--demo-sleep=SECONDS # (Set the wait time after Slow & Demo Mode actions.)\n--highlights=NUM # (Number of highlight animations for Demo Mode actions.)\n--message-duration=SECONDS # (The time length for Messenger alerts.)\n--check-js # (Check for JavaScript errors after page loads.)\n--ad-block # (Block some types of display ads from loading.)\n--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)\n--block-images # (Block images from loading during tests.)\n--do-not-track # (Indicate to websites that you don't want to be tracked.)\n--verify-delay=SECONDS # (The delay before MasterQA verification checks.)\n--ee | --esc-end # (Lets the user end the current test via the ESC key.)\n--recorder # (Enables the Recorder for turning browser actions into code.)\n--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)\n--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)\n--rec-print # (If the Recorder is enabled, prints output after tests end.)\n--disable-js # (Disable JavaScript on websites. Pages might break!)\n--disable-csp # (Disable the Content Security Policy of websites.)\n--disable-ws # (Disable Web Security on Chromium-based browsers.)\n--enable-ws # (Enable Web Security on Chromium-based browsers.)\n--enable-sync # (Enable \"Chrome Sync\" on websites.)\n--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)\n--uc-cdp-events # (Capture CDP events when running in \"--undetected\" mode.)\n--log-cdp # (\"goog:loggingPrefs\", {\"performance\": \"ALL\", \"browser\": \"ALL\"})\n--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)\n--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)\n--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)\n--dash-title=STRING # (Set the title shown for the generated dashboard.)\n--enable-3d-apis # (Enables WebGL and 3D APIs.)\n--swiftshader # (Chrome \"--use-gl=angle\" / \"--use-angle=swiftshader-webgl\")\n--incognito # (Enable Chrome's Incognito mode.)\n--guest # (Enable Chrome's Guest mode.)\n--dark # (Enable Chrome's Dark mode.)\n--devtools # (Open Chrome's DevTools when the browser opens.)\n--rs | --reuse-session # (Reuse browser session for all tests.)\n--rcs | --reuse-class-session # (Reuse session for tests in class.)\n--crumbs # (Delete all cookies between tests reusing a session.)\n--disable-beforeunload # (Disable the \"beforeunload\" event on Chrome.)\n--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)\n--maximize # (Start tests with the browser window maximized.)\n--screenshot # (Save a screenshot at the end of each test.)\n--no-screenshot # (No screenshots saved unless tests directly ask it.)\n--visual-baseline # (Set the visual baseline for Visual/Layout tests.)\n--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)\n--external-pdf # (Set Chromium \"plugins.always_open_pdf_externally\":True.)\n--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)\n--list-fail-page # (After each failing test, list the URL of the failure.)\n
(For more details, see the full list of command-line options here.)
\ud83c\udf9b\ufe0f You can also view a list of popular pytest
options for SeleniumBase by typing:
seleniumbase options\n
Or the short form:
sbase options\n
Example tests using Logging: To see logging abilities, you can run a test suite that includes tests that fail on purpose:
pytest test_suite.py\n
\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. If --archive-logs
is specified (or if ARCHIVE_EXISTING_LOGS is set to True in settings.py), test logs will also get archived to the archived_logs/
folder. Otherwise, the log files will be cleaned out when the next test run begins (by default).
\ud83d\udd35 If any test is moving too fast for your eyes to see what's going on, you can run it in Demo Mode by adding --demo
on the command line, which pauses the browser briefly between actions, highlights page elements being acted on, and lets you know what test assertions are happening in real time:
pytest my_first_test.py --demo\n
\ud83d\udd35 You can override the default wait time by either updating settings.py or by using --demo-sleep=NUM
when using Demo Mode. (NOTE: If you use --demo-sleep=NUM
without using --demo
, nothing will happen.)
pytest my_first_test.py --demo --demo-sleep=1.2\n
Passing additional data to tests: If you want to pass additional data from the command line to your tests, you can use --data=STRING
. Now inside your tests, you can use self.data
to access that.
To run pytest
with multiple processes, add -n=NUM
, -n NUM
, or -nNUM
on the command line, where NUM
is the number of CPUs you want to use.
pytest -n=8\npytest -n 8\npytest -n8\n
How to retry failing tests automatically: You can use pytest --reruns=NUM
to retry failing tests that many times. Add --reruns-delay=SECONDS
to wait that many seconds between retries. Example:
pytest --reruns=1 --reruns-delay=1\n
Debugging tests: \ud83d\udd35 You can use the following calls in your scripts to help you debug issues:
import time; time.sleep(5) # Makes the test wait and do nothing for 5 seconds.\nimport pdb; pdb.set_trace() # Debug Mode. n: next, c: continue, s: step, u: up, d: down.\nimport pytest; pytest.set_trace() # Debug Mode. n: next, c: continue, s: step, u: up, d: down.\n
\ud83d\udd35 To pause an active test that throws an exception or error, (and keep the browser window open while Debug Mode begins in the console), add --pdb
as a pytest
option:
pytest test_fail.py --pdb\n
\ud83d\udd35 To start tests in Debug Mode, add --trace
as a pytest
option:
pytest test_coffee_cart.py --trace\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
).
\ud83c\udf9b\ufe0f There are times when you'll want to combine various command-line options for added effect. For instance, the multi-process option, -n8
, can be customized by adding: --dist=loadscope
or --dist=loadfile
to it. There's more info on that here: pytest-xdist:
-n8 --dist=loadscope
: Tests are grouped by module for test functions and by class for test methods. Groups are distributed to available workers as whole units. This guarantees that all tests in a group run in the same process. This can be useful if you have expensive module-level or class-level fixtures. Grouping by class takes priority over grouping by module.
-n8 --dist=loadfile
: Tests are grouped by their containing file. Groups are distributed to available workers as whole units. This guarantees that all tests in a file run in the same worker.
-n8 --dist=loadgroup
(click to expand) xdist_group
mark. Groups are distributed to available workers as whole units. This guarantees that all tests with the same xdist_group
name run in the same worker.@pytest.mark.xdist_group(name=\"group1\")\ndef test_1():\n pass\n\nclass Test:\n @pytest.mark.xdist_group(\"group1\")\n def test_2():\n pass\n
This makes test_1
and Test::test_2
run in the same worker. Tests without the xdist_group
mark are distributed normally.
\ud83c\udf9b\ufe0f You might also want to combine multiple options at once. For example:
pytest --headless -n8 --dashboard --html=report.html -v --rs --crumbs\n
The above not only runs tests in parallel processes, but it also tells tests in the same process to share the same browser session, runs the tests in headless mode, displays the full name of each test on a separate line, creates a realtime dashboard of the test results, and creates a full report after all tests complete.
The SeleniumBase Dashboard:\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python 3's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py --dashboard --rs --headless\n
Pytest Reports: \ud83d\udd35 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\ud83d\udd35 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\ud83d\udd35 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest html reports in Jenkins, you may need to configure Jenkins settings for the html to render correctly. This is due to Jenkins CSP changes.
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
Nosetest Reports: The --report
option gives you a fancy report after your test suite completes.
nosetests test_suite.py --report\n
(NOTE: You can add --show_report
to immediately display Nosetest reports after the test suite completes. Only use --show_report
when running tests locally because it pauses the test run.)
You can specify a Language Locale Code to customize web pages on supported websites. With SeleniumBase, you can change the web browser's Locale on the command line by doing this:
pytest --locale=CODE # Example: --locale=ru\n
Visit \ud83d\uddfe Locales for a full list of codes.
Changing the default driver version:\ud83d\udd35 By default, SeleniumBase will make sure that the major driver version matches the major browser version for Chromium tests. (Eg. If Chrome 117.X
is installed and you have chromedriver 117.X
, then nothing happens, but if you had chromedriver 116.X
instead, then SeleniumBase would download chromedriver 117.X
to match the browser version.)
\ud83c\udf9b\ufe0f To change this default behavior, you can use:
pytest --driver-version=VER\n
The VER
in --driver-version=VER
can be: * A major driver version. Eg. 117
. (milestone) * An exact driver version. Eg. 117.0.5938.92
. * \"browser\"
(exact match on browser version) * \"keep\"
(keep using the driver you already have) * \"latest\"
/ \"stable\"
(latest stable version) * \"previous\"
/ \"latest-1\"
(latest minus one) * \"beta\"
(latest beta version) * \"dev\"
(latest dev version) * \"canary\"
(latest canary version) * \"mlatest\"
(latest version for the milestone)
Note that different options could lead to the same result. (Eg. If you have the latest version of a browser for a milestone, then \"browser\"
and \"mlatest\"
should give you the same driver if the latest driver version for that milestone matches the browser version.)
\ud83c\udf9b\ufe0f An easy way to override seleniumbase/config/settings.py is by using a custom settings file. Here's the command-line option to add to tests: (See examples/custom_settings.py)
pytest --settings-file=custom_settings.py\n
(Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
Running tests on a remote Selenium Grid:\ud83c\udf10 SeleniumBase lets you run tests on remote Selenium Grids such as BrowserStack's Selenium Grid, Sauce Labs's Selenium Grid, other Grids, and even your own Grid:
\ud83c\udf10 For setting browser desired capabilities while running Selenium remotely, see the ReadMe located here: https://github.com/seleniumbase/SeleniumBase/tree/master/examples/capabilities
Here's how to connect to a BrowserStack Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@hub.browserstack.com --port=80\n
Here's how to connect to a Sauce Labs Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https\n
Here's how to connect to a CrossBrowserTesting Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@hub.crossbrowsertesting.com --port=80\n
\ud83c\udf10 Or you can create your own Selenium Grid for test distribution. (See this ReadMe for details)
\ud83c\udf10 To use a server on the https
protocol, add --protocol=https
: (Now automatic if the port is 443.)
pytest test_demo_site.py --protocol=https --server=IP_ADDRESS --port=PORT\n
Using a Proxy Server: \ud83c\udf10 If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add --proxy=IP_ADDRESS:PORT
as an argument on the command line.
pytest proxy_test.py --proxy=IP_ADDRESS:PORT\n
\ud83c\udf10 If the proxy server that you wish to use requires authentication, you can do the following (Chromium only):
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n
\ud83c\udf10 SeleniumBase also supports SOCKS4 and SOCKS5 proxies:
pytest proxy_test.py --proxy=\"socks4://IP_ADDRESS:PORT\"\n\npytest proxy_test.py --proxy=\"socks5://IP_ADDRESS:PORT\"\n
To make things easier, you can add your frequently-used proxies to PROXY_LIST in proxy_list.py, and then use --proxy=KEY_FROM_PROXY_LIST
to use the IP_ADDRESS:PORT of that key.
pytest proxy_test.py --proxy=proxy1\n
Changing the User-Agent: \ud83d\udd24 If you wish to change the User-Agent for your browser tests (Chrome and Firefox only), you can add --agent=\"USER-AGENT-STRING\"
as an argument on the command line.
pytest user_agent_test.py --agent=\"Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU\"\n
Mobile Device Testing: \ud83d\udcf1 Use --mobile
to quickly run your tests using Chrome's mobile device emulator with default values for device metrics (CSS Width, CSS Height, Pixel-Ratio) and a default value set for the user agent. To configure the mobile device metrics, use --metrics=\"CSS_Width,CSS_Height,Pixel_Ratio\"
to set those values. You'll also be able to set the user agent with --agent=\"USER-AGENT-STRING\"
(a default user agent will be used if not specified). To find real values for device metrics, see this GitHub Gist. For a list of available user agent strings, check out this page.
# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"411,731,3\"\n\n# Run mobile tests specifying the user agent\npytest test_swag_labs.py --mobile --agent=\"Mozilla/5.0 (Linux; Android 9; Pixel 3 XL)\"\n
"}, {"location": "help_docs/demo_mode/", "title": "\ud83c\udfa6 Demo Mode", "text": ""}, {"location": "help_docs/demo_mode/#demo-mode", "title": "Demo Mode \ud83c\udfa6", "text": "\ud83d\udd35 Demo Mode helps you see what a test is doing.
\ud83c\udfc7\ud83d\udca8 \ud83d\udc40 If a test runs too fast for your eyes, use Demo Mode to slow it down, highlight actions, and display assertions. Example usage:
cd examples/\npytest test_coffee_cart.py --demo\n
(--demo
mode slows down tests and highlights actions)
Another example:
pytest my_first_test.py --demo\n
Here's how to run test_swag_labs.py from examples/ in Demo Mode:
pytest test_swag_labs.py --demo\n
Here's an example that only uses the highlight()
method for highlighting browser actions:
(test_error_page.py from examples/)
pytest test_error_page.py\n
Here's an example of a mobile test in Demo Mode:
"}, {"location": "help_docs/desired_capabilities/", "title": "\ud83d\udcc3 Desired Capabilities", "text": ""}, {"location": "help_docs/desired_capabilities/#using-desired-capabilities", "title": "Using Desired Capabilities", "text": "You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as BrowserStack or Sauce Labs).
Sample run commands may look like this when run from the SeleniumBase/examples/ folder: (The browser is now specified in the capabilities file.)
pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@hub.browserstack.com --port=80 --cap_file=capabilities/sample_cap_file_BS.py\n
pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https --cap_file=capabilities/sample_cap_file_SL.py\n
(Parameters: --browser=remote
, --server=SERVER
, --port=PORT
, and --cap_file=CAP_FILE.py
)
Here's an example desired capabilities file for BrowserStack using the newer SDK format in a .yml
/ .yaml
file:
platforms:\n - browserName: safari\n osVersion: 17\n deviceName: iPhone 15 Pro Max\nbuildIdentifier: ${BUILD_NUMBER}\nparallelsPerPlatform: 1\nprojectName: My Project\nbrowserstackLocal: true\ndebug: true\nnetworkLogs: true\n
Here's an example desired capabilities file for BrowserStack using the legacy JSONWP format in a .py
file:
desired_cap = {\n \"browser\": \"Chrome\",\n \"os\": \"Windows\",\n \"os_version\": \"11\",\n \"browser_version\": \"latest\",\n \"browserstack.console\": \"info\",\n \"browserstack.debug\": \"true\",\n \"browserstack.networkLogs\": \"true\",\n \"browserstack.local\": \"true\",\n}\n
Here's an example desired capabilities file for Sauce Labs:
capabilities = {\n \"browserName\": \"chrome\",\n \"browserVersion\": \"latest\",\n \"platformName\": \"macOS 10.14\",\n \"sauce:options\": {},\n}\n
(Note that the browser is now being specified in the capabilities file, rather than with --BROWSER
when using a remote Selenium Grid. If using a local Selenium Grid, specify the browser, eg: --firefox
.)
SeleniumBase has a desired capabilities parser that can capture all lines from the specified file in the following formats:
'KEY': 'VALUE'\n'KEY': True\n'KEY': False\ncaps['KEY'] = \"VALUE\"\ncaps['KEY'] = True\ncaps['KEY'] = False\n
(Each pair must be on a separate line. You can interchange single and double quotes.)
You can also swap --browser=remote
with an actual browser, eg --browser=chrome
, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using --cap_file=FILE.py
. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser.
You'll need default SeleniumBase capabilities for: * Using a proxy server (not the same as a Selenium Grid server) * Downloading files to a desired folder * Disabling some warnings on Chrome * Overriding a website's Content Security Policy on Chrome * Other possible reasons
You can also set browser desired capabilities from a command-line string. Eg:
pytest test_swag_labs.py --cap-string='{\"browserName\":\"chrome\",\"name\":\"test1\"}' --server=\"127.0.0.1\" --browser=remote\n
(Enclose cap-string in single quotes. Enclose parameter keys in double quotes.)
If you pass \"*\"
into the \"name\"
field of --cap-string
, the name will become the test identifier. Eg:
pytest my_first_test.py --cap-string='{\"browserName\":\"chrome\",\"name\":\"*\"}' --server=\"127.0.0.1\" --browser=chrome\n
Example name: \"my_first_test.MyTestClass.test_basics\"
If using a local Selenium Grid with SeleniumBase, start up the Grid Hub and nodes first:
sbase grid-hub start\nsbase grid-node start\n
(The Selenium Server JAR file will be automatically downloaded for first-time Grid users. You'll also need Java installed to start up the Grid.)
"}, {"location": "help_docs/features_list/", "title": "\ud83c\udff0 List of Features", "text": ""}, {"location": "help_docs/features_list/#seleniumbase-features", "title": "SeleniumBase Features: \ud83c\udff0", "text": "--headless
)-n NUM_THREADS
)--reuse-session
/--rs
)--mobile
)--proxy=IP_ADDRESS:PORT
)--proxy-pac-url=URL.pac
)--proxy=USER:PASS@HOST:PORT
)--proxy-pac-url=USER:PASS@URL.pac
)--agent=USER_AGENT_STRING
)--user-data-dir=DIR
)--undetected
/--uc
)--wire
)--extension-zip=ZIP
)--extension-dir=DIR
)seleniumbase
or sbase
to use.)self.driver
)self.execute_script()
)::shadow
to CSS fragments.)(Watch the original tutorial on YouTube)
"}, {"location": "help_docs/handling_iframes/", "title": "\ud83d\uddbc\ufe0f How to handle iframes", "text": ""}, {"location": "help_docs/handling_iframes/#how-to-handle-iframes", "title": "How to handle iframes", "text": "\ud83d\uddbc\ufe0f iframes follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
self.switch_to_frame(\"iframe\")\n# ... Now perform actions inside the iframe\nself.switch_to_parent_frame() # Exit the current iframe\n
To exit from multiple iframes, use self.switch_to_default_content()
. (If inside a single iframe, this has the same effect as self.switch_to_parent_frame()
.)
self.switch_to_frame('iframe[name=\"frame1\"]')\nself.switch_to_frame('iframe[name=\"frame2\"]')\n# ... Now perform actions inside the inner iframe\nself.switch_to_default_content() # Back to the main page\n
\ud83d\uddbc\ufe0f You can also use a context manager to act inside iframes:
with self.frame_switch(\"iframe\"):\n # ... Now perform actions while inside the code block\n# You have left the iframe\n
This also works with nested iframes:
with self.frame_switch('iframe[name=\"frame1\"]'):\n with self.frame_switch('iframe[name=\"frame2\"]'):\n # ... Now perform actions while inside the code block\n # You are now back inside the first iframe\n# You have left all the iframes\n
\ud83d\uddbc\ufe0f In special cases, you may want to set the page to the content of an iframe:
self.set_content_to_frame(\"iframe\")\n
To back out of one call of that, use:
self.set_content_to_parent()\n
To back out of all nested calls of that, use:
self.set_content_to_default()\n
\ud83d\uddbc\ufe0f See SeleniumBase/examples/iframe_tests.py for tests that use all available iframe commands.
"}, {"location": "help_docs/happy_customers/", "title": "\ud83d\udccb Case Studies", "text": ""}, {"location": "help_docs/happy_customers/#businesses-who-have-used-seleniumbase", "title": "Businesses who have used SeleniumBase", "text": "
HubSpot:
In addition to using SeleniumBase for testing the UI of their content management system, HubSpot used SeleniumBase to automate the migration of website pages from their old CMS to their new one, which saved them over one million USD and a significant amount of time.
Learn how HubSpot uses SeleniumBase for website testing by reading: Automated Testing with Selenium
For more reading about automation at HubSpot, see: The Classic \"QA Team\" is Obsolete
"}, {"location": "help_docs/happy_customers/#how-is-this-list-generated", "title": "How is this list generated?", "text": "Most of these rows come from LinkedIn search results of profile descriptions, where employees mentioned that they have used SeleniumBase at their company. These details may also be found in other public networks and social media sites, such as GitHub (where organizations could have public repos that use SeleniumBase).
"}, {"location": "help_docs/hidden_files_info/", "title": "\ud83d\udc65 macOS Hidden Files", "text": ""}, {"location": "help_docs/hidden_files_info/#showing-hidden-files-on-macos", "title": "Showing hidden files on macOS", "text": "Depending on your macOS settings, some files may be hidden from view in your Finder window, such as .gitignore
.
Press the \u201cCommand\u201d + \u201cShift\u201d + \u201c.\u201d (period) keys at the same time.
(The hidden files will show up as translucent in the folder. If you want to obscure the files again, press the same \u201cCommand\u201d + \u201cShift\u201d + \u201c.\u201d (period) combination.)
defaults write com.apple.finder AppleShowAllFiles -bool true\n
More info on that can be found here:
\ud83d\udc41\ufe0f\ud83d\udd0e The primary SeleniumBase syntax format works by extending pytest as a direct plugin. SeleniumBase automatically spins up web browsers for tests (using Selenium WebDriver), and then gives those tests access to the SeleniumBase libraries through the BaseCase class. Tests are also given access to SeleniumBase command-line options and SeleniumBase methods, which provide additional functionality.
\ud83d\udc41\ufe0f\ud83d\udd0e pytest
uses a feature called test discovery to automatically find and run Python methods that start with test_
when those methods are located in Python files that start with test_
or end with _test.py
.
\ud83d\udc41\ufe0f\ud83d\udd0e The primary SeleniumBase syntax format starts by importing BaseCase
:
from seleniumbase import BaseCase\n
\ud83d\udc41\ufe0f\ud83d\udd0e This next line activates pytest
when a file is called directly with python
by accident:
BaseCase.main(__name__, __file__)\n
\ud83d\udc41\ufe0f\ud83d\udd0e Classes can inherit BaseCase
to gain SeleniumBase functionality:
class MyTestClass(BaseCase):\n
\ud83d\udc41\ufe0f\ud83d\udd0e Test methods inside BaseCase
classes become SeleniumBase tests: (These tests automatically launch a web browser before starting, and quit the web browser after ending. Default settings can be changed via command-line options.)
class MyTestClass(BaseCase):\n def test_abc(self):\n # ...\n
\ud83d\udc41\ufe0f\ud83d\udd0e SeleniumBase APIs can be called from tests via self
:
class MyTestClass(BaseCase):\n def test_abc(self):\n self.open(\"https://example.com\")\n
\ud83d\udc41\ufe0f\ud83d\udd0e Here's what a full test might look like:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass TestSimpleLogin(BaseCase):\n def test_simple_login(self):\n self.open(\"https://seleniumbase.io/simple/login\")\n self.type(\"#username\", \"demo_user\")\n self.type(\"#password\", \"secret_pass\")\n self.click('a:contains(\"Sign in\")')\n self.assert_exact_text(\"Welcome!\", \"h1\")\n self.assert_element(\"img#image1\")\n self.highlight(\"#image1\")\n self.click_link(\"Sign out\")\n self.assert_text(\"signed out\", \"#top_message\")\n
(See the example, test_simple_login.py, for reference.)
\ud83d\udc41\ufe0f\ud83d\udd0e Here are some examples of running tests with pytest
:
pytest test_mfa_login.py\npytest --headless -n8 --dashboard --html=report.html -v --rs --crumbs\npytest -m marker2\npytest -k agent\npytest offline_examples/\n
\ud83d\udc41\ufe0f\ud83d\udd0e Here's a SeleniumBase syntax format that uses the raw driver
. Unlike the format mentioned earlier, it can be run with python
instead of pytest
. The driver
includes original driver
methods and new ones added by SeleniumBase:
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.get(\"https://seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
(See the example, raw_login_driver.py, for reference.)
\ud83d\udc41\ufe0f\ud83d\udd0e Note that regular SeleniumBase formats (ones that use BaseCase
, the SB
context manager, or the sb
pytest
fixture) have more methods than the improved driver
format. The regular formats also have more features. Some features, (such as the SeleniumBase dashboard), require a pytest
format.
SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (up to a timeout limit). This means you no longer need random time.sleep()
statements in your scripts.
There are three layers of protection that provide reliability for tests using SeleniumBase:
(1): Selenium's default pageLoadStrategy
is normal
: This strategy causes Selenium to wait for the full page to load, with HTML content and sub-resources downloaded and parsed.
(2): SeleniumBase includes methods such as wait_for_ready_state_complete()
, which run inside other SeleniumBase methods to ensure that it's safe to proceed with the next command.
(3): SeleniumBase methods automatically wait for elements to be visible and interactable before interacting with those elements.
If you want to speed up your tests and you think the third level of protection is enough by itself, you can use command-line options to remove the first, the second, or both of those first two levels of protection:
--pls=none
--> Set pageLoadStrategy
to \"none\"
: This strategy causes Selenium to return immediately after the initial HTML content is fully received by the browser.
--sjw
--> Skip JS Waits, such as wait_for_ready_state_complete()
.
\ud83d\udd75\ufe0f HTML Inspector provides useful info about a web page.
\ud83d\udd75\ufe0f (Based on: github.com/philipwalton/html-inspector)
\ud83d\udd75\ufe0f Example: examples/test_inspect_html.py (Chromium-only)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass HtmlInspectorTests(BaseCase):\n def test_html_inspector(self):\n self.open(\"https://xkcd.com/1144/\")\n self.inspect_html()\n
pytest test_inspect_html.py\n============== test session starts ==============\n\n* HTML Inspection Results: https://xkcd.com/1144/\n\u26a0\ufe0f 'property' is not a valid attribute of the <meta> element.\n\u26a0\ufe0f Do not use <div> or <span> elements without any attributes.\n\u26a0\ufe0f 'srcset' is not a valid attribute of the <img> element.\n\u26a0\ufe0f The 'border' attribute is no longer valid on the <img> element.\n\u26a0\ufe0f The <center> element is obsolete.\n\u26a0\ufe0f The id 'comicLinks' appears more than once in the document.\n* (See the Console output for details!)\n
"}, {"location": "help_docs/install/", "title": "\ud83c\udfc4 Install SeleniumBase", "text": ""}, {"location": "help_docs/install/#seleniumbase-installation", "title": "SeleniumBase Installation", "text": "If installing seleniumbase
directly from PyPI, (the Python Package Index), use: pip install seleniumbase\n
To upgrade an existing seleniumbase
install from PyPI: pip install -U seleniumbase\n
If installing seleniumbase
from a Git clone, use: git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install .\n
For a development mode install in editable mode, use: git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install -e .\n
To upgrade an existing seleniumbase
install from GitHub: git pull # To pull the latest version\npip install -e . # Or \"pip install .\"\n
If installing seleniumbase
from a GitHub branch, use: pip install git+https://github.com/seleniumbase/SeleniumBase.git@master#egg=seleniumbase\n
pip install
can be customized: --upgrade
OR -U
to upgrade SeleniumBase.)--force-reinstall
to upgrade indirect libraries.)pip3
if multiple versions of Python are present.)(If you're not using a virtual environment, you may need to add --user
to your pip
command if you're seeing errors during installation.)
Git
, Python
, and pip
", "text": ""}, {"location": "help_docs/install_python_pip_git/#git", "title": "Git", "text": "You can download Git from here.
(A Git GUI tool like SourceTree or GitHub Desktop can help you with Git commands.)
(You can also download SeleniumBase from GitHub without using git-related commands.)
"}, {"location": "help_docs/install_python_pip_git/#python", "title": "Python", "text": "You can download Python from https://www.python.org/downloads/ if it's not already preinstalled on your machine.
"}, {"location": "help_docs/install_python_pip_git/#pip", "title": "pip", "text": "pip
already comes with Python! (It lets you install packages, such as seleniumbase
.)
\u26a0\ufe0f If something went wrong with your pip
installation, try this:
python -m ensurepip --default-pip\n
If your existing version of pip is old, upgrade to the latest version:
python -m pip install --upgrade pip setuptools\n
On CentOS 7 and some versions of Linux, you may need to install pip with yum
:
yum -y update\nyum -y install python-pip\n
If you're having any trouble getting pip, you can GET PIP HERE.
When done, make sure the location of pip is on your path, which is $PATH
for macOS/Linux. (On Windows, it's the System Variables Path
within System Environment Variables.)
You can also get pip (or fix pip) by using:
curl https://bootstrap.pypa.io/get-pip.py | python\n
Keep Pip and Setuptools up-to-date:
python -m pip install -U pip setuptools\n
--user
to the command if you're not inside a Python virtual environment, or use \"sudo\" on a UNIX-based OS if you're getting errors during installation.)\ud83c\udfa8 The following SeleniumBase solutions utilize this feature:
\ud83c\udfa6 (Demo Mode)
\ud83d\ude8e (Website Tours)
\ud83c\udf9e\ufe0f (Presentation Maker)
\ud83d\udcca (Chart Maker / Dashboard)
\ud83d\udec2 (Dialog Boxes / MasterQA)
\ud83d\uddfa\ufe0f Here's an example of loading a website-tour library into the browser for a Google Maps tour:
\ud83d\uddfa\ufe0f This example is from maps_introjs_tour.py. (The --interval=1
makes the tour go automatically to the next step after 1 second.)
cd examples/tour_examples\npytest maps_introjs_tour.py --interval=1\n
\ud83d\udd79\ufe0f SeleniumBase includes powerful JS code generators for converting Python into JavaScript for using the supported JS packages. A few lines of Python in your tests might generate hundreds of lines of JavaScript.
\ud83d\uddfa\ufe0f Here is some tour code in Python from maps_introjs_tour.py that expands into a lot of JavaScript.
self.open(\"https://www.google.com/maps/@42.3591234,-71.0915634,15z\")\nself.create_tour(theme=\"introjs\")\nself.add_tour_step(\"Welcome to Google Maps!\", title=\"SeleniumBase Tours\")\nself.add_tour_step(\"Enter Location\", \"#searchboxinput\", title=\"Search Box\")\nself.add_tour_step(\"See it\", \"#searchbox-searchbutton\", alignment=\"bottom\")\nself.add_tour_step(\"Thanks for using Tours!\", title=\"End of Guided Tour\")\nself.export_tour(filename=\"maps_introjs_tour.js\")\nself.play_tour()\n
\ud83d\udd79\ufe0f For existing features, SeleniumBase already takes care of loading all the necessary JS and CSS files into the web browser. To load other packages, here are a few useful methods that you should know about:
self.add_js_link(js_link)\n
\ud83d\udd79\ufe0f This example loads the IntroJS JavaScript library:
self.add_js_link(\"https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.9.3/intro.min.js\")\n
\ud83d\udd79\ufe0f You can load any JS package this way as long as you know the URL. \ud83d\udd79\ufe0f If you're wondering how SeleniumBase does this, here's the full Python code from js_utils.py, which uses WebDriver's execute_script()
method for making JS calls after escaping quotes with backslashes as needed:
def add_js_link(driver, js_link):\n script_to_add_js = (\n \"\"\"function injectJS(link) {\n var body = document.getElementsByTagName(\"body\")[0];\n var script = document.createElement(\"script\");\n script.src = link;\n script.defer;\n script.type=\"text/javascript\";\n script.crossorigin = \"anonymous\";\n script.onload = function() { null };\n body.appendChild(script);\n }\n injectJS(\"%s\");\"\"\")\n js_link = escape_quotes_if_needed(js_link)\n driver.execute_script(script_to_add_js % js_link)\n
\ud83d\udd79\ufe0f Now that you've loaded JavaScript into the browser, you may also want to load some CSS to go along with it:
self.add_css_link(css_link)\n
\ud83d\udd79\ufe0f Here's code that loads the IntroJS CSS:
self.add_css_link(\"https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.9.3/introjs.css\")\n
\ud83d\udd79\ufe0f And here's the Python WebDriver code that makes this possible:
def add_css_link(driver, css_link):\n script_to_add_css = (\n \"\"\"function injectCSS(css) {\n var head = document.getElementsByTagName(\"head\")[0];\n var link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.type = \"text/css\";\n link.href = css;\n link.crossorigin = \"anonymous\";\n head.appendChild(link);\n }\n injectCSS(\"%s\");\"\"\")\n css_link = escape_quotes_if_needed(css_link)\n driver.execute_script(script_to_add_css % css_link)\n
\ud83d\udd79\ufe0f Website tours are just one of the many uses of the JS Package Manager. \ud83d\udec2 The following example shows the JqueryConfirm package loaded into a website for creating fancy dialog boxes:
\u2195\ufe0f (Example: dialog_box_tour.py) \u2195\ufe0f Here's how to run that example:cd examples/dialog_boxes\npytest test_dialog_boxes.py\n
(Example from the Dialog Boxes ReadMe)
\ud83d\udd79\ufe0f Since packages are loaded directly from a CDN link, you won't need other package managers like NPM, Bower, or Yarn to get the packages that you need into the websites that you want. To learn more about SeleniumBase, check out the Docs Site:All the code is on GitHub:
"}, {"location": "help_docs/locale_codes/", "title": "\ud83d\uddfe Locale Codes", "text": ""}, {"location": "help_docs/locale_codes/#language-locale-codes", "title": "Language Locale Codes", "text": "
You can specify a Language Locale Code to customize web pages on supported websites. With SeleniumBase, you can change the web browser's Locale on the command line by doing this:
pytest --locale=CODE # Example: --locale=ru\n
List of Language Locale Codes: LanguageCode Afrikaansaf
Amharicam
Arabicar
Arabic (Egypt)ar_eg
Arabic (Saudi Arabia)ar_sa
Basqueeu
Belarusianbe
Bengalibn
Bulgarianbg
Catalanca
Chinesezh
Chinese (China Mainland)zh_cn
Chinese (Hong Kong)zh_hk
Chinese (Taiwan)zh_tw
Croatianhr
Czechcs
Danishda
Dutchnl
Englishen
English (United States)en_us
English (Australia)en_au
English (Canada)en_ca
English (United Kingdom)en_gb
English (Ireland)en_ie
English (India)en_in
English (Singapore)en_sg
English (South Africa)en_za
Estonianet
Farsifa
Filipinofil
Finnishfi
Frenchfr
French (Canada)fr_ca
French (Switzerland)fr_ch
Galiciangl
Germande
German (Austria)de_at
Greekel
Gujaratigu
Hebrewhe
Hindihi
Hungarianhu
Icelandicis
Indonesianid
Italianit
Japaneseja
Kannadakn
Koreanko
Laolo
Latvianlv
Lingalaln
Lithuanianlt
Malayms
Malayalamml
Marathimr
Norwegianno
Polishpl
Portuguesept
Portuguese (Brazil)pt_br
Portuguese (Portugal)pt_pt
Romanianro
Russianru
Serbiansr
Slovaksk
Sloveniansl
Spanishes
Spanish (Latin America)es_419
Spanish (Argentina)es_ar
Spanish (Chile)es_cl
Spanish (Colombia)es_co
Spanish (Costa Rica)es_cr
Spanish (Dominican Rep.)es_do
Spanish (Ecuador)es_ec
Spanish (El Salvador)es_sv
Spanish (Guatemala)es_gt
Spanish (Honduras)es_hn
Spanish (Mexico)es_mx
Spanish (Nicaragua)es_ni
Spanish (Panama)es_pa
Spanish (Peru)es_pe
Spanish (Puerto Rico)es_pr
Spanish (Paraguay)es_py
Spanish (United States)es_us
Spanish (Uruguay)es_uy
Spanish (Venezuela)es_ve
Swahilisw
Swedishsv
Swiss Germangsw
Tagalogtl
Tamilta
Telugute
Thaith
Turkishtr
Ukrainianuk
Urduur
Vietnamesevi
Zuluzu
"}, {"location": "help_docs/method_summary/", "title": "\ud83d\udcd8 API Reference", "text": ""}, {"location": "help_docs/method_summary/#seleniumbase-methods-api-reference", "title": "SeleniumBase Methods (API Reference)\ud83d\udd35 Examples", "text": "Here's a list of SeleniumBase method definitions, which are defined in base_case.py
For backwards compatibility, older versions of method names have remained to keep older scripts working. (E.g: wait_for_element_visible was shortened to wait_for_element and then to find_element.)
self.open(url)\n# Duplicates: self.open_url(url), self.visit(url), visit_url(url),\n# self.goto(url), self.go_to(url)\n\nself.get(url)\n# If the url parameter is a URL: Perform self.open(url)\n# Otherwise: return self.get_element(URL_AS_A_SELECTOR)\n\nself.click(selector, by=\"css selector\", timeout=None, delay=0, scroll=True)\n\nself.slow_click(selector, by=\"css selector\", timeout=None)\n\nself.double_click(selector, by=\"css selector\", timeout=None)\n\nself.context_click(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.right_click(selector, by=\"css selector\", timeout=None)\n\nself.click_chain(selectors_list, by=\"css selector\", timeout=None, spacing=0)\n\nself.type(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.update_text(selector, text, by=\"css selector\", timeout=None)\n# self.input(selector, text, by=\"css selector\", timeout=None)\n# self.fill(selector, text, by=\"css selector\", timeout=None)\n# self.write(selector, text, by=\"css selector\", timeout=None)\n\nself.send_keys(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.add_text(selector, text, by=\"css selector\", timeout=None)\n\nself.press_keys(selector, text, by=\"css selector\", timeout=None)\n\nself.submit(selector, by=\"css selector\")\n\nself.clear(selector, by=\"css selector\", timeout=None)\n\nself.focus(selector, by=\"css selector\", timeout=None)\n\nself.refresh()\n# Duplicates: self.refresh_page(), self.reload_page(), self.reload()\n\nself.get_current_url()\n\nself.get_origin()\n\nself.get_page_source()\n\nself.get_title()\n# Duplicates: self.get_page_title()\n\nself.get_user_agent()\n\nself.get_locale_code()\n\nself.go_back()\n\nself.go_forward()\n\nself.open_start_page()\n\nself.open_if_not_url(url)\n\nself.is_element_present(selector, by=\"css selector\")\n\nself.is_element_visible(selector, by=\"css selector\")\n\nself.is_element_clickable(selector, by=\"css selector\")\n\nself.is_element_enabled(selector, by=\"css selector\")\n\nself.is_text_visible(text, selector=\"html\", by=\"css selector\")\n\nself.is_exact_text_visible(text, selector=\"html\", by=\"css selector\")\n\nself.is_non_empty_text_visible(selector=\"html\", by=\"css selector\")\n\nself.is_attribute_present(selector, attribute, value=None, by=\"css selector\")\n\nself.is_link_text_visible(link_text)\n\nself.is_partial_link_text_visible(partial_link_text)\n\nself.is_link_text_present(link_text)\n\nself.is_partial_link_text_present(link_text)\n\nself.get_link_attribute(link_text, attribute, hard_fail=True)\n# Duplicates\n# self.get_link_text_attribute(link_text, attribute, hard_fail=True)\n\nself.get_partial_link_text_attribute(link_text, attribute, hard_fail=True)\n\nself.click_link(link_text, timeout=None)\n# Duplicates\n# self.click_link_text(link_text, timeout=None)\n\nself.click_partial_link(partial_link_text, timeout=None)\n# Duplicates\n# self.click_partial_link_text(partial_link_text, timeout=None)\n\nself.get_text(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.get_attribute(selector, attribute, by=\"css selector\", timeout=None, hard_fail=True)\n\nself.set_attribute(selector, attribute, value, by=\"css selector\", timeout=None, scroll=False)\n\nself.set_attributes(selector, attribute, value, by=\"css selector\")\n# Duplicates\n# self.set_attribute_all(selector, attribute, value, by=\"css selector\")\n\nself.remove_attribute(selector, attribute, by=\"css selector\", timeout=None)\n\nself.remove_attributes(selector, attribute, by=\"css selector\")\n\nself.get_property(selector, property, by=\"css selector\", timeout=None)\n\nself.get_text_content(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.get_property_value(selector, property, by=\"css selector\", timeout=None)\n\nself.get_image_url(selector, by=\"css selector\", timeout=None)\n\nself.find_elements(selector, by=\"css selector\", limit=0)\n\nself.find_visible_elements(selector, by=\"css selector\", limit=0)\n\nself.click_visible_elements(selector, by=\"css selector\", limit=0, timeout=None)\n\nself.click_nth_visible_element(selector, number, by=\"css selector\", timeout=None)\n\nself.click_if_visible(selector, by=\"css selector\", timeout=0)\n\nself.click_active_element()\n\nself.click_with_offset(\n selector, x, y, by=\"css selector\", mark=None, timeout=None, center=None)\n\nself.double_click_with_offset(\n selector, x, y, by=\"css selector\", mark=None, timeout=None, center=None)\n\nself.is_checked(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.is_selected(selector, by=\"css selector\", timeout=None)\n\nself.check_if_unchecked(selector, by=\"css selector\")\n# Duplicates\n# self.select_if_unselected(selector, by=\"css selector\")\n\nself.uncheck_if_checked(selector, by=\"css selector\")\n# Duplicates\n# self.unselect_if_selected(selector, by=\"css selector\")\n\nself.is_element_in_an_iframe(selector, by=\"css selector\")\n\nself.switch_to_frame_of_element(selector, by=\"css selector\")\n\nself.hover(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.hover_on_element(selector, by=\"css selector\", timeout=None)\n# self.hover_over_element(selector, by=\"css selector\", timeout=None)\n\nself.hover_and_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None, js_click=False)\n\nself.hover_and_js_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None)\n\nself.hover_and_double_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None)\n\nself.drag_and_drop(\n drag_selector, drop_selector,\n drag_by=\"css selector\", drop_by=\"css selector\",\n timeout=None, jquery=False)\n\nself.drag_and_drop_with_offset(\n selector, x, y, by=\"css selector\", timeout=None)\n\nself.select_option_by_text(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.select_option_by_index(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.select_option_by_value(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.get_select_options(\n dropdown_selector, attribute=\"text\", by=\"css selector\", timeout=None)\n\nself.load_html_string(html_string, new_page=True)\n\nself.set_content(html_string, new_page=False)\n\nself.load_html_file(html_file, new_page=True)\n\nself.open_html_file(html_file)\n\nself.execute_script(script, *args, **kwargs)\n\nself.execute_cdp_cmd(script, *args, **kwargs)\n\nself.execute_async_script(script, timeout=None)\n\nself.safe_execute_script(script, *args, **kwargs)\n\nself.get_gui_element_rect(selector, by=\"css selector\")\n\nself.get_gui_element_center(selector, by=\"css selector\")\n\nself.get_window_rect()\n\nself.get_window_size()\n\nself.get_window_position()\n\nself.set_window_rect(x, y, width, height)\n\nself.set_window_size(width, height)\n\nself.set_window_position(x, y)\n\nself.maximize_window()\n\nself.switch_to_frame(frame=\"iframe\", timeout=None)\n\nself.switch_to_default_content()\n\nself.switch_to_parent_frame()\n\nwith self.frame_switch(frame, timeout=None):\n # Indented Code Block for Context Manager (Must use \"with\")\n\nself.set_content_to_frame(frame, timeout=None)\n\nself.set_content_to_default(nested=False)\n# Duplicates: self.set_content_to_default_content(nested=False)\n\nself.set_content_to_parent()\n# Duplicates: self.set_content_to_parent_frame()\n\nself.open_new_window(switch_to=True)\n# Duplicates: self.open_new_tab(switch_to=True)\n\nself.switch_to_window(window, timeout=None)\n# Duplicates: self.switch_to_tab(tab, timeout=None)\n\nself.switch_to_default_window()\n# Duplicates: self.switch_to_default_tab()\n\nself.switch_to_newest_window()\n# Duplicates: self.switch_to_newest_tab()\n\nself.get_new_driver(\n browser=None,\n headless=None,\n locale_code=None,\n protocol=None,\n servername=None,\n port=None,\n proxy=None,\n proxy_bypass_list=None,\n proxy_pac_url=None,\n multi_proxy=None,\n agent=None,\n switch_to=True,\n cap_file=None,\n cap_string=None,\n recorder_ext=None,\n disable_js=None,\n disable_csp=None,\n enable_ws=None,\n enable_sync=None,\n use_auto_ext=None,\n undetectable=None,\n uc_cdp_events=None,\n uc_subprocess=None,\n log_cdp_events=None,\n no_sandbox=None,\n disable_gpu=None,\n headless2=None,\n incognito=None,\n guest_mode=None,\n dark_mode=None,\n devtools=None,\n remote_debug=None,\n enable_3d_apis=None,\n swiftshader=None,\n ad_block_on=None,\n host_resolver_rules=None,\n block_images=None,\n do_not_track=None,\n chromium_arg=None,\n firefox_arg=None,\n firefox_pref=None,\n user_data_dir=None,\n extension_zip=None,\n extension_dir=None,\n disable_features=None,\n binary_location=None,\n driver_version=None,\n page_load_strategy=None,\n use_wire=None,\n external_pdf=None,\n is_mobile=None,\n d_width=None,\n d_height=None,\n d_p_r=None,\n)\n\nself.switch_to_driver(driver)\n\nself.switch_to_default_driver()\n\nself.save_screenshot(name, folder=None, selector=None, by=\"css selector\")\n\nself.save_screenshot_to_logs(name=None, selector=None, by=\"css selector\")\n\nself.save_data_to_logs(data, file_name=None)\n\nself.append_data_to_logs(data, file_name=None)\n\nself.save_page_source(name, folder=None)\n\nself.save_cookies(name=\"cookies.txt\")\n\nself.load_cookies(name=\"cookies.txt\")\n\nself.delete_all_cookies()\n# Duplicates: self.clear_all_cookies()\n\nself.delete_saved_cookies(name=\"cookies.txt\")\n\nself.get_saved_cookies(name=\"cookies.txt\")\n\nself.get_cookie(name)\n\nself.get_cookies()\n\nself.add_cookie(cookie_dict)\n\nself.add_cookies(cookies)\n\nself.wait_for_ready_state_complete(timeout=None)\n\nself.wait_for_angularjs(timeout=None)\n\nself.sleep(seconds)\n# Duplicates: self.wait(seconds)\n\nself.install_addon(xpi_file)\n\nself.activate_jquery()\n\nself.activate_demo_mode()\n\nself.deactivate_demo_mode()\n\nself.activate_design_mode()\n\nself.deactivate_design_mode()\n\nself.activate_recorder()\n\nself.save_recorded_actions()\n\nself.bring_active_window_to_front()\n\nself.bring_to_front(selector, by=\"css selector\")\n\nself.highlight_click(selector, by=\"css selector\", loops=3, scroll=True, timeout=None)\n\nself.highlight_type(selector, text, by=\"css selector\", loops=3, scroll=True, timeout=None)\n# Duplicates\n# self.highlight_update_text(\n# selector, text, by=\"css selector\", loops=3, scroll=True, timeout=None)\n\nself.highlight_if_visible(selector, by=\"css selector\", loops=4, scroll=True)\n\nself.highlight(selector, by=\"css selector\", loops=4, scroll=True, timeout=None)\n\nself.highlight_elements(selector, by=\"css selector\", loops=4, scroll=True, limit=0)\n\nself.press_up_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_down_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_left_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_right_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.scroll_to(selector, by=\"css selector\", timeout=None)\n# Duplicates: self.scroll_to_element(selector, by=\"css selector\")\n\nself.slow_scroll_to(selector, by=\"css selector\", timeout=None)\n# Duplicates: self.slow_scroll_to_element(selector, by=\"css selector\")\n\nself.scroll_into_view(selector, by=\"css selector\", timeout=None)\n\nself.scroll_to_top()\n\nself.scroll_to_bottom()\n\nself.click_xpath(xpath)\n\nself.js_click(selector, by=\"css selector\", all_matches=False, timeout=None, scroll=True)\n\nself.js_click_if_present(selector, by=\"css selector\", timeout=0)\n\nself.js_click_if_visible(selector, by=\"css selector\", timeout=0)\n\nself.js_click_all(selector, by=\"css selector\", timeout=None)\n\nself.jquery_click(selector, by=\"css selector\", timeout=None)\n\nself.jquery_click_all(selector, by=\"css selector\", timeout=None)\n\nself.hide_element(selector, by=\"css selector\")\n\nself.hide_elements(selector, by=\"css selector\")\n\nself.show_element(selector, by=\"css selector\")\n\nself.show_elements(selector, by=\"css selector\")\n\nself.remove_element(selector, by=\"css selector\")\n\nself.remove_elements(selector, by=\"css selector\")\n\nself.ad_block()\n# Duplicates: self.block_ads()\n\nself.show_file_choosers()\n\nself.disable_beforeunload()\n\nself.get_domain_url(url)\n\nself.get_active_element_css()\n\nself.get_beautiful_soup(source=None)\n\nself.get_unique_links()\n\nself.get_link_status_code(link, allow_redirects=False, timeout=5, verify=False)\n\nself.assert_link_status_code_is_not_404(link)\n\nself.assert_no_404_errors(multithreaded=True, timeout=None)\n# Duplicates\n# self.assert_no_broken_links(multithreaded=True, timeout=None)\n\nself.print_unique_links_with_status_codes()\n\nself.get_pdf_text(\n pdf, page=None, maxpages=None, password=None,\n codec='utf-8', wrap=False, nav=False, override=False, caching=True)\n\nself.assert_pdf_text(\n pdf, text, page=None, maxpages=None, password=None,\n codec='utf-8', wrap=True, nav=False, override=False, caching=True)\n\nself.create_folder(folder)\n\nself.choose_file(selector, file_path, by=\"css selector\", timeout=None)\n\nself.save_element_as_image_file(selector, file_name, folder=None, overlay_text=\"\")\n\nself.download_file(file_url, destination_folder=None)\n\nself.save_file_as(file_url, new_file_name, destination_folder=None)\n\nself.save_data_as(data, file_name, destination_folder=None)\n\nself.append_data_to_file(data, file_name, destination_folder=None)\n\nself.get_file_data(file_name, folder=None)\n\nself.get_downloads_folder()\n\nself.get_browser_downloads_folder()\n\nself.get_downloaded_files(regex=None, browser=False)\n\nself.get_path_of_downloaded_file(file, browser=False)\n\nself.get_data_from_downloaded_file(file, timeout=None, browser=False)\n\nself.is_downloaded_file_present(file, browser=False)\n\nself.is_downloaded_file_regex_present(regex, browser=False)\n\nself.delete_downloaded_file_if_present(file, browser=False)\n# Duplicates: self.delete_downloaded_file(file, browser=False)\n\nself.assert_downloaded_file(file, timeout=None, browser=False)\n\nself.assert_downloaded_file_regex(regex, timeout=None, browser=False)\n\nself.assert_data_in_downloaded_file(data, file, timeout=None, browser=False)\n\nself.assert_true(expr, msg=None)\n\nself.assert_false(expr, msg=None)\n\nself.assert_equal(first, second, msg=None)\n\nself.assert_not_equal(first, second, msg=None)\n\nself.assert_in(first, second, msg=None)\n\nself.assert_not_in(first, second, msg=None)\n\nself.assert_raises(*args, **kwargs)\n\nself.wait_for_attribute(selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_attribute(selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_title(title)\n\nself.assert_title_contains(substring)\n\nself.assert_url(url)\n\nself.assert_url_contains(substring)\n\nself.assert_no_js_errors(exclude=[])\n\nself.inspect_html()\n\nself.is_valid_url(url)\n\nself.is_online()\n\nself.is_chromium()\n\nself.get_chrome_version()\n\nself.get_chromium_version()\n\nself.get_chromedriver_version()\n\nself.get_chromium_driver_version()\n\nself.get_mfa_code(totp_key=None)\n# Duplicates\n# self.get_totp_code(totp_key=None)\n# self.get_google_auth_password(totp_key=None)\n# self.get_google_auth_code(totp_key=None)\n\nself.enter_mfa_code(selector, totp_key=None, by=\"css selector\", timeout=None)\n# Duplicates\n# self.enter_totp_code(selector, totp_key=None, by=\"css selector\", timeout=None)\n\nself.convert_css_to_xpath(css)\n\nself.convert_xpath_to_css(xpath)\n\nself.convert_to_css_selector(selector, by)\n\nself.set_value(selector, text, by=\"css selector\", timeout=None, scroll=True)\n\nself.js_update_text(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.js_type(selector, text, by=\"css selector\", timeout=None)\n# self.set_text(selector, text, by=\"css selector\", timeout=None)\n\nself.set_text_content(selector, text, by=\"css selector\", timeout=None, scroll=False)\n\nself.jquery_update_text(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.jquery_type(selector, text, by=\"css selector\", timeout=None)\n\nself.get_value(selector, by=\"css selector\", timeout=None)\n\nself.set_time_limit(time_limit)\n\nself.set_default_timeout(timeout)\n\nself.reset_default_timeout()\n\nself.fail(msg=None)\n\nself.skip(reason=\"\")\n\n############\n\nself.start_recording_console_logs()\n\nself.console_log_string(string)\n\nself.console_log_script(script)\n\nself.get_recorded_console_logs()\n\n############\n\nself.set_local_storage_item(key, value)\n\nself.get_local_storage_item(key)\n\nself.remove_local_storage_item(key)\n\nself.clear_local_storage()\n# Duplicates: delete_local_storage()\n\nself.get_local_storage_keys()\n\nself.get_local_storage_items()\n\nself.set_session_storage_item(key, value)\n\nself.get_session_storage_item(key)\n\nself.remove_session_storage_item(key)\n\nself.clear_session_storage()\n# Duplicates: delete_session_storage()\n\nself.get_session_storage_keys()\n\nself.get_session_storage_items()\n\n############\n\nself.set_wire_proxy(string) # Requires \"--wire\"!\n\n############\n\nself.add_css_link(css_link)\n\nself.add_js_link(js_link)\n\nself.add_css_style(css_style)\n\nself.add_js_code_from_link(js_link)\n\nself.add_js_code(js_code)\n\nself.add_meta_tag(http_equiv=None, content=None)\n\n############\n\nself.create_presentation(name=None, theme=\"default\", transition=\"default\")\n\nself.add_slide(\n content=None, image=None, code=None, iframe=None,\n content2=None, notes=None, transition=None, name=None)\n\nself.save_presentation(name=None, filename=None, show_notes=False, interval=0)\n\nself.begin_presentation(name=None, filename=None, show_notes=False, interval=0)\n\n############\n\nself.create_pie_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_bar_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_column_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_line_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True,\n labels=True, legend=True)\n\nself.create_area_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True,\n labels=True, legend=True)\n\nself.add_series_to_chart(data_name=None, chart_name=None)\n\nself.add_data_point(label, value, color=None, chart_name=None)\n\nself.save_chart(chart_name=None, filename=None, folder=None)\n\nself.display_chart(chart_name=None, filename=None, interval=0)\n\nself.extract_chart(chart_name=None)\n\n############\n\nself.create_tour(name=None, theme=None)\n\nself.create_shepherd_tour(name=None, theme=None)\n\nself.create_bootstrap_tour(name=None)\n\nself.create_hopscotch_tour(name=None)\n\nself.create_introjs_tour(name=None)\n\nself.set_introjs_colors(theme_color=None, hover_color=None)\n\nself.add_tour_step(message, selector=None, name=None, title=None, theme=None, alignment=None)\n\nself.play_tour(name=None, interval=0)\n# Duplicates\n# self.start_tour(name=None, interval=0):\n\nself.export_tour(name=None, filename=\"my_tour.js\", url=None)\n\n############\n\nself.activate_jquery_confirm()\n\nself.set_jqc_theme(theme, color=None, width=None)\n\nself.reset_jqc_theme()\n\nself.get_jqc_button_input(message, buttons, options=None)\n\nself.get_jqc_text_input(message, button=None, options=None)\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\n############\n\nself.activate_messenger()\n\nself.post_message(message, duration=None, pause=True, style=\"info\")\n\nself.post_message_and_highlight(message, selector, by=\"css selector\")\n\nself.post_success_message(message, duration=None, pause=True)\n\nself.post_error_message(message, duration=None, pause=True)\n\nself.set_messenger_theme(theme=\"default\", location=\"default\", max_messages=\"default\")\n\n############\n\nself.generate_referral(start_page, destination_page, selector=None)\n\nself.generate_traffic(start_page, destination_page, loops=1, selector=None)\n\nself.generate_referral_chain(pages)\n\nself.generate_traffic_chain(pages, loops=1)\n\n############\n\nself.get_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_selector(selector, by=\"css selector\", timeout=None)\n# self.locator(selector, by=\"css selector\", timeout=None)\n# self.wait_for_element_present(selector, by=\"css selector\", timeout=None)\n\nself.wait_for_query_selector(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_present(selector, by=\"css selector\", timeout=None)\n\nself.assert_elements_present(*args, **kwargs)\n\n############\n\nself.find_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_element(selector, by=\"css selector\", timeout=None)\n# self.wait_for_element_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_element_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_elements(*args, **kwargs)\n# Duplicates\n# self.assert_elements_visible(*args, **kwargs)\n\n############\n\nself.find_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.find_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_exact_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.find_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_non_empty_text_visible(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_link_text_present(link_text, timeout=None)\n\nself.wait_for_partial_link_text_present(link_text, timeout=None)\n\nself.find_link_text(link_text, timeout=None)\n# Duplicates\n# self.wait_for_link_text(link_text, timeout=None)\n# self.wait_for_link_text_visible(link_text, timeout=None)\n\nself.assert_link_text(link_text, timeout=None)\n# Duplicates\n# self.assert_link(link_text, timeout=None)\n\n############\n\nself.find_partial_link_text(partial_link_text, timeout=None)\n# Duplicates\n# self.wait_for_partial_link_text(partial_link_text, timeout=None)\n\nself.assert_partial_link_text(partial_link_text, timeout=None)\n\n############\n\nself.wait_for_element_absent(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_element_not_present(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_absent(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_element_not_present(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_element_clickable(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_element_not_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_not_visible(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.wait_for_exact_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_exact_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_attribute_not_present(\n selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_attribute_not_present(\n selector, attribute, value=None, by=\"css selector\", timeout=None)\n\n############\n\nself.accept_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_accept_alert(timeout=None)\n\nself.dismiss_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_dismiss_alert(timeout=None)\n\nself.switch_to_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_switch_to_alert(timeout=None)\n\n############\n\nself.quit_extra_driver(driver=None)\n\n############\n\nself.check_window(name=\"default\", level=0, baseline=False, check_domain=True, full_diff=False)\n\n############\n\nself.deferred_assert_element(selector, by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_element(\n# selector, by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_element_present(selector, by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_element_present(\n# selector, by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_text(text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_text(\n# text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_exact_text(\n text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_exact_text(\n# text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_non_empty_text(\n selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_non_empty_text(\n# selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_check_window(\n name=\"default\", level=0, baseline=False, check_domain=True, full_diff=False, fs=False)\n# Duplicates\n# self.delayed_check_window(\n# name=\"default\", level=0, baseline=False,\n# check_domain=True, full_diff=False, fs=False)\n\nself.process_deferred_asserts(print_only=False)\n# Duplicates: self.process_delayed_asserts(print_only=False)\n\n############\n\nself.fail(msg=None) # Inherited from \"unittest\"\n\nself._check_browser() # Fails test cleanly if the active window is closed\n\nself._print(TEXT) # Calls Python's print() / Allows for translations\n\n############ # \"driver\"-specific methods added (or modified) by SeleniumBase\ndriver.default_get(url) # Because driver.get(url) works differently in UC Mode\n\ndriver.open(url) # Like driver.get(), but allows partial URLs without protocol\n\ndriver.click(selector)\n\ndriver.click_link(link_text)\n\ndriver.click_if_visible(selector)\n\ndriver.click_active_element()\n\ndriver.send_keys(selector, text)\n\ndriver.press_keys(selector, text)\n\ndriver.type(selector, text)\n\ndriver.submit(selector)\n\ndriver.assert_element(selector)\n\ndriver.assert_element_present(selector)\n\ndriver.assert_element_not_visible(selector)\n\ndriver.assert_text(text, selector)\n\ndriver.assert_exact_text(text, selector)\n\ndriver.find_element(selector)\n\ndriver.find_elements(selector)\n\ndriver.wait_for_element(selector)\n\ndriver.wait_for_element_visible(selector)\n\ndriver.wait_for_element_present(selector)\n\ndriver.wait_for_selector(selector)\n\ndriver.wait_for_text(text, selector)\n\ndriver.wait_for_exact_text(text, selector)\n\ndriver.wait_for_and_accept_alert()\n\ndriver.wait_for_and_dismiss_alert()\n\ndriver.is_element_present(selector)\n\ndriver.is_element_visible(selector)\n\ndriver.is_text_visible(text, selector)\n\ndriver.is_exact_text_visible(text, selector)\n\ndriver.is_attribute_present(selector, attribute)\n\ndriver.get_text(selector)\n\ndriver.js_click(selector)\n\ndriver.get_active_element_css()\n\ndriver.get_locale_code()\n\ndriver.get_origin()\n\ndriver.get_user_agent()\n\ndriver.highlight(selector)\n\ndriver.highlight_click(selector)\n\ndriver.highlight_if_visible(selector)\n\ndriver.sleep(seconds)\n\ndriver.locator(selector)\n\ndriver.get_attribute(selector, attribute)\n\ndriver.get_page_source()\n\ndriver.get_title()\n\ndriver.switch_to_frame(frame=\"iframe\")\n\n############ # \"driver\"-specific methods added (or modified) by SeleniumBase for UC Mode\ndriver.get(url) # If UC Mode and site detects bots, then uc_open_with_tab(url)\n\ndriver.uc_open(url) # (Open in same tab with default reconnect_time)\n\ndriver.uc_open_with_tab(url) # (New tab with default reconnect_time)\n\ndriver.uc_open_with_reconnect(url, reconnect_time=None) # (New tab)\n\ndriver.uc_open_with_disconnect(url, timeout=None) # New tab + sleep()\n\ndriver.reconnect(timeout) # disconnect() + sleep(timeout) + connect()\n\ndriver.disconnect() # Stops the webdriver service to prevent detection\n\ndriver.connect() # Starts the webdriver service to allow actions again\n\ndriver.uc_click(selector) # A stealthy click for evading bot-detection\n\ndriver.uc_gui_press_key(key) # Use PyAutoGUI to press the keyboard key\n\ndriver.uc_gui_press_keys(keys) # Use PyAutoGUI to press a list of keys\n\ndriver.uc_gui_write(text) # Similar to uc_gui_press_keys(), but faster\n\ndriver.uc_gui_click_x_y(x, y, timeframe=0.25) # PyAutoGUI click screen\n\ndriver.uc_gui_click_captcha(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False) # reC\n\ndriver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False) # CFT\n\ndriver.uc_gui_handle_cf(frame=\"iframe\") # PyAutoGUI click CF Turnstile\n\ndriver.uc_switch_to_frame(frame=\"iframe\") # Stealthy switch_to_frame()\n
\u2705 Test Folder: SeleniumBase/examples
Use --mobile
to run SeleniumBase tests using Chrome's mobile device emulator with default values for Device Metrics and User-Agent.
Here's an example mobile test:
SeleniumBase/examples/test_skype_site.py
pytest test_skype_site.py --mobile\n
To configure Device Metrics, use:
--metrics=\"CSS_Width,CSS_Height,Pixel_Ratio\"\n
To configure the User-Agent, use:
--agent=\"USER-AGENT-STRING\"\n
To find real values for Device Metrics, see:
To find real User-Agent strings, see:
Here's another example of a mobile test:
SeleniumBase/examples/test_swag_labs.py
pytest test_swag_labs.py --mobile\n
Here's an example of configuring mobile settings for that test:
# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"360,640,2\"\n\n# Run mobile tests specifying the user agent\npytest test_swag_labs.py --mobile --agent=\"Mozilla/5.0 (Linux; Android 9; Pixel 3 XL)\"\n
For some SeleniumBase Syntax Formats, you can also use mobile=True
to run tests in Mobile Mode:
from seleniumbase import Driver\n\ndriver = Driver(mobile=True)\ntry:\n driver.open(\"https://www.skype.com/en/get-skype/\")\n driver.assert_element('[aria-label=\"Microsoft\"]')\n driver.assert_text(\"Download Skype\", \"h1\")\n driver.highlight(\"div.appBannerContent\")\n driver.highlight(\"h1\")\n driver.assert_text(\"Skype for Mobile\", \"h2\")\n driver.highlight(\"h2\")\n driver.highlight(\"#get-skype-0\")\n driver.highlight_click(\"span[data-dropdown-icon]\")\n driver.highlight(\"#get-skype-0_android-download\")\n driver.highlight('[data-bi-id*=\"ios\"]')\nfinally:\n driver.quit()\n
"}, {"location": "help_docs/mysql_installation/", "title": "\ud83d\uddc4\ufe0f MySQL Instructions", "text": ""}, {"location": "help_docs/mysql_installation/#mysql-installation-instructions", "title": "MySQL Installation Instructions", "text": ""}, {"location": "help_docs/mysql_installation/#mysql-optional", "title": "MySQL (OPTIONAL)", "text": "
(NOTE: If you don't plan on using the SeleniumBase MySQL DB feature, then you can skip this section.)
"}, {"location": "help_docs/mysql_installation/#github-actions-ubuntu-linux-mysql-setup", "title": "GitHub Actions Ubuntu Linux MySQL Setup", "text": "sudo /etc/init.d/mysql start\nmysql -e 'CREATE DATABASE IF NOT EXISTS test_db;' -uroot -proot\nwget https://raw.githubusercontent.com/seleniumbase/SeleniumBase/master/seleniumbase/core/create_db_tables.sql\nsudo mysql -h 127.0.0.1 -uroot -proot test_db < create_db_tables.sql\nsudo mysql -e 'ALTER USER \"root\"@\"localhost\" IDENTIFIED BY \"test\";' -uroot -proot\nsudo service mysql restart\n
Have SeleniumBase tests write to the MySQL DB:
pytest --with-db_reporting\n
Query MySQL DB Results:
mysql -e 'select test_address,browser,state,start_time,runtime from test_db.test_run_data;' -uroot -ptest\n
"}, {"location": "help_docs/mysql_installation/#standard-ubuntu-linux-mysql-setup", "title": "Standard Ubuntu Linux MySQL Setup", "text": "sudo apt update\nsudo apt install mysql-server\nsudo mysql_secure_installation\nsudo mysql -e 'CREATE DATABASE IF NOT EXISTS test_db;'\nsudo mysql -h 127.0.0.1 -u root test_db < seleniumbase/core/create_db_tables.sql\nsudo service mysql restart\n
To change the password from root
to test
:
mysqladmin -u root -p'root' password 'test'\nsudo service mysql restart\n
"}, {"location": "help_docs/mysql_installation/#macos-mysql-setup", "title": "MacOS MySQL Setup", "text": "brew install mysql\n
Then start the MySQL service:
brew services start mysql\n
(Continue with additional steps below to set up your DB.)
"}, {"location": "help_docs/mysql_installation/#windows-mysql-setup", "title": "Windows MySQL Setup", "text": "Download MySQL here Follow the steps from the MySQL Downloads page.
(Continue with additional steps below to set up your DB.)
"}, {"location": "help_docs/mysql_installation/#access-your-mysql-db", "title": "Access your MySQL DB", "text": "If you want a visual tool to help make your MySQL life easier, try MySQL Workbench.
"}, {"location": "help_docs/mysql_installation/#prepare-your-mysql-db", "title": "Prepare your MySQL DB", "text": "Use the create_db_tables.sql file to create the necessary tables for storing test data.
"}, {"location": "help_docs/mysql_installation/#configure-your-mysql-db-for-seleniumbase", "title": "Configure your MySQL DB for SeleniumBase", "text": "Update your settings.py file with your MySQL DB credentials so that tests can write to the database when they run.
"}, {"location": "help_docs/mysql_installation/#have-seleniumbase-tests-write-to-your-mysql-db", "title": "Have SeleniumBase tests write to your MySQL DB", "text": "Add the --with-db_reporting
argument on the command-line when you want tests to write to your MySQL database. Example:
pytest --with-db_reporting\n
"}, {"location": "help_docs/recorder_mode/", "title": "\ud83d\udd34 Recorder Mode", "text": ""}, {"location": "help_docs/recorder_mode/#recorder-mode", "title": "Recorder Mode \ud83d\udd34/\u23fa\ufe0f", "text": "\ud83d\udd34 SeleniumBase Recorder Mode lets you record & export browser actions into test automation scripts.
\u23fa\ufe0f Recorder Mode can be activated from the command-line interface or the Recorder Desktop App.
\u23fa\ufe0f To make a new recording from the command-line interface, use sbase mkrec
, sbase codegen
, or sbase record
:
sbase mkrec TEST_NAME.py --url=URL\n
If the file already exists, you'll get an error. If no URL is provided, you'll start on a blank page and will need to navigate somewhere for the Recorder to activate. (The Recorder captures events on URLs that start with https
, http
, or file
.) The command above runs an empty test that stops at a breakpoint so that you can perform manual browser actions for the Recorder. When you have finished recording, type \"c
\" on the command-line and press [ENTER]
to continue from the breakpoint. The test will complete and a file called TEST_NAME_rec.py
will be automatically created in the ./recordings
folder. That file will get copied back to the original folder with the name you gave it. (You can run with Edge instead of Chrome by adding --edge
to the command above. For headed Linux machines, add --gui
to prevent the default headless mode on Linux.)
Example:
sbase mkrec new_test.py --url=wikipedia.org\n\n* RECORDING initialized: new_test.py\n\npytest new_test.py --rec -q -s --url=wikipedia.org\n\n>>>>>>>>>>>>>>>>>> PDB set_trace >>>>>>>>>>>>>>>>>\n\n> PATH_TO_YOUR_CURRENT_DIRECTORY/new_test.py(9)\n .\n 5 def test_recording(self):\n 6 if self.recorder_ext:\n 7 # When done recording actions,\n 8 # type \"c\", and press [Enter].\n 9 -> import pdb; pdb.set_trace()\n return None\n(Pdb+) c\n\n>>>>>>>>>>>>>>>>>> PDB continue >>>>>>>>>>>>>>>>>>\n\n>>> RECORDING SAVED as: recordings/new_test_rec.py\n**************************************************\n\n*** RECORDING COPIED to: new_test.py\n
\ud83d\udd34 You can also activate Recorder Mode from the Recorder Desktop App:
sbase recorder\n* Starting the SeleniumBase Recorder Desktop App...\n
\u23fa\ufe0f While a recording is in progress, you can press the [ESC]
key to pause the Recorder. To resume the recording, you can hit the [~`]
key, which is located directly below the [ESC]
key on most keyboards.
\u23fa\ufe0f From within Recorder Mode there are two additional modes: \"Assert Element Mode\" and \"Assert Text Mode\". To switch into \"Assert Element Mode\", press the [^]-key (SHIFT+6)
: The border will become purple, and you'll be able to click on elements to assert from your test. To switch into \"Assert Text Mode\", press the [&]-key (SHIFT+7)
: The border will become teal, and you'll be able to click on elements for asserting text from your test.
\u23fa\ufe0f While using either of the two special Assertion Modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without navigating away from the page, etc. To add an assertion for buttons without triggering default \"click\" behavior, mouse-down on the button and then mouse-up somewhere else. (This prevents a detected click while still recording the assert.) To return back to the original Recorder Mode, press any key other than [SHIFT]
or [BACKSPACE]
(Eg: Press [CONTROL]
, etc.). Press [ESC]
once to leave the Assertion Modes, but it'll stop the Recorder if you press it again.
\u23fa\ufe0f For extra flexibility, the sbase mkrec
command can be split into four separate commands:
sbase mkfile TEST_NAME.py --rec\n\npytest TEST_NAME.py --rec -q -s\n\nsbase print ./recordings/TEST_NAME_rec.py -n\n\ncp ./recordings/TEST_NAME_rec.py ./TEST_NAME.py\n
The first command creates a boilerplate test with a breakpoint; the second command runs the test with the Recorder activated; the third command prints the completed test to the console; and the fourth command replaces the initial boilerplate with the completed test. If you're just experimenting with the Recorder, you can run the second command as many times as you want, and it'll override previous recordings saved to ./recordings/TEST_NAME_rec.py
. (Note that -s
is needed to allow breakpoints, unless you already have a pytest.ini
file present with addopts = --capture=no
in it. The -q
is optional, which shortens pytest
console output.)
\u23fa\ufe0f You can also use the Recorder to add code to an existing test. To do that, you'll first need to create a breakpoint in your code to insert manual browser actions:
import pdb; pdb.set_trace()\n
Now you'll be able to run your test with pytest
, and it will stop at the breakpoint for you to add in actions: (Press c
and ENTER
on the command-line to continue from the breakpoint.)
pytest TEST_NAME.py --rec -s\n
\u23fa\ufe0f You can also set a breakpoint at the start of your test by adding --trace
as a pytest
command-line option: (This is useful when running Recorder Mode without any pdb
breakpoints.)
pytest TEST_NAME.py --trace --rec -s\n
\u23fa\ufe0f After the test completes, a file called TEST_NAME_rec.py
will be automatically created in the ./recordings
folder, which will include the actions performed by the test, and the manual actions that you added in.
\u23fa\ufe0f Here's a command-line notification for a completed recording:
>>> RECORDING SAVED as: recordings/TEST_NAME_rec.py\n***************************************************\n
\u23fa\ufe0f When running additional tests from the same Python module, Recordings will get added to the file that was created from the first test:
>>> RECORDING ADDED to: recordings/TEST_NAME_rec.py\n***************************************************\n
\u23fa\ufe0f Recorder Mode works by saving your recorded actions into the browser's sessionStorage. SeleniumBase then reads from the browser's sessionStorage to take the raw data and generate a full test from it. Keep in mind that sessionStorage is only present while the browser tab remains in the same domain/origin. (The sessionStorage of that tab goes away if you leave that domain/origin.) To compensate, links to web pages of different domain/origin will automatically open a new tab for you in Recorder Mode.
\u23fa\ufe0f Additionally, the SeleniumBase self.open(URL)
method will also open a new tab for you in Recorder Mode if the domain/origin is different from the current URL. If you need to navigate to a different domain/origin from within the same tab, call self.save_recorded_actions()
first, which saves the recorded data for later. When a recorded test completes, SeleniumBase scans the sessionStorage data of all open browser tabs for generating the completed script.
\u23fa\ufe0f As an alternative to activating Recorder Mode with the --rec
command-line arg, you can also call self.activate_recorder()
from your tests. Using the Recorder this way is only useful for tests that stay on the same URL. This is because the standard Recorder Mode functions as a Chrome extension and persists wherever the browser goes. (This version only stays on the page where called.)
\u23fa\ufe0f (Note that same domain/origin is not the same as same URL. Example: https://xkcd.com/353 and https://xkcd.com/1537 are two different URLs with the same domain/origin. That means both URLs share the same sessionStorage, and that changes persist to different URLs of the same domain/origin. If you want to find out a website's origin during a test, just call: self.get_origin()
, which returns the value of window.location.origin
from the browser's console.)
\u23fa\ufe0f Inside recorded tests, you might find the self.open_if_not_url(URL)
method, which opens the URL given if the browser is not currently on that page. SeleniumBase uses this method in recorded scripts when the Recorder detects that a browser action changed the current URL. This method prevents an unnecessary page load and shows what page the test visited after a browser action.
\u23fa\ufe0f By launching the Recorder App with sbase recorder --ee
, you can end the recording by pressing {SHIFT
+ESC
} instead of the usual way of ending the recording by typing c
from a breakpoint()
and pressing Enter
. Those buttons don't need to be pressed at the same time, but SHIFT
must be pressed directly before ESC
.
All the code is on GitHub:
"}, {"location": "help_docs/shadow_dom/", "title": "\ud83d\udc64 Shadow DOM Support", "text": ""}, {"location": "help_docs/shadow_dom/#shadow-dom-support-shadow-root-interaction", "title": "Shadow DOM support / Shadow-root interaction", "text": "
\ud83d\udd35 SeleniumBase lets you pierce through open Shadow DOM selectors (to interact with elements inside) by adding ::shadow
to CSS fragments that include a shadow-root element. For multi-layered shadow-roots, you must individually pierce through each shadow-root element that you want to get through.
\ud83d\udd35 Here are some examples of Shadow DOM selectors:
css_1 = \"downloads-manager::shadow #no-downloads\"\n\ncss_2 = \"downloads-manager::shadow #downloadsList downloads-item::shadow #file-link\"\n\ncss_3 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow cr-icon-button\"\n\ncss_4 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow #searchInput\"\n\ncss_5 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow #clearSearch\"\n
\ud83d\udd35 The shadow-root (::shadow
) elements are transitional, and therefore cannot be the final part of your CSS selectors. Complete your CSS selectors by including an element that's inside a shadow-root.
\ud83d\udd35 NOTE: ::shadow
selectors only exist within SeleniumBase. (They are not part of standard CSS.)
\ud83d\udd35 Here are some examples of tests that interact with Shadow DOM elements: * examples/shadow_root_test.py * examples/test_shadow_dom.py * examples/old_wordle_script.py
"}, {"location": "help_docs/syntax_formats/", "title": "\ud83d\udd21 Syntax Formats", "text": "The 23 Syntax Formats / Design Patterns \ud83d\udd21 SeleniumBase supports multiple ways of structuring tests:In this format, (which is used by most of the tests in the SeleniumBase examples folder), BaseCase
is imported at the top of a Python file, followed by a Python class inheriting BaseCase
. Then, any test method defined in that class automatically gains access to SeleniumBase methods, including the setUp()
and tearDown()
methods that are automatically called for opening and closing web browsers at the start and end of tests.
To run a test of this format, use pytest
or pynose
. Adding BaseCase.main(__name__, __file__)
enables python
to run pytest
on your file indirectly. Here's an example:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n def test_demo_site(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n self.type(\"#myTextInput\", \"This is Automated\")\n self.click(\"#myButton\")\n self.assert_element(\"tbody#tbodyId\")\n self.assert_text(\"Automation Practice\", \"h3\")\n self.click_link(\"SeleniumBase Demo Page\")\n self.assert_exact_text(\"Demo Page\", \"h1\")\n self.assert_no_js_errors()\n
(See examples/test_demo_site.py for the full test.)
Using BaseCase
inheritance is a great starting point for anyone learning SeleniumBase, and it follows good object-oriented programming principles.
There are situations where you may want to customize the setUp
and tearDown
of your tests. Maybe you want to have all your tests login to a specific web site first, or maybe you want to have your tests report results through an API call depending on whether a test passed or failed. This can be done by creating a subclass of BaseCase
and then carefully creating custom setUp()
and tearDown()
methods that don't overwrite the critical functionality of the default SeleniumBase setUp()
and tearDown()
methods. Afterwards, your test classes will inherit the subclass of BaseCase
with the added functionality, rather than directly inheriting BaseCase
itself. Here's an example of that:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass BaseTestCase(BaseCase):\n def setUp(self):\n super().setUp()\n # <<< Run custom setUp() code for tests AFTER the super().setUp() >>>\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n if self.has_exception():\n # <<< Run custom code if the test failed. >>>\n pass\n else:\n # <<< Run custom code if the test passed. >>>\n pass\n # (Wrap unreliable tearDown() code in a try/except block.)\n # <<< Run custom tearDown() code BEFORE the super().tearDown() >>>\n super().tearDown()\n\n def login(self):\n # <<< Placeholder. Add your code here. >>>\n # Reduce duplicate code in tests by having reusable methods like this.\n # If the UI changes, the fix can be applied in one place.\n pass\n\n def example_method(self):\n # <<< Placeholder. Add your code here. >>>\n pass\n\nclass MyTests(BaseTestCase):\n def test_example(self):\n self.login()\n self.example_method()\n self.type(\"input\", \"Name\")\n self.click(\"form button\")\n # ...\n
(See examples/boilerplates/base_test_case.py for more info.)
3. The \"sb\" pytest fixture (no class)The pytest framework comes with a unique system called fixtures, which replaces import statements at the top of Python files by importing libraries directly into test definitions. More than just being an import, a pytest fixture can also automatically call predefined setUp()
and tearDown()
methods at the beginning and end of test methods. To work, sb
is added as an argument to each test method definition that needs SeleniumBase functionality. This means you no longer need import statements in your Python files to use SeleniumBase. If using other pytest fixtures in your tests, you may need to use the SeleniumBase fixture (instead of BaseCase
class inheritance) for compatibility reasons. Here's an example of the sb
fixture in a test that does not use Python classes:
def test_sb_fixture_with_no_class(sb):\n sb.open(\"seleniumbase.io/help_docs/install/\")\n sb.type('input[aria-label=\"Search\"]', \"GUI Commander\")\n sb.click('mark:contains(\"Commander\")')\n sb.assert_title_contains(\"GUI / Commander\")\n
(See the top of examples/test_sb_fixture.py for the test.)
4. The \"sb\" pytest fixture (in class)The sb
pytest fixture can also be used inside of a class. There is a slight change to the syntax because that means test methods must also include self
in their argument definitions when test methods are defined. (The self
argument represents the class object, and is used in every test method that lives inside of a class.) Once again, no import statements are needed in your Python files for this to work. Here's an example of using the sb
fixture in a test method that lives inside of a Python class:
class Test_SB_Fixture:\n def test_sb_fixture_inside_class(self, sb):\n sb.open(\"seleniumbase.io/help_docs/install/\")\n sb.type('input[aria-label=\"Search\"]', \"GUI Commander\")\n sb.click('mark:contains(\"Commander\")')\n sb.assert_title_contains(\"GUI / Commander\")\n
(See the bottom of examples/test_sb_fixture.py for the test.)
5. Page Object Model with BaseCaseWith SeleniumBase, you can use Page Objects to break out code from tests, but remember, the self
variable (from test methods that inherit BaseCase
) contains the driver and all other framework-specific variable definitions. Therefore, that self
must be passed as an arg into any outside class method in order to call SeleniumBase methods from there. In the example below, the self
variable from the test method is passed into the sb
arg of the Page Object class method because the self
arg of the Page Object class method is already being used for its own class. Every Python class method definition must include the self
as the first arg.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass LoginPage:\n def login_to_swag_labs(self, sb, username):\n sb.open(\"https://www.saucedemo.com\")\n sb.type(\"#user-name\", username)\n sb.type(\"#password\", \"secret_sauce\")\n sb.click('input[type=\"submit\"]')\n\nclass MyTests(BaseCase):\n def test_swag_labs_login(self):\n LoginPage().login_to_swag_labs(self, \"standard_user\")\n self.assert_element(\"div.inventory_list\")\n self.assert_element('div:contains(\"Sauce Labs Backpack\")')\n
(See examples/boilerplates/samples/swag_labs_test.py for the full test.)
6. Page Object Model with the \"sb\" fixtureThis is similar to the classic Page Object Model with BaseCase
inheritance, except that this time we pass the sb
pytest fixture from the test into the sb
arg of the page object class method, (instead of passing self
). Now that you're using sb
as a pytest fixture, you no longer need to import BaseCase
anywhere in your code. See the example below:
class LoginPage:\n def login_to_swag_labs(self, sb, username):\n sb.open(\"https://www.saucedemo.com\")\n sb.type(\"#user-name\", username)\n sb.type(\"#password\", \"secret_sauce\")\n sb.click('input[type=\"submit\"]')\n\nclass MyTests:\n def test_swag_labs_login(self, sb):\n LoginPage().login_to_swag_labs(sb, \"standard_user\")\n sb.assert_element(\"div.inventory_list\")\n sb.assert_element('div:contains(\"Sauce Labs Backpack\")')\n
(See examples/boilerplates/samples/sb_swag_test.py for the full test.)
7. Using \"request\" to get \"sb\" (no class)The pytest request
fixture can be used to retrieve other pytest fixtures from within tests, such as the sb
fixture. This allows you to have more control over when fixtures get initialized because the fixture no longer needs to be loaded at the very beginning of test methods. This is done by calling request.getfixturevalue('sb')
from the test. Here's an example of using the pytest request
fixture to load the sb
fixture in a test method that does not use Python classes:
def test_request_sb_fixture(request):\n sb = request.getfixturevalue('sb')\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.assert_text(\"SeleniumBase\", \"#myForm h2\")\n sb.assert_element(\"input#myTextInput\")\n sb.type(\"#myTextarea\", \"This is me\")\n sb.click(\"#myButton\")\n sb.tearDown()\n
(See the top of examples/test_request_sb_fixture.py for the test.)
8. Using \"request\" to get \"sb\" (in class)The pytest request
fixture can also be used to get the sb
fixture from inside a Python class. Here's an example of that:
class Test_Request_Fixture:\n def test_request_sb_fixture_in_class(self, request):\n sb = request.getfixturevalue('sb')\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.assert_element(\"input#myTextInput\")\n sb.type(\"#myTextarea\", \"Automated\")\n sb.assert_text(\"This Text is Green\", \"#pText\")\n sb.click(\"#myButton\")\n sb.assert_text(\"This Text is Purple\", \"#pText\")\n sb.tearDown()\n
(See the bottom of examples/test_request_sb_fixture.py for the test.)
9. Overriding the driver via BaseCaseWhen you want to use SeleniumBase methods via BaseCase
, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough. Here's an example of that:
from selenium import webdriver\nfrom seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass OverrideDriverTest(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n \"\"\"This method overrides get_new_driver() from BaseCase.\"\"\"\n options = webdriver.ChromeOptions()\n options.add_argument(\"--disable-3d-apis\")\n options.add_argument(\"--disable-notifications\")\n if self.headless:\n options.add_argument(\"--headless=new\")\n options.add_argument(\"--disable-gpu\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\", \"enable-logging\"],\n )\n prefs = {\n \"credentials_enable_service\": False,\n \"profile.password_manager_enabled\": False,\n }\n options.add_experimental_option(\"prefs\", prefs)\n return webdriver.Chrome(options=options)\n\n def test_simple(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n self.assert_text(\"Demo Page\", \"h1\")\n
(From examples/test_override_driver.py)
The above format lets you customize selenium-wire for intercepting and inspecting requests and responses during SeleniumBase tests. Here's how a selenium-wire
integration may look:
from seleniumbase import BaseCase\nfrom seleniumwire import webdriver # Requires \"pip install selenium-wire\"\nBaseCase.main(__name__, __file__)\n\n\nclass WireTestCase(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n options = webdriver.ChromeOptions()\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"]\n )\n options.add_experimental_option(\"useAutomationExtension\", False)\n return webdriver.Chrome(options=options)\n\n def test_simple(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n for request in self.driver.requests:\n print(request.url)\n
(NOTE: The selenium-wire
integration is now included with seleniumbase
: Add --wire
as a pytest
command-line option to activate.)
When you want to use SeleniumBase methods via the sb
pytest fixture, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough.
\"\"\"Overriding the \"sb\" fixture to override the driver.\"\"\"\nimport pytest\n\n@pytest.fixture()\ndef sb(request):\n from selenium import webdriver\n from seleniumbase import BaseCase\n from seleniumbase import config as sb_config\n from seleniumbase.core import session_helper\n\n class BaseClass(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n \"\"\"This method overrides get_new_driver() from BaseCase.\"\"\"\n options = webdriver.ChromeOptions()\n if self.headless:\n options.add_argument(\"--headless=new\")\n options.add_argument(\"--disable-gpu\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"],\n )\n return webdriver.Chrome(options=options)\n\n def setUp(self):\n super().setUp()\n\n def base_method(self):\n pass\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n super().tearDown()\n\n if request.cls:\n if sb_config.reuse_class_session:\n the_class = str(request.cls).split(\".\")[-1].split(\"'\")[0]\n if the_class != sb_config._sb_class:\n session_helper.end_reused_class_session_as_needed()\n sb_config._sb_class = the_class\n request.cls.sb = BaseClass(\"base_method\")\n request.cls.sb.setUp()\n request.cls.sb._needs_tearDown = True\n request.cls.sb._using_sb_fixture = True\n request.cls.sb._using_sb_fixture_class = True\n sb_config._sb_node[request.node.nodeid] = request.cls.sb\n yield request.cls.sb\n if request.cls.sb._needs_tearDown:\n request.cls.sb.tearDown()\n request.cls.sb._needs_tearDown = False\n else:\n sb = BaseClass(\"base_method\")\n sb.setUp()\n sb._needs_tearDown = True\n sb._using_sb_fixture = True\n sb._using_sb_fixture_no_class = True\n sb_config._sb_node[request.node.nodeid] = sb\n yield sb\n if sb._needs_tearDown:\n sb.tearDown()\n sb._needs_tearDown = False\n\ndef test_override_fixture_no_class(sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n\nclass TestOverride:\n def test_override_fixture_inside_class(self, sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n
(From examples/test_override_sb_fixture.py)
Here's how the selenium-wire integration may look when overriding the sb
pytest fixture to override the driver:
import pytest\n\n@pytest.fixture()\ndef sb(request):\n import sys\n from seleniumbase import BaseCase\n from seleniumbase import config as sb_config\n from seleniumwire import webdriver # Requires \"pip install selenium-wire\"\n\n class BaseClass(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n options = webdriver.ChromeOptions()\n if \"linux\" in sys.platform:\n options.add_argument(\"--headless=new\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"],\n )\n return webdriver.Chrome(options=options)\n\n def setUp(self):\n super().setUp()\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n super().tearDown()\n\n def base_method(self):\n pass\n\n if request.cls:\n request.cls.sb = BaseClass(\"base_method\")\n request.cls.sb.setUp()\n request.cls.sb._needs_tearDown = True\n request.cls.sb._using_sb_fixture = True\n request.cls.sb._using_sb_fixture_class = True\n sb_config._sb_node[request.node.nodeid] = request.cls.sb\n yield request.cls.sb\n if request.cls.sb._needs_tearDown:\n request.cls.sb.tearDown()\n request.cls.sb._needs_tearDown = False\n else:\n sb = BaseClass(\"base_method\")\n sb.setUp()\n sb._needs_tearDown = True\n sb._using_sb_fixture = True\n sb._using_sb_fixture_no_class = True\n sb_config._sb_node[request.node.nodeid] = sb\n yield sb\n if sb._needs_tearDown:\n sb.tearDown()\n sb._needs_tearDown = False\n\ndef test_wire_with_no_class(sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n for request in sb.driver.requests:\n print(request.url)\n\nclass TestWire:\n def test_wire_inside_class(self, sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n for request in sb.driver.requests:\n print(request.url)\n
(NOTE: The selenium-wire
integration is now included with seleniumbase
: Add --wire
as a pytest
command-line option to activate. If you need both --wire
with --undetected
modes together, you'll still need to override get_new_driver()
.)
This format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Chinese. Here's an example of that:
from seleniumbase.translate.chinese import \u7852\u6d4b\u8bd5\u7528\u4f8b\n\u7852\u6d4b\u8bd5\u7528\u4f8b.main(__name__, __file__)\n\n\nclass \u6211\u7684\u6d4b\u8bd5\u7c7b(\u7852\u6d4b\u8bd5\u7528\u4f8b):\n def test_\u4f8b\u5b501(self):\n self.\u5f00\u542f(\"https://zh.wikipedia.org/wiki/\")\n self.\u65ad\u8a00\u6807\u9898(\"\u7ef4\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u4e66\")\n self.\u65ad\u8a00\u5143\u7d20('a[title=\"Wikipedia:\u5173\u4e8e\"]')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u521b\u5efa\u8d26\u53f7\")')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u767b\u5f55\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u65b0\u95fb\u52a8\u6001\", \"span#\u65b0\u95fb\u52a8\u6001\")\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u821e\u9f8d\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u821e\u9f8d\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Chinese_draak.jpg\"]')\n self.\u56de\u53bb()\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u9ebb\u5a46\u8c46\u8150\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u9ebb\u5a46\u8c46\u8150\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('figure:contains(\"\u4e00\u5bb6\u4e2d\u9910\u9928\u7684\u9ebb\u5a46\u8c46\u8150\")')\n self.\u56de\u53bb()\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u7cbe\u6b66\u82f1\u96c4\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Fist_of_legend.jpg\"]')\n self.\u65ad\u8a00\u6587\u672c(\"\u674e\u8fde\u6770\", 'li a[title=\"\u674e\u8fde\u6770\"]')\n
(See examples/translations/chinese_test_1.py for the Chinese test.)
12. BaseCase with Dutch translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Dutch. Here's an example of that:
from seleniumbase.translate.dutch import Testgeval\nTestgeval.main(__name__, __file__)\n\n\nclass MijnTestklasse(Testgeval):\n def test_voorbeeld_1(self):\n self.openen(\"https://nl.wikipedia.org/wiki/Hoofdpagina\")\n self.controleren_element('a[title*=\"hoofdpagina gaan\"]')\n self.controleren_tekst(\"Welkom op Wikipedia\", \"td.hp-welkom\")\n self.typ(\"#searchInput\", \"Stroopwafel\")\n self.klik(\"#searchButton\")\n self.controleren_tekst(\"Stroopwafel\", \"#firstHeading\")\n self.controleren_element('img[src*=\"Stroopwafels\"]')\n self.typ(\"#searchInput\", \"Rijksmuseum Amsterdam\")\n self.klik(\"#searchButton\")\n self.controleren_tekst(\"Rijksmuseum\", \"#firstHeading\")\n self.controleren_element('img[src*=\"Rijksmuseum\"]')\n self.terug()\n self.controleren_url_bevat(\"Stroopwafel\")\n self.vooruit()\n self.controleren_url_bevat(\"Rijksmuseum\")\n
(See examples/translations/dutch_test_1.py for the Dutch test.)
13. BaseCase with French translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into French. Here's an example of that:
from seleniumbase.translate.french import CasDeBase\nCasDeBase.main(__name__, __file__)\n\n\nclass MaClasseDeTest(CasDeBase):\n def test_exemple_1(self):\n self.ouvrir(\"https://fr.wikipedia.org/wiki/\")\n self.v\u00e9rifier_texte(\"Wikip\u00e9dia\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('[alt=\"Wikip\u00e9dia\"]')\n self.js_taper(\"#searchform input\", \"Cr\u00e8me br\u00fbl\u00e9e\")\n self.cliquer(\"#searchform button\")\n self.v\u00e9rifier_texte(\"Cr\u00e8me br\u00fbl\u00e9e\", \"#firstHeading\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('img[alt*=\"Cr\u00e8me br\u00fbl\u00e9e\"]')\n self.js_taper(\"#searchform input\", \"Jardin des Tuileries\")\n self.cliquer(\"#searchform button\")\n self.v\u00e9rifier_texte(\"Jardin des Tuileries\", \"#firstHeading\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('img[alt*=\"Jardin des Tuileries\"]')\n self.retour()\n self.v\u00e9rifier_url_contient(\"br\u00fbl\u00e9e\")\n self.en_avant()\n self.v\u00e9rifier_url_contient(\"Jardin\")\n
(See examples/translations/french_test_1.py for the French test.)
14. BaseCase with Italian translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Italian. Here's an example of that:
from seleniumbase.translate.italian import CasoDiProva\nCasoDiProva.main(__name__, __file__)\n\n\nclass MiaClasseDiTest(CasoDiProva):\n def test_esempio_1(self):\n self.apri(\"https://it.wikipedia.org/wiki/\")\n self.verificare_testo(\"Wikipedia\")\n self.verificare_elemento('a[title=\"Lingua italiana\"]')\n self.digitare(\"#searchInput\", \"Pizza\")\n self.fare_clic(\"#searchButton\")\n self.verificare_testo(\"Pizza\", \"#firstHeading\")\n self.verificare_elemento('figure img[src*=\"pizza\"]')\n self.digitare(\"#searchInput\", \"Colosseo\")\n self.fare_clic(\"#searchButton\")\n self.verificare_testo(\"Colosseo\", \"#firstHeading\")\n self.verificare_elemento('figure img[src*=\"Colosseo\"]')\n self.indietro()\n self.verificare_url_contiene(\"Pizza\")\n self.avanti()\n self.verificare_url_contiene(\"Colosseo\")\n
(See examples/translations/italian_test_1.py for the Italian test.)
15. BaseCase with Japanese translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Japanese. Here's an example of that:
from seleniumbase.translate.japanese import \u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\n\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9.main(__name__, __file__)\n\n\nclass \u79c1\u306e\u30c6\u30b9\u30c8\u30af\u30e9\u30b9(\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9):\n def test_\u4f8b1(self):\n self.\u3092\u958b\u304f(\"https://ja.wikipedia.org/wiki/\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('[title*=\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\u3078\u3088\u3046\u3053\u305d\"]')\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u30a2\u30cb\u30e1\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a2\u30cb\u30e1\", \"#firstHeading\")\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u5bff\u53f8\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u5bff\u53f8\", \"#firstHeading\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"Various_sushi\"]')\n self.JS\u5165\u529b(\"#searchInput\", \"\u30ec\u30b4\u30e9\u30f3\u30c9\u30fb\u30b8\u30e3\u30d1\u30f3\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"LEGOLAND_JAPAN\"]')\n self.\u30ea\u30f3\u30af\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u540d\u53e4\u5c4b\u57ce\")\n self.\u30ea\u30f3\u30af\u30c6\u30ad\u30b9\u30c8\u3092\u30af\u30ea\u30c3\u30af\u3057\u307e\u3059(\"\u30c6\u30fc\u30de\u30d1\u30fc\u30af\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30c6\u30fc\u30de\u30d1\u30fc\u30af\", \"#firstHeading\")\n
(See examples/translations/japanese_test_1.py for the Japanese test.)
16. BaseCase with Korean translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Korean. Here's an example of that:
from seleniumbase.translate.korean import \uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4\n\uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4.main(__name__, __file__)\n\n\nclass \ud14c\uc2a4\ud2b8_\ud074\ub798\uc2a4(\uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4):\n def test_\uc2e4\uc2dc\uc608_1(self):\n self.\uc5f4\uae30(\"https://ko.wikipedia.org/wiki/\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\uc704\ud0a4\ubc31\uacfc\")\n self.\uc694\uc18c_\ud655\uc778('[title=\"\uc704\ud0a4\ubc31\uacfc:\uc18c\uac1c\"]')\n self.JS_\uc785\ub825(\"#searchform input\", \"\uae40\uce58\")\n self.\ud074\ub9ad(\"#searchform button\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\uae40\uce58\", \"#firstHeading\")\n self.\uc694\uc18c_\ud655\uc778('img[src*=\"Various_kimchi.jpg\"]')\n self.\ub9c1\ud06c_\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ud55c\uad6d \uc694\ub9ac\")\n self.JS_\uc785\ub825(\"#searchform input\", \"\ube44\ube54\ubc25\")\n self.\ud074\ub9ad(\"#searchform button\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ube44\ube54\ubc25\", \"#firstHeading\")\n self.\uc694\uc18c_\ud655\uc778('img[src*=\"Dolsot-bibimbap.jpg\"]')\n self.\ub9c1\ud06c_\ud14d\uc2a4\ud2b8\ub97c_\ud074\ub9ad\ud569\ub2c8\ub2e4(\"\ub3cc\uc1a5\ube44\ube54\ubc25\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ub3cc\uc1a5\ube44\ube54\ubc25\", \"#firstHeading\")\n
(See examples/translations/korean_test_1.py for the Korean test.)
17. BaseCase with Portuguese translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Portuguese. Here's an example of that:
from seleniumbase.translate.portuguese import CasoDeTeste\nCasoDeTeste.main(__name__, __file__)\n\n\nclass MinhaClasseDeTeste(CasoDeTeste):\n def test_exemplo_1(self):\n self.abrir(\"https://pt.wikipedia.org/wiki/\")\n self.verificar_texto(\"Wikip\u00e9dia\")\n self.verificar_elemento('[title=\"L\u00edngua portuguesa\"]')\n self.digitar(\"#searchform input\", \"Jo\u00e3o Pessoa\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Jo\u00e3o Pessoa\", \"#firstHeading\")\n self.verificar_elemento('img[alt*=\"Jo\u00e3o Pessoa\"]')\n self.digitar(\"#searchform input\", \"Florian\u00f3polis\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Florian\u00f3polis\", \"h1#firstHeading\")\n self.verificar_elemento('td:contains(\"Avenida Beira-Mar\")')\n self.voltar()\n self.verificar_url_cont\u00e9m(\"Jo\u00e3o_Pessoa\")\n self.atualizar_a_p\u00e1gina()\n self.js_digitar(\"#searchform input\", \"Teatro Amazonas\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Teatro Amazonas\", \"#firstHeading\")\n self.verificar_texto_do_link(\"Festival Amazonas de \u00d3pera\")\n
(See examples/translations/portuguese_test_1.py for the Portuguese test.)
18. BaseCase with Russian translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Russian. Here's an example of that:
from seleniumbase.translate.russian import \u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d\n\u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d.main(__name__, __file__)\n\n\nclass \u041c\u043e\u0439\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439\u041a\u043b\u0430\u0441\u0441(\u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d):\n def test_\u043f\u0440\u0438\u043c\u0435\u0440_1(self):\n self.\u043e\u0442\u043a\u0440\u044b\u0442\u044c(\"https://ru.wikipedia.org/wiki/\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('[title=\"\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a\"]')\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u0412\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u044f\", \"h2.main-wikimedia-header\")\n self.\u0432\u0432\u0435\u0434\u0438\u0442\u0435(\"#searchInput\", \"\u041c\u0413\u0423\")\n self.\u043d\u0430\u0436\u043c\u0438\u0442\u0435(\"#searchButton\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\", \"#firstHeading\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('img[alt*=\"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0437\u0434\u0430\u043d\u0438\u0435 \u041c\u0413\u0423\"]')\n self.\u0432\u0432\u0435\u0434\u0438\u0442\u0435(\"#searchInput\", \"\u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0428\u0443\u0440\u0438\u043a\u0430\")\n self.\u043d\u0430\u0436\u043c\u0438\u0442\u0435(\"#searchButton\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u00ab\u042b\u00bb \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0428\u0443\u0440\u0438\u043a\u0430\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('img[alt=\"\u041f\u043e\u0441\u0442\u0435\u0440 \u0444\u0438\u043b\u044c\u043c\u0430\"]')\n self.\u043d\u0430\u0437\u0430\u0434()\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_URL_\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442(\"\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\")\n self.\u0432\u043f\u0435\u0440\u0435\u0434()\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_URL_\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442(\"\u0428\u0443\u0440\u0438\u043a\u0430\")\n
(See examples/translations/russian_test_1.py for the Russian test.)
19. BaseCase with Spanish translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Spanish. Here's an example of that:
from seleniumbase.translate.spanish import CasoDePrueba\nCasoDePrueba.main(__name__, __file__)\n\n\nclass MiClaseDePrueba(CasoDePrueba):\n def test_ejemplo_1(self):\n self.abrir(\"https://es.wikipedia.org/wiki/\")\n self.verificar_texto(\"Wikipedia\")\n self.verificar_elemento('[title=\"Wikipedia:Bienvenidos\"]')\n self.escriba('[name=\"search\"]', \"Parque de Atracciones Tibidabo\")\n self.haga_clic('button:contains(\"Buscar\")')\n self.verificar_texto(\"Tibidabo\", \"#firstHeading\")\n self.verificar_elemento('img[src*=\"Tibidabo\"]')\n self.escriba('input[name=\"search\"]', \"Palma de Mallorca\")\n self.haga_clic('button:contains(\"Buscar\")')\n self.verificar_texto(\"Palma de Mallorca\", \"#firstHeading\")\n self.verificar_elemento('img[src*=\"Palma\"]')\n self.volver()\n self.verificar_url_contiene(\"Tibidabo\")\n self.adelante()\n self.verificar_url_contiene(\"Mallorca\")\n
(See examples/translations/spanish_test_1.py for the Spanish test.)
20. Gherkin syntax with \"behave\" BDD runnerWith Behave's BDD Gherkin format, you can use natural language to write tests that work with SeleniumBase methods. Behave tests are run by calling behave
on the command-line. This requires some special files in a specific directory structure. Here's an example of that structure:
features/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 behave.ini\n\u251c\u2500\u2500 environment.py\n\u251c\u2500\u2500 feature_file.feature\n\u2514\u2500\u2500 steps/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 imported.py\n \u2514\u2500\u2500 step_file.py\n
A *.feature
file might look like this:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert exact text \"Welcome!\" in \"h1\"\n And Highlight \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n When Click link \"Sign out\"\n Then Assert element 'a:contains(\"Sign in\")'\n And Assert text \"You have been signed out!\"\n
(From examples/behave_bdd/features/realworld.feature)
You'll need the environment.py
file for tests to work. Here it is:
from seleniumbase import BaseCase\nfrom seleniumbase.behave import behave_sb\nbehave_sb.set_base_class(BaseCase) # Accepts a BaseCase subclass\nfrom seleniumbase.behave.behave_sb import before_all # noqa\nfrom seleniumbase.behave.behave_sb import before_feature # noqa\nfrom seleniumbase.behave.behave_sb import before_scenario # noqa\nfrom seleniumbase.behave.behave_sb import before_step # noqa\nfrom seleniumbase.behave.behave_sb import after_step # noqa\nfrom seleniumbase.behave.behave_sb import after_scenario # noqa\nfrom seleniumbase.behave.behave_sb import after_feature # noqa\nfrom seleniumbase.behave.behave_sb import after_all # noqa\n
(From examples/behave_bdd/features/environment.py)
Inside that file, you can use BaseCase
(or a subclass) for the inherited class.
For your behave
tests to have access to SeleniumBase Behave steps, you can create an imported.py
file with the following line:
from seleniumbase.behave import steps # noqa\n
That will allow you to use lines like this in your *.feature
files:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert exact text \"Welcome!\" in \"h1\"\n And Highlight \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n
You can also create your own step files (Eg. step_file.py
):
from behave import step\n\n@step(\"Open the Swag Labs Login Page\")\ndef go_to_swag_labs(context):\n sb = context.sb\n sb.open(\"https://www.saucedemo.com\")\n sb.clear_local_storage()\n\n@step(\"Login to Swag Labs with {user}\")\ndef login_to_swag_labs(context, user):\n sb = context.sb\n sb.type(\"#user-name\", user)\n sb.type(\"#password\", \"secret_sauce\\n\")\n
(For more information, see the SeleniumBase Behave BDD ReadMe.)
21. SeleniumBase SB (Python context manager)This format provides a pure Python way of using SeleniumBase without a test runner. Options can be passed via method instantiation or from the command-line. When setting the test
option to True
(or calling python --test
), then standard test logging will occur, such as screenshots and reports for failing tests. All the usual SeleniumBase options are available, such as customizing the browser settings, etc. Here are some examples:
from seleniumbase import SB\n\nwith SB() as sb:\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
(See examples/raw_sb.py for the test.)
Here's another example, which uses test
mode:
from seleniumbase import SB\n\nwith SB(test=True) as sb:\n sb.open(\"https://google.com/ncr\")\n sb.type('[name=\"q\"]', \"SeleniumBase on GitHub\\n\")\n sb.click('a[href*=\"github.com/seleniumbase\"]')\n sb.highlight(\"div.Layout-main\")\n sb.highlight(\"div.Layout-sidebar\")\n sb.sleep(0.5)\n\nwith SB(test=True, rtf=True, demo=True) as sb:\n sb.open(\"seleniumbase.github.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n sb.assert_text(\"This is Automated\", \"#myTextInput\")\n sb.assert_text(\"This Text is Green\", \"#pText\")\n sb.click('button:contains(\"Click Me\")')\n sb.assert_text(\"This Text is Purple\", \"#pText\")\n sb.click(\"#checkBox1\")\n sb.assert_element_not_visible(\"div#drop2 img#logo\")\n sb.drag_and_drop(\"img#logo\", \"div#drop2\")\n sb.assert_element(\"div#drop2 img#logo\")\n
(See examples/raw_test_scripts.py for the test.)
22. The driver manager (via context manager)This pure Python format gives you a raw webdriver
instance in a with
block. The SeleniumBase Driver Manager will automatically make sure that your driver is compatible with your browser version. It gives you full access to customize driver options via method args or via the command-line. The driver will automatically call quit()
after the code leaves the with
block. Here are some examples:
\"\"\"DriverContext() example. (Runs with \"python\").\"\"\"\nfrom seleniumbase import DriverContext\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/\")\n driver.highlight('img[alt=\"SeleniumBase\"]', loops=6)\n\nwith DriverContext(browser=\"chrome\", incognito=True) as driver:\n driver.open(\"seleniumbase.io/apps/calculator\")\n driver.click('[id=\"4\"]')\n driver.click('[id=\"2\"]')\n driver.assert_text(\"42\", \"#output\")\n driver.highlight(\"#output\", loops=6)\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/demo_page\")\n driver.highlight(\"h2\")\n driver.type(\"#myTextInput\", \"Automation\")\n driver.click(\"#checkBox1\")\n driver.highlight(\"img\", loops=6)\n
(See examples/raw_driver_context.py for an example.)
23. The driver manager (via direct import)Another way of running Selenium tests with pure python
(as opposed to using pytest
or pynose
) is by using this format, which bypasses BaseCase methods while still giving you a flexible driver with a manager. SeleniumBase includes helper files such as page_actions.py, which may help you get around some of the limitations of bypassing BaseCase
. Here's an example:
\"\"\"Driver() example. (Runs with \"python\").\"\"\"\nfrom seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/demo_page\")\n driver.highlight(\"h2\")\n driver.type(\"#myTextInput\", \"Automation\")\n driver.click(\"#checkBox1\")\n driver.highlight(\"img\", loops=6)\nfinally:\n driver.quit()\n\ndriver = Driver(browser=\"chrome\", headless=False)\ntry:\n driver.open(\"seleniumbase.io/apps/calculator\")\n driver.click('[id=\"4\"]')\n driver.click('[id=\"2\"]')\n driver.assert_text(\"42\", \"#output\")\n driver.highlight(\"#output\", loops=6)\nfinally:\n driver.quit()\n
(From examples/raw_driver_manager.py)
Here's how the selenium-wire integration may look when using the Driver()
format:
from seleniumbase import Driver\n\ndriver = Driver(wire=True, headless=True)\ntry:\n driver.get(\"https://wikipedia.org\")\n for request in driver.requests:\n print(request.url)\nfinally:\n driver.quit()\n
Here's another selenium-wire
example with the Driver()
format:
from seleniumbase import Driver\n\ndef intercept_response(request, response):\n print(request.headers)\n\ndriver = Driver(wire=True)\ntry:\n driver.response_interceptor = intercept_response\n driver.get(\"https://wikipedia.org\")\nfinally:\n driver.quit()\n
Here's an example of basic login with the Driver()
format:
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
(From examples/raw_login_driver.py)
The Driver()
manager format can be used as a drop-in replacement for virtually every Python/selenium framework, as it uses the raw driver
instance for handling commands. The Driver()
method simplifies the work of managing drivers with optimal settings, and it can be configured with multiple args. The Driver()
also accepts command-line options (such as python --headless
) so that you don't need to modify your tests directly to use different settings. These command-line options only take effect if the associated method args remain unset (or set to None
) for the specified options.
When using the Driver()
format, you may need to activate a Virtual Display on your own if you want to run headed tests in a headless Linux environment. (See https://github.com/mdmintz/sbVirtualDisplay for details.) One such example of this is using an authenticated proxy, which is configured via a Chrome extension that is generated at runtime. (Note that regular headless mode in Chrome doesn't support extensions.)
SeleniumBase Playlist on YouTube:
SeleniumBase GitHub Repo Link:
SeleniumBase Gitter Chat Link:
Other Social Media Links:
"}, {"location": "help_docs/translations/", "title": "\ud83c\udf0f Translations", "text": ""}, {"location": "help_docs/translations/#translated-tests", "title": "\ud83c\udf0f Translated Tests \ud83c\ude3a Translation API \ud83c\ude3a", "text": "SeleniumBase supports the following 10 languages: English, Chinese, Dutch, French, Italian, Japanese, Korean, Portuguese, Russian, and Spanish. (Examples can be found in SeleniumBase/examples/translations)
Multi-language tests run with pytest like other tests. Test methods have a one-to-one mapping to supported languages. Here's an example of a translated test:
# Chinese Translation\nfrom seleniumbase.translate.chinese import \u7852\u6d4b\u8bd5\u7528\u4f8b\n\nclass \u6211\u7684\u6d4b\u8bd5\u7c7b(\u7852\u6d4b\u8bd5\u7528\u4f8b):\n def test_\u4f8b\u5b501(self):\n self.\u5f00\u542f(\"https://zh.wikipedia.org/wiki/\")\n self.\u65ad\u8a00\u6807\u9898(\"\u7ef4\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u4e66\")\n self.\u65ad\u8a00\u5143\u7d20('a[title=\"Wikipedia:\u5173\u4e8e\"]')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u521b\u5efa\u8d26\u53f7\")')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u767b\u5f55\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u65b0\u95fb\u52a8\u6001\", \"span#\u65b0\u95fb\u52a8\u6001\")\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u821e\u9f8d\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u821e\u9f8d\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Chinese_draak.jpg\"]')\n
Here's another example:
# Japanese Translation\nfrom seleniumbase.translate.japanese import \u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\n\nclass \u79c1\u306e\u30c6\u30b9\u30c8\u30af\u30e9\u30b9(\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9):\n def test_\u4f8b1(self):\n self.\u3092\u958b\u304f(\"https://ja.wikipedia.org/wiki/\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('[title*=\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\u3078\u3088\u3046\u3053\u305d\"]')\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u30a2\u30cb\u30e1\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a2\u30cb\u30e1\", \"#firstHeading\")\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u5bff\u53f8\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u5bff\u53f8\", \"#firstHeading\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"Various_sushi\"]')\n
You can use SeleniumBase to selectively translate the method names of any test from one language to another with the console scripts interface. Additionally, the import
line at the top of the Python file will change to import the new BaseCase
. Example: BaseCase
becomes CasoDeTeste
when a test is translated into Portuguese.
seleniumbase translate\n
* Usage:\nseleniumbase translate [SB_FILE.py] [LANGUAGE] [ACTION]\n\n* Languages:\n``--en`` / ``--English`` | ``--zh`` / ``--Chinese``\n``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``\n``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``\n``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``\n``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``\n\n* Actions:\n``-p`` / ``--print`` (Print translation output to the screen)\n``-o`` / ``--overwrite`` (Overwrite the file being translated)\n``-c`` / ``--copy`` (Copy the translation to a new ``.py`` file)\n\n* Options:\n``-n`` (include line Numbers when using the Print action)\n\n* Examples:\nTranslate test_1.py into Chinese and only print the output:\n>>> seleniumbase translate test_1.py --zh -p\nTranslate test_2.py into Portuguese and overwrite the file:\n>>> seleniumbase translate test_2.py --pt -o\nTranslate test_3.py into Dutch and make a copy of the file:\n>>> seleniumbase translate test_3.py --nl -c\n\n* Output:\nTranslates a SeleniumBase Python file into the language\nspecified. Method calls and ``import`` lines get swapped.\nBoth a language and an action must be specified.\nThe ``-p`` action can be paired with one other action.\nWhen running with ``-c`` (or ``--copy``) the new file name\nwill be the original name appended with an underscore\nplus the 2-letter language code of the new language.\n(Example: Translating ``test_1.py`` into Japanese with\n``-c`` will create a new file called ``test_1_ja.py``.)\n
"}, {"location": "help_docs/uc_mode/", "title": "\ud83d\udc64 UC Mode", "text": ""}, {"location": "help_docs/uc_mode/#uc-mode", "title": "UC Mode \ud83d\udc64", "text": "\ud83d\udc64 SeleniumBase UC Mode (Undetected-Chromedriver Mode) allows bots to appear human, which lets them evade detection from anti-bot services that try to block them or trigger CAPTCHAs on various websites.
(Watch the 1st UC Mode tutorial on YouTube! \u25b6\ufe0f)
(Watch the 2nd UC Mode tutorial on YouTube! \u25b6\ufe0f)
\ud83d\udc64 UC Mode is based on undetected-chromedriver, but includes multiple updates, fixes, and improvements, such as:
uc_*()
methods.\ud83d\udc64 Here's a simple example with the Driver
manager:
from seleniumbase import Driver\n\ndriver = Driver(uc=True)\nurl = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, 4)\ndriver.quit()\n
\ud83d\udc64 Here's an example with the SB
manager (which has more methods and functionality than the Driver
format):
from seleniumbase import SB\n\nwith SB(uc=True) as sb:\n url = \"https://gitlab.com/users/sign_in\"\n sb.uc_open_with_reconnect(url, 4)\n
\ud83d\udc64 Here's a longer example, which includes a special click if the CAPTCHA isn't bypassed on the initial page load:
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://gitlab.com/users/sign_in\"\n sb.uc_open_with_reconnect(url, 4)\n sb.uc_gui_click_captcha()\n sb.assert_text(\"Username\", '[for=\"user_login\"]', timeout=3)\n sb.assert_element('label[for=\"user_login\"]')\n sb.highlight('button:contains(\"Sign in\")')\n sb.highlight('h1:contains(\"GitLab.com\")')\n sb.post_message(\"SeleniumBase wasn't detected\", duration=4)\n
\ud83d\udc64 Here's an example where clicking the checkbox is required, even for humans:(Commonly seen on forms that are CAPTCHA-protected.)
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://seleniumbase.io/apps/turnstile\"\n sb.uc_open_with_reconnect(url, reconnect_time=2)\n sb.uc_gui_handle_cf()\n sb.assert_element(\"img#captcha-success\", timeout=3)\n sb.set_messenger_theme(location=\"top_left\")\n sb.post_message(\"SeleniumBase wasn't detected\", duration=3)\n
If running on a Linux server, uc_gui_handle_cf()
might not be good enough. Switch to uc_gui_click_cf()
to be more stealthy. You can also use uc_gui_click_captcha()
as a generic CAPTCHA-clicker, which auto-detects between CF Turnstile and Google reCAPTCHA.
\ud83d\udc64 Here's an example where the CAPTCHA appears after submitting a form:
from seleniumbase import SB\n\nwith SB(uc=True, test=True, incognito=True, locale_code=\"en\") as sb:\n url = \"https://ahrefs.com/website-authority-checker\"\n input_field = 'input[placeholder=\"Enter domain\"]'\n submit_button = 'span:contains(\"Check Authority\")'\n sb.uc_open_with_reconnect(url, 2) # The bot-check is later\n sb.type(input_field, \"github.com/seleniumbase/SeleniumBase\")\n sb.reconnect(0.1)\n sb.uc_click(submit_button, reconnect_time=4)\n sb.uc_gui_click_captcha()\n sb.wait_for_text_not_visible(\"Checking\", timeout=10)\n sb.highlight('p:contains(\"github.com/seleniumbase/SeleniumBase\")')\n sb.highlight('a:contains(\"Top 100 backlinks\")')\n sb.set_messenger_theme(location=\"bottom_center\")\n sb.post_message(\"SeleniumBase wasn't detected!\")\n
\ud83d\udc64 Here, the CAPTCHA appears after clicking to go to the sign-in screen:
from seleniumbase import SB\n\nwith SB(uc=True, test=True, ad_block=True) as sb:\n url = \"https://www.thaiticketmajor.com/concert/\"\n sb.uc_open_with_reconnect(url, 6.111)\n sb.uc_click(\"button.btn-signin\", 4.1)\n sb.uc_gui_click_captcha()\n
\ud83d\udc64 On Linux, use sb.uc_gui_click_cf()
to handle Cloudflare Turnstiles:
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://www.virtualmanager.com/en/login\"\n sb.uc_open_with_reconnect(url, 4)\n print(sb.get_page_title())\n sb.uc_gui_click_cf() # Ready if needed!\n print(sb.get_page_title())\n sb.assert_element('input[name*=\"email\"]')\n sb.assert_element('input[name*=\"login\"]')\n sb.set_messenger_theme(location=\"bottom_center\")\n sb.post_message(\"SeleniumBase wasn't detected!\")\n
The 2nd print()
should output \"Virtual Manager\", which means that the automation successfully passed the Turnstile.
\ud83d\udc64 In UC Mode, driver.get(url)
has been modified from its original version: If anti-bot services are detected from a requests.get(url)
call that's made before navigating to the website, then driver.uc_open_with_reconnect(url)
will be used instead. To open a URL normally in UC Mode, use driver.default_get(url)
.
driver
-specific methods added by SeleniumBase for UC Mode: --uc
/ uc=True
", "text": "driver.uc_open(url)\n\ndriver.uc_open_with_tab(url)\n\ndriver.uc_open_with_reconnect(url, reconnect_time=None)\n\ndriver.uc_open_with_disconnect(url, timeout=None)\n\ndriver.reconnect(timeout)\n\ndriver.disconnect()\n\ndriver.connect()\n\ndriver.uc_click(\n selector, by=\"css selector\",\n timeout=settings.SMALL_TIMEOUT, reconnect_time=None)\n\ndriver.uc_gui_press_key(key)\n\ndriver.uc_gui_press_keys(keys)\n\ndriver.uc_gui_write(text)\n\ndriver.uc_gui_click_x_y(x, y, timeframe=0.25)\n\ndriver.uc_gui_click_captcha(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_handle_cf(frame=\"iframe\")\n\ndriver.uc_switch_to_frame(frame, reconnect_time=None)\n
(Note that the reconnect_time
is used to specify how long the driver should be disconnected from Chrome to prevent detection before reconnecting again.)
\ud83d\udc64 Since driver.get(url)
is slower in UC Mode for bypassing detection, use driver.default_get(url)
for a standard page load instead:
driver.default_get(url) # Faster, but Selenium can be detected\n
\ud83d\udc64 Here are some examples of using those special UC Mode methods: (Use self.driver
for BaseCase
formats. Use sb.driver
for SB()
formats):
url = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, reconnect_time=3)\ndriver.uc_open_with_reconnect(url, 3)\n\ndriver.reconnect(5)\ndriver.reconnect(timeout=5)\n
\ud83d\udc64 You can also set the reconnect_time
/ timeout
to \"breakpoint\"
as a valid option. This allows the user to perform manual actions (until typing c
and pressing ENTER
to continue from the breakpoint):
url = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, reconnect_time=\"breakpoint\")\ndriver.uc_open_with_reconnect(url, \"breakpoint\")\n\ndriver.reconnect(timeout=\"breakpoint\")\ndriver.reconnect(\"breakpoint\")\n
(Note that while the special UC Mode
breakpoint is active, you can't use Selenium
commands in the browser, and the browser can't detect Selenium
.)
\ud83d\udc64 On Linux, you may need to use driver.uc_gui_click_cf()
to successfully bypass a Cloudflare CAPTCHA. If there's more than one Cloudflare iframe on that website, then put the CSS Selector of an element that's above the iframe as the first arg to driver.uc_gui_click_cf()
. This method uses pyautogui
. In order for pyautogui
to focus on the correct element, use xvfb=True
/ --xvfb
to activate a special virtual display on Linux.
\ud83d\udc64 driver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False)
has three args. (All optional). The first one, frame
, lets you specify the iframe in case the CAPTCHA is not located in the first iframe on the page. The second one, retry
, lets you retry the click after reloading the page if the first one didn't work (and a CAPTCHA is still present after the page reload). The third arg, blind
, will retry after a page reload (if the first click failed) by clicking at the last known coordinates of the CAPTCHA checkbox without confirming first with Selenium that a CAPTCHA is still on the page.
\ud83d\udc64 driver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False)
is for reCAPTCHA. This may only work a few times before not working anymore... not because Selenium was detected, but because reCAPTCHA uses advanced AI to detect unusual activity, unlike the CF Turnstile, which only uses basic detection.
\ud83d\udc64 driver.uc_gui_click_captcha()
auto-detects the CAPTCHA type before trying to click it. This is a generic method for both CF Turnstile and Google reCAPTCHA. It will use the code from uc_gui_click_cf()
and uc_gui_click_rc()
as needed.
\ud83d\udc64 To find out if UC Mode will work at all on a specific site (before adjusting for timing), load your site with the following script:
from seleniumbase import SB\n\nwith SB(uc=True) as sb:\n sb.driver.uc_open_with_reconnect(URL, reconnect_time=\"breakpoint\")\n
(If you remain undetected while loading the page and performing manual actions, then you know you can create a working script once you swap the breakpoint with a time and add special methods like driver.uc_click
as needed.)
\ud83d\udc64 Multithreaded UC Mode:
If you're using pytest
for multithreaded UC Mode (which requires using one of the pytest
syntax formats), then all you have to do is set the number of threads when your script runs. (-n NUM
) Eg:
pytest --uc -n 4\n
(Then pytest-xdist
is automatically used to spin up and process the threads.)
If you don't want to use pytest
for multithreading, then you'll need to do a little more work. That involves using a different multithreading library, (eg. concurrent.futures
), and making sure that thread-locking is done correctly for processes that share resources. To handle that thread-locking, include sys.argv.append(\"-n\")
in your SeleniumBase file.
Here's a sample script that uses concurrent.futures
for spinning up multiple processes:
import sys\nfrom concurrent.futures import ThreadPoolExecutor\nfrom seleniumbase import Driver\nsys.argv.append(\"-n\") # Tell SeleniumBase to do thread-locking as needed\n\ndef launch_driver(url):\n driver = Driver(uc=True)\n try:\n driver.get(url=url)\n driver.sleep(2)\n finally:\n driver.quit()\n\nurls = ['https://seleniumbase.io/demo_page' for i in range(3)]\nwith ThreadPoolExecutor(max_workers=len(urls)) as executor:\n for url in urls:\n executor.submit(launch_driver, url)\n
\ud83d\udc64 What makes UC Mode work?
Here are the 3 primary things that UC Mode does to make bots appear human:
chromedriver
to rename Chrome DevTools Console variables.chromedriver
to them.chromedriver
from Chrome during stealthy actions.For example, if the Chrome DevTools Console variables aren't renamed, you can expect to find them easily when using selenium
for browser automation:
(If those variables are still there, then websites can easily detect your bots.)
If you launch Chrome using chromedriver
, then there will be settings that make your browser look like a bot. (Instead, UC Mode connects chromedriver
to Chrome after the browser is launched, which makes Chrome look like a normal, human-controlled web browser.)
While chromedriver
is connected to Chrome, website services can detect it. Thankfully, raw selenium
already includes driver.service.stop()
for stopping the chromedriver
service, driver.service.start()
for starting the chromedriver
service, and driver.start_session(capabilities)
for reviving the active browser session with the given capabilities. (SeleniumBase
UC Mode methods automatically use those raw selenium
methods as needed.)
Links to those raw Selenium method definitions have been provided for reference (but you don't need to call those methods directly):
driver.service.stop()
driver.service.start()
driver.start_session(capabilities)
Also note that chromedriver
isn't detectable in a browser tab if it never touches that tab. Here's a JS command that lets you open a URL in a new tab (from your current tab):
window.open(\"URL\");
--> (Info: W3Schools)The above JS method is used within SeleniumBase
UC Mode methods for opening URLs in a stealthy way. Since some websites try to detect if your browser is a bot on the initial page load, this allows you to bypass detection in those situations. After a few seconds (customizable), UC Mode tells chromedriver
to connect to that tab so that automated commands can now be issued. At that point, chromedriver
could be detected if websites are looking for it (but generally websites only look for it during specific events, such as page loads, form submissions, and button clicks).
Avoiding detection while clicking is easy if you schedule your clicks to happen at a future point when the chromedriver
service has been stopped. Here's a JS command that lets you schedule events (such as clicks) to happen in the future:
window.setTimeout(function() { SCRIPT }, MS);
--> (Info: W3Schools)The above JS method is used within the SeleniumBase
UC Mode method: driver.uc_click(selector)
so that clicking can be done in a stealthy way. UC Mode schedules your click, disconnects chromedriver
from Chrome, waits a little (customizable), and reconnects.
\ud83d\udee0\ufe0f Troubleshooting UC Mode
On Windows, the uc_gui_click_cf()
and uc_gui_click_captcha()
methods require \"Scaling\" to be set at \"100%\". (Note that \"100%\" may be different from the system's \"Recommended\" percent, which can be higher depending on your screen resolution and monitor size.)
As an alternative to using the uc_gui_click_cf()
or uc_gui_click_captcha()
methods on Windows, you can use sb.uc_gui_handle_cf()
, which does not require \"Scaling\" to be set to a specific value. Instead of using the mouse to click a CAPTCHA, sb.uc_gui_handle_cf()
uses a combination of the TAB
key and the SPACEBAR
.
\ud83c\udfc6 Choosing the right CAPTCHA service for your business / website:
As an ethical hacker / cybersecurity researcher who builds bots that bypass CAPTCHAs for sport, the CAPTCHA service that I personally recommend for keeping bots out is Google's reCAPTCHA:
Since Google makes Chrome, Google's own reCAPTCHA service has access to more data than other CAPTCHA services (eg. hCaptcha, CloudFlare, DataDome, etc.), and can therefore use that data to make better decisions about whether or not web activity is coming from real humans or automated bots.
\u2696\ufe0f Legal implications of web-scraping:
Based on the following article, https://nubela.co/blog/meta-lost-the-scraping-legal-battle-to-bright-data/, (which outlines a court case where social-networking company: Meta lost the legal battle to data-scraping company: Bright Data), it was determined that web scraping is 100% legal in the eyes of the courts as long as: 1. The scraping is only done with public data and not private data. 2. The scraping isn\u2019t done while logged in on the site being scraped.
If the above criteria are met, then scrape away! (According to the article)
(Note: I'm not a lawyer, so I can't officially offer legal advice, but I can direct people to existing articles online where people can find their own answers.)
"}, {"location": "help_docs/useful_grep_commands/", "title": "\ud83d\udcdc Useful grep commands", "text": ""}, {"location": "help_docs/useful_grep_commands/#useful-grep-commands", "title": "Useful grep commands", "text": "There are several useful grep commands for helping you find and/or replace text in multiple files. Examples:
"}, {"location": "help_docs/useful_grep_commands/#list-all-files-containing-selfget_new_driver-ignoring-pyc-files-from-the-current-directory", "title": "List all files containingself.get_new_driver(
, ignoring \".pyc\" files, from the current directory", "text": "grep -rl \"self.get_new_driver(\" * --exclude=\\*.pyc
OR grep -rl * -e \"self.get_new_driver(\" --exclude=\\*.pyc
To only search .py
files, use --include=\\*.py
:
grep -rl \"self.get_new_driver(\" * --include=\\*.py
sed -i 's/foo_abc/bar_xyz/g' *.py
sed -i '' 's/foo_abc/bar_xyz/g' *.py
ps
with grep
):", "text": "ps -ef |grep chromedriver
(NOTE: Safari's WebDriver requires macOS 10.13 \"High Sierra\" or later.)
You can find the official Apple documentation regarding \"Testing with WebDriver in Safari\" on the following page: https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari
Run safaridriver --enable
once in a terminal to enable Safari's WebDriver. (If you\u2019re upgrading from a previous macOS release, you may need to prefix the command with sudo
.)
Now you can use --safari
to run your SeleniumBase tests on Safari.
There are multiple ways of creating a Python virtual environment. This tutorial covers two of those:
venv
command (included with Python 3+).mkvirtualenv
command.venv
creates virtual environments in the location where run (generally with Python projects).
mkvirtualenv
creates virtual environments in one place (generally in your home directory).
(The Python Software Foundation recommends venv
for creating virtual environments.)
macOS/Linux terminal (python3 -m venv ENV
)
python3 -m venv sbase_env\nsource sbase_env/bin/activate\n
Windows CMD prompt (py -m venv ENV
):
py -m venv sbase_env\ncall sbase_env\\\\Scripts\\\\activate\n
To exit a virtual env, type deactivate
.
macOS/Linux terminal:
python3 -m pip install virtualenvwrapper --force-reinstall\nexport WORKON_HOME=$HOME/.virtualenvs\nsource `which virtualenvwrapper.sh`\n
(Shortcut: Run source virtualenv_install.sh
from the top-level SeleniumBase folder to perform the above steps.)
(If you add source `which virtualenvwrapper.sh`
to your local bash file (~/.bash_profile
on macOS, or ~/.bashrc
on Linux), virtualenvwrapper commands such as mkvirtualenv
will be available whenever you open a new command prompt.)
Windows CMD prompt:
py -m pip install virtualenvwrapper-win --force-reinstall --user\n
(Shortcut: Run win_virtualenv.bat
from the top-level SeleniumBase folder to perform the above step.)
mkvirtualenv ENV
:mkvirtualenv sbase_env\n
(If you have multiple versions of Python installed on your machine, and you want your virtual environment to use a specific Python version, add --python=PATH_TO_PYTHON_EXE
to your mkvirtualenv
command with the Python executable to use.)
Creating a virtual environment:
mkvirtualenv sbase_env\n
Leaving your virtual environment:
deactivate\n
Returning to a virtual environment:
workon sbase_env\n
Listing all virtual environments:
workon\n
Deleting a virtual environment:
rmvirtualenv sbase_env\n
If the python
and python3
versions don't match (while in a virtualenv on macOS or Linux), the following command will sync the versions:
alias python=python3\n
(To remove an alias, use: unalias NAME
)
To verify the python
version, use:
python --version\n
To see the PATH of your python
(macOS/Linux), use:
which python\n
python-guide.org/en/latest/dev/virtualenvs has more information about Python virtual environments. For specific details about VirtualEnv and VirtualEnvWrapper, see http://virtualenv.readthedocs.org/en/latest/ and http://virtualenvwrapper.readthedocs.org/en/latest/.
"}, {"location": "integrations/azure/azure_pipelines/ReadMe/", "title": "\ud83e\udd16 Azure Pipelines", "text": ""}, {"location": "integrations/azure/azure_pipelines/ReadMe/#running-browser-based-test-automation-with-azure-pipelines-by-using-seleniumbase", "title": "Running browser-based test automation with Azure Pipelines by using SeleniumBase", "text": ""}, {"location": "integrations/azure/azure_pipelines/ReadMe/#step-0-fork-the-seleniumbase-repo-on-github-to-get-started-quickly", "title": "Step 0. Fork the SeleniumBase repo on GitHub to get started quickly.", "text": "Navigate to https://azure.microsoft.com/en-us/services/devops/?nav=min
Follow the steps...
https://dev.azure.com/seleniumbase/seleniumbase/_build/results?buildId=234
"}, {"location": "integrations/azure/azure_pipelines/ReadMe/#every-time-you-create-a-pull-request-now-azure-pipelines-will-run-your-tests-automatically", "title": "Every time you create a pull request now, Azure Pipelines will run your tests automatically.", "text": "To learn more, study SeleniumBase and see how the azure-pipelines.yml file works.
"}, {"location": "integrations/azure/jenkins/ReadMe/", "title": "\ud83e\udd16 Jenkins on Azure", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#building-a-browser-based-test-automation-server-with-jenkins-on-azure-by-using-seleniumbase", "title": "Building a browser-based test automation server with Jenkins on Azure by using SeleniumBase", "text": "(2022 NOTE: Steps from this 2019 tutorial from Boston Code Camp are now out-of-date. For installing Jenkins from the Azure Marketplace, you can try using Bitnami Jenkins. Or, for the newer official Microsoft tutorial, see Get Started: Install Jenkins on an Azure Linux VM, and then continue with Step 4 below to resume SeleniumBase setup after you've created your Jenkins instance.)
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-0-fork-the-seleniumbase-repo-on-github-to-get-started-quickly", "title": "Step 0. Fork the SeleniumBase repo on GitHub to get started quickly.", "text": "Jenkins (Publisher: Microsoft)
result to get to the Jenkins Start page.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-2-launch-a-jenkins-instance", "title": "Step 2. Launch a Jenkins instance", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#click-create-and-follow-the-steps", "title": "Click \"Create\" and follow the steps...", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#continue-to-additional-settings-when-youre-done-with-basics", "title": "Continue to \"Additional Settings\" when you're done with \"Basics\".", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#on-the-additional-settings-section-set-the-size-to-b2s", "title": "On the \"Additional Settings\" section, set the Size to \"B2s\":", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-youve-reached-step-5-click-create-to-complete-the-setup", "title": "Once you've reached Step 5, click \"Create\" to complete the setup.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-3-inspect-your-new-jenkins-instance-to-ssh-into-the-new-machine", "title": "Step 3. Inspect your new Jenkins instance to SSH into the new machine", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-your-new-jenkins-instance-has-finished-launching-you-should-be-able-to-see-the-main-page", "title": "Once your new Jenkins instance has finished launching, you should be able to see the main page", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#on-the-main-page-you-should-be-able-to-find-the-public-ip-address", "title": "On the main page, you should be able to find the Public IP Address.", "text": "ssh USERNAME@IP_ADDRESS\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-4-clone-the-seleniumbase-repository-from-the-root-directory", "title": "Step 4. Clone the SeleniumBase repository from the root (\"/\") directory.", "text": "cd /\nsudo git clone https://github.com/seleniumbase/SeleniumBase.git\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-5-enter-the-linux-folder", "title": "Step 5. Enter the \"linux\" folder", "text": "cd SeleniumBase/integrations/linux/\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-6-give-the-jenkins-user-sudo-access-see-jenkins_permissionssh-for-details", "title": "Step 6. Give the \"jenkins\" user sudo access (See jenkins_permissions.sh for details)", "text": "./jenkins_permissions.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-7-become-the-jenkins-user-and-enter-a-bash-shell", "title": "Step 7. Become the \"jenkins\" user and enter a \"bash\" shell", "text": "sudo su jenkins\nbash\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-8-install-dependencies-see-linuxfilesh-for-details", "title": "Step 8. Install dependencies (See Linuxfile.sh for details)", "text": "./Linuxfile.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-9-start-up-the-headless-browser-display-mechanism-xvfb-see-xvfb_launchersh-for-details", "title": "Step 9. Start up the headless browser display mechanism: Xvfb (See Xvfb_launcher.sh for details)", "text": "./Xvfb_launcher.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-10-go-to-the-seleniumbase-directory", "title": "Step 10. Go to the SeleniumBase directory", "text": "cd /SeleniumBase\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-11-install-the-requirements-for-seleniumbase", "title": "Step 11. Install the requirements for SeleniumBase", "text": "sudo pip install -r requirements.txt --upgrade\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-12-install-seleniumbase-make-sure-you-already-installed-the-requirements-above", "title": "Step 12. Install SeleniumBase (Make sure you already installed the requirements above)", "text": "sudo python setup.py develop\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-13-install-chromedriver", "title": "Step 13. Install chromedriver", "text": "sudo seleniumbase install chromedriver\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-14-run-an-example-test-in-chrome-to-verify-installation-may-take-up-to-10-seconds", "title": "Step 14. Run an example test in Chrome to verify installation (May take up to 10 seconds)", "text": "pytest examples/my_first_test.py --headless --browser=chrome\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-15-secure-your-jenkins-machine", "title": "Step 15. Secure your Jenkins machine", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#navigate-to-httpjenkins_ip_addressjenkins-on-azure", "title": "Navigate to http://JENKINS_IP_ADDRESS/jenkins-on-azure/", "text": "(Depending on your version of Jenkins, you may see the following screen, or nothing at all.)
"}, {"location": "integrations/azure/jenkins/ReadMe/#initially-jenkins-uses-only-http-which-makes-it-less-secure", "title": "Initially, Jenkins uses onlyhttp
, which makes it less secure.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#youll-need-to-set-up-ssh-port-forwarding-in-order-to-secure-it", "title": "You'll need to set up SSH Port Forwarding in order to secure it.", "text": "ssh -L 127.0.0.1:8080:localhost:8080 USERNAME@DNS_NAME
http://127.0.0.1:8080/
", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#youll-need-to-get-the-password-from-the-ssh-terminal-on-the-linux-machine-to-log-in", "title": "You'll need to get the password from the SSH terminal on the Linux machine to log in", "text": "sudo cat /var/lib/jenkins/secrets/initialAdminPassword\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-17-customize-jenkins", "title": "Step 17. Customize Jenkins", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-18-create-an-admin-user", "title": "Step 18. Create an Admin user", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-jenkins-has-finished-loading-the-top-left-of-the-page-should-look-like-this", "title": "Once Jenkins has finished loading, the top left of the page should look like this", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-19-create-a-new-jenkins-job", "title": "Step 19. Create a new Jenkins job", "text": "https://github.com/seleniumbase/SeleniumBase.git
. (You'll eventually be using your own clone of the repository here.)cd examples\npytest my_first_test.py --headless\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#click-save-when-youre-done", "title": "Click \"Save\" when you're done.", "text": "If you have a web application that you want to test, you'll be able to create SeleniumBase tests and add them to Jenkins as you saw here. You may want to create a Deploy job, which downloads the latest version of your repository, and then kicks off all tests to run after that. You could then tell that Deploy job to auto-run whenever a change is pushed to your repository by using: \"Poll SCM\". All your tests would then be able to run by using: \"Build after other projects are built\".
"}, {"location": "integrations/azure/jenkins/ReadMe/#congratulations-youre-now-well-on-your-way-to-becoming-a-build-release-automation-engineer", "title": "Congratulations! You're now well on your way to becoming a build & release / automation engineer!", "text": ""}, {"location": "integrations/docker/ReadMe/", "title": "\ud83d\udc33 Docker Start Guide", "text": ""}, {"location": "integrations/docker/ReadMe/#docker-setup-instructions-for-seleniumbase", "title": "Docker setup instructions for SeleniumBase", "text": ""}, {"location": "integrations/docker/ReadMe/#1-install-the-docker-desktop", "title": "1. Install the Docker Desktop", "text": "You can get that from here: https://www.docker.com/products/docker-desktop/
You might also want to install the Docker Engine: https://docs.docker.com/engine/install/
"}, {"location": "integrations/docker/ReadMe/#2-go-to-the-seleniumbase-home-directory-on-the-command-line-which-is-where-dockerfile-is-located-this-assumes-youve-already-cloned-the-seleniumbase-repo", "title": "2. Go to the SeleniumBase home directory on the command line, which is where Dockerfile is located. (This assumes you've already cloned the SeleniumBase repo.)", "text": ""}, {"location": "integrations/docker/ReadMe/#3-create-your-docker-image-from-your-dockerfile-get-ready-to-wait-awhile", "title": "3. Create your Docker image from your Dockerfile: (Get ready to wait awhile)", "text": "docker build -t seleniumbase .\n
If running on an Apple M1/M2 Mac, use this instead:
docker build --platform linux/amd64 -t seleniumbase .\n
M1/M2 Mac users should also see StackOverflow.com/a/76586216/7058266 to Enable Rosetta in Docker Desktop. (Otherwise you will encounter errors like this when Chrome tries to launch: \"Chrome failed to start: crashed.\"
)
docker run seleniumbase ./run_docker_test_in_chrome.sh\n
"}, {"location": "integrations/docker/ReadMe/#5-you-can-also-enter-docker-and-stay-inside-the-shell", "title": "5. You can also enter Docker and stay inside the shell", "text": "docker run -i -t seleniumbase\n
"}, {"location": "integrations/docker/ReadMe/#6-now-you-can-run-the-example-test-from-inside-the-docker-shell", "title": "6. Now you can run the example test from inside the Docker shell", "text": "./run_docker_test_in_chrome.sh\n
"}, {"location": "integrations/docker/ReadMe/#7-when-youre-satisfied-you-may-exit-the-docker-shell", "title": "7. When you're satisfied, you may exit the Docker shell", "text": "exit\n
"}, {"location": "integrations/docker/ReadMe/#8-optional-since-docker-images-and-containers-take-up-a-lot-of-space-you-may-want-to-clean-up-your-machine-from-time-to-time-when-theyre-not-being-used", "title": "8. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they\u2019re not being used", "text": "Details on that can be found here: http://stackoverflow.com/questions/17236796/how-to-remove-old-docker-containers
Here are a few of those cleanup commands:
docker container prune\ndocker system prune\ndocker images | grep \"<none>\" | awk '{print $3}' | xargs docker rmi\ndocker rm 'docker ps --no-trunc -aq'\n
If you want to completely remove all of your Docker containers and images, use these commands: (If there's nothing to delete, those commands will return an error.)
docker rm -f $(docker ps -a -q)\ndocker rmi -f $(docker images -q)\n
For more cleanup commands, check out: https://codefresh.io/blog/everyday-hacks-docker/
"}, {"location": "integrations/docker/ReadMe/#9-optional-more-reading-on-docker-can-be-found-here", "title": "9. (Optional) More reading on Docker can be found here", "text": ".yml
script.", "text": "master
branch.", "text": "(This tutorial, from a previous Google Cloud Meetup, will teach you how to setup a Linux server for running automated browser tests. The cost of running this server is about $13.60/month on Google Cloud (enough to handle 5 parallel tests). This is less expensive than using other platforms.)
"}, {"location": "integrations/google_cloud/ReadMe/#step-1-open-the-google-cloud-platform-cloud-launcher", "title": "Step 1. Open the Google Cloud Platform Cloud Launcher", "text": "cd /\nsudo git clone https://github.com/seleniumbase/SeleniumBase.git\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-5-enter-the-linux-folder", "title": "Step 5. Enter the \"linux\" folder", "text": "cd SeleniumBase/integrations/linux/\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-6-give-jenkins-aka-tomcat-user-sudo-access-see-tomcat_permissionssh-for-details", "title": "Step 6. Give Jenkins (aka \"tomcat\" user) sudo access (See tomcat_permissions.sh for details)", "text": "./tomcat_permissions.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-7-become-tomcat-the-jenkins-user-and-enter-a-bash-shell", "title": "Step 7. Become \"tomcat\" (the Jenkins user) and enter a \"bash\" shell", "text": "sudo su tomcat\nbash\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-8-install-dependencies-see-linuxfilesh-for-details", "title": "Step 8. Install dependencies (See Linuxfile.sh for details)", "text": "./Linuxfile.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-9-start-up-the-headless-browser-display-mechanism-xvfb-see-xvfb_launchersh-for-details", "title": "Step 9. Start up the headless browser display mechanism: Xvfb (See Xvfb_launcher.sh for details)", "text": "./Xvfb_launcher.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-10-go-to-the-seleniumbase-directory", "title": "Step 10. Go to the SeleniumBase directory", "text": "cd /SeleniumBase\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-11-install-the-requirements-for-seleniumbase", "title": "Step 11. Install the requirements for SeleniumBase", "text": "sudo pip install -r requirements.txt --upgrade\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-12-install-seleniumbase", "title": "Step 12. Install SeleniumBase", "text": "sudo python setup.py develop\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-13-run-an-example-test-on-chrome-to-verify-installation-may-take-up-to-10-seconds", "title": "Step 13. Run an example test on Chrome to verify installation (May take up to 10 seconds)", "text": "pytest examples/my_first_test.py --headless\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-14-if-you-prefer-using-nosetests-that-works-too", "title": "Step 14. If you prefer using nosetests, that works too", "text": "nosetests examples/my_first_test.py --headless\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-15-you-can-also-verify-that-the-example-test-runs-on-firefox", "title": "Step 15. You can also verify that the example test runs on Firefox", "text": "pytest examples/my_first_test.py --headless --browser=firefox\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-16-login-to-jenkins", "title": "Step 16. Login to Jenkins", "text": "https://github.com/seleniumbase/SeleniumBase.git
. (You'll eventually be using your own clone of the repository here.)pytest examples/my_first_test.py --headless\n
If you have a web application that you want to test, you'll be able to create SeleniumBase tests and add them to Jenkins as you saw here. You may want to create a Deploy job, which downloads the latest version of your repository, and then kicks off all tests to run after that. You could then tell that Deploy job to auto-run whenever a change is pushed to your repository by using: \"Poll SCM\". All your tests would then be able to run by using: \"Build after other projects are built\". You can also use MySQL to save test results in the DB so that you can query the data at any time.
"}, {"location": "integrations/google_cloud/ReadMe/#congratulations-youre-now-well-on-your-way-to-becoming-a-build-release-automation-engineer", "title": "Congratulations! You're now well on your way to becoming a build & release / automation engineer!", "text": ""}, {"location": "integrations/google_cloud/ReadMe/#mysql-db-setup-instructions", "title": "MySQL DB setup instructions", "text": ""}, {"location": "integrations/google_cloud/ReadMe/#step-21-return-to-the-google-cloud-launcher-and-launch-a-mysql-instance", "title": "Step 21. Return to the Google Cloud Launcher and launch a MySQL Instance", "text": "test_db
.pytest examples/test_suite.py --headless --with-db_reporting\n
@print_runtime(description=None, limit=None)
@runtime_limit(limit, description=None)
@retry_on_exception(tries=6, delay=1, backoff=2, max_delay=32)
@rate_limited(max_per_second)
Example demonstrating a rate-limited printing functionality:
import unittest\nfrom seleniumbase import decorators\n\nclass MyTestClass(unittest.TestCase):\n\n @decorators.rate_limited(3.5) # The arg is max calls per second\n def print_item(self, item):\n print(item)\n\n def test_rate_limited_printing(self):\n print(\"\\nRunning rate-limited print test:\")\n for item in range(1, 11):\n self.print_item(item)\n
"}, {"location": "seleniumbase/common/ReadMe/#part-2-stringpassword-obfuscation-encryption-and-decryption", "title": "Part 2: String/Password Obfuscation, Encryption, and Decryption", "text": ""}, {"location": "seleniumbase/common/ReadMe/#intro", "title": "Intro", "text": "Often in your tests, you may need to login to a website to perform testing. This generally means storing passwords in plaintext formats. For security reasons, that may not be an optimal solution. For this reason, encryption/obfuscation tools have been built here to help you mask your passwords in your tests. It's not a bulletproof solution, but it can keep anyone looking over your shoulder during test creation from getting your login passwords if they don't have your encryption key, which is stored in a separate file.
"}, {"location": "seleniumbase/common/ReadMe/#usage", "title": "Usage", "text": "First, set your custom encryption/decryption key in your local clone of settings.py. (If you modify the key later, you'll need to encrypt all your passwords again.)
Next, use obfuscate.py to obfuscate/encrypt passwords into coded strings:
python obfuscate.py\n\nEnter password to obfuscate: (CTRL+C to exit)\nPassword: *********\nVerify password:\nPassword: *********\n\nHere is the obfuscated password:\n$^*ENCRYPT=RXlYMSJWTz8HSwM=?&#$\n
(You can also use unobfuscate.py to encrypt passwords without having them masked while typing them. Or you can use it to decrypt an obfuscated password.)
from seleniumbase import encryption\n...\npassword = encryption.decrypt('$^*ENCRYPT=RXlYMSJWTz8HSwM=?&#$')\n
(You'll notice that encrypted strings have a common start token and end token. This is to help tell them apart from non-encrypted strings. You can customize these tokens in settings.py. The current default setting is $^*ENCRYPT=
for the start token and ?&#$
for the end token.)
See decryption_test.py for an example of decrypting encrypted passwords in tests.
"}, {"location": "seleniumbase/console_scripts/ReadMe/", "title": "\ud83c\udf20 Console Scripts", "text": ""}, {"location": "seleniumbase/console_scripts/ReadMe/#console-scripts", "title": "Console Scripts \ud83c\udf20", "text": "\ud83c\udf1f SeleniumBase console scripts can do many things, such as downloading web drivers, creating test directories with config files, activating the SeleniumBase Recorder, launching the SeleniumBase Commander, translating tests into other languages, running a Selenium Grid, and more.
Usage: seleniumbase [COMMAND] [PARAMETERS]
(simplified): sbase [COMMAND] [PARAMETERS]
To list all commands: seleniumbase --help
(For running tests, use pytest with SeleniumBase.)
COMMANDS:\n get / install [DRIVER] [OPTIONS]\n methods (List common Python methods)\n options (List common pytest options)\n behave-options (List common behave options)\n gui / commander [OPTIONAL PATH or TEST FILE]\n behave-gui (SBase Commander for Behave)\n caseplans [OPTIONAL PATH or TEST FILE]\n mkdir [DIRECTORY] [OPTIONS]\n mkfile [FILE.py] [OPTIONS]\n mkrec / codegen [FILE.py] [OPTIONS]\n recorder (Open Recorder Desktop App.)\n record (If args: mkrec. Else: App.)\n mkpres [FILE.py] [LANG]\n mkchart [FILE.py] [LANG]\n print [FILE] [OPTIONS]\n translate [SB_FILE.py] [LANG] [ACTION]\n convert [WEBDRIVER_UNITTEST_FILE.py]\n extract-objects [SB_FILE.py]\n inject-objects [SB_FILE.py] [OPTIONS]\n objectify [SB_FILE.py] [OPTIONS]\n revert-objects [SB_FILE.py] [OPTIONS]\n encrypt / obfuscate\n decrypt / unobfuscate\n proxy (Start a basic proxy server)\n download server (Get Selenium Grid JAR file)\n grid-hub [start|stop] [OPTIONS]\n grid-node [start|stop] --hub=[HOST/IP]\n * (EXAMPLE: \"sbase get chromedriver\") *\n\n Type \"sbase help [COMMAND]\" for specific command info.\n For info on all commands, type: \"seleniumbase --help\".\n Use \"pytest\" for running tests.\n
get / install sbase get [DRIVER] [OPTIONS]\nsbase install [DRIVER] [OPTIONS]\n
sbase get chromedriver\nsbase get geckodriver\nsbase get edgedriver\nsbase get chromedriver 114\nsbase get chromedriver 114.0.5735.90\nsbase get chromedriver stable\nsbase get chromedriver beta\nsbase get chromedriver -p\n
(Drivers: chromedriver
, geckodriver
, edgedriver
, iedriver
, uc_driver
)
(Options: A specific driver version or major version integer. If not set, the driver version matches the browser. -p
/ --path
: Also copy to \"/usr/local/bin\".)
Downloads the webdriver to seleniumbase/drivers/
(chromedriver
is required for Chrome automation) (geckodriver
is required for Firefox automation) (edgedriver
is required for MS__Edge automation)
sbase methods\n
Displays common SeleniumBase Python methods.
optionssbase options\n
Displays common pytest command-line options that are available when using SeleniumBase.
--browser=BROWSER (The web browser to use. Default is \"chrome\")\n--edge / --firefox / --safari (Shortcut for browser selection.)\n--headless (Run tests headlessly. Default mode on Linux OS.)\n--demo (Slow down and visually see test actions as they occur.)\n--slow (Slow down the automation. Faster than using Demo Mode.)\n--rs / --reuse-session (Reuse browser session between tests.)\n--crumbs (Clear all cookies between tests reusing a session.)\n--maximize (Start tests with the web browser window maximized.)\n--dashboard (Enable SeleniumBase\\'s Dashboard at dashboard.html)\n--incognito (Enable Chromium\\'s Incognito mode.)\n--guest (Enable Chromium\\'s Guest Mode.)\n--dark (Enable Chromium\\'s Dark Mode.)\n--uc (Use undetected-chromedriver to evade detection.)\n-m=MARKER (Run tests with the specified pytest marker.)\n-n=NUM (Multithread the tests using that many threads.)\n-v (Verbose mode. Print the full names of each test run.)\n--html=report.html (Create a detailed pytest-html report.)\n--collect-only / --co (Only show discovered tests. No run.)\n--co -q (Only show full names of discovered tests. No run.)\n-x (Stop running tests after the first failure is reached.)\n--pdb (Enter the Post Mortem Debug Mode after any test fails.)\n--trace (Enter Debug Mode immediately after starting any test.)\n | Debug Mode Commands >>> help / h: List all commands. |\n | n: Next line of method. s: Step through. c: Continue. |\n | return / r: Run until method returns. j: Jump to line. |\n | where / w: Show stack spot. u: Up stack. d: Down stack. |\n | longlist / ll: See code. dir(): List namespace objects. |\n--help / -h (Display list of all available pytest options.)\n--final-debug (Enter Final Debug Mode after each test ends.)\n--recorder / --rec (Save browser actions as Python scripts.)\n--rec-behave / --rec-gherkin (Save actions as Gherkin code.)\n--rec-print (Display recorded scripts when they are created.)\n--save-screenshot (Save a screenshot at the end of each test.)\n--archive-logs (Archive old log files instead of deleting them.)\n--check-js (Check for JavaScript errors after page loads.)\n--start-page=URL (The browser start page when tests begin.)\n--agent=STRING (Modify the web browser\\'s User-Agent string.)\n--mobile (Use Chromium\\'s mobile device emulator during tests.)\n--metrics=STRING (Set mobile \"CSSWidth,CSSHeight,PixelRatio\".)\n--ad-block (Block some types of display ads after page loads.)\n--settings-file=FILE (Override default SeleniumBase settings.)\n--env=ENV (Set the test env. Access with \"self.env\" in tests.)\n--data=DATA (Extra test data. Access with \"self.data\" in tests.)\n--disable-csp (Disable the Content Security Policy of websites.)\n--remote-debug (Sync to Ch-R-Debugger chrome://inspect/#devices)\n--server=SERVER (The Selenium Grid server/IP used for tests.)\n--port=PORT (The Selenium Grid port used by the test server.)\n--proxy=SERVER:PORT (Connect to a proxy server:port for tests.)\n--proxy=USER:PASS@SERVER:PORT (Use authenticated proxy server.)\n\nFor the full list of command-line options, type: \"pytest --help\".\n
behave-options sbase behave-options\n
Displays common Behave command-line options that are available when using SeleniumBase.
-D browser=BROWSER (The web browser to use. Default is \"chrome\")\n-D headless (Run tests headlessly. Default mode on Linux OS.)\n-D demo (Slow down and visually see test actions as they occur.)\n-D slow (Slow down the automation. Faster than using Demo Mode.)\n-D reuse-session / -D rs (Reuse browser session between tests.)\n-D crumbs (Clear all cookies between tests reusing a session.)\n-D maximize (Start tests with the web browser window maximized.)\n-D dashboard (Enable SeleniumBase\\'s Dashboard at dashboard.html)\n-D incognito (Enable Chromium\\'s Incognito Mode.)\n-D guest (Enable Chromium\\'s Guest Mode.)\n-D dark (Enable Chromium\\'s Dark Mode.)\n-D uc (Use undetected-chromedriver to evade detection.)\n--no-snippets / -q (Quiet mode. Don\\'t print snippets.)\n--dry-run / -d (Dry run. Only show discovered tests.)\n--stop (Stop running tests after the first failure is reached.)\n-D pdb (Enter the Post Mortem Debug Mode after any test fails.)\n | Debug Mode Commands >>> help / h: List all commands. |\n | n: Next line of method. s: Step through. c: Continue. |\n | return / r: Run until method returns. j: Jump to line. |\n | where / w: Show stack spot. u: Up stack. d: Down stack. |\n | longlist / ll: See code. dir(): List namespace objects. |\n-D recorder (Record browser actions to generate test scripts.)\n-D rec-print (Display recorded scripts when they are created.)\n-D save-screenshot (Save a screenshot at the end of each test.)\n-D archive-logs (Archive old log files instead of deleting them.)\n-D check-js (Check for JavaScript errors after page loads.)\n-D start-page=URL (The browser start page when tests begin.)\n-D agent=STRING (Modify the web browser\\'s User-Agent string.)\n-D mobile (Use Chromium\\'s mobile device emulator during tests.)\n-D metrics=STRING (Set mobile \"CSSWidth,CSSHeight,PixelRatio\".)\n-D ad-block (Block some types of display ads after page loads.)\n-D settings-file=FILE (Override default SeleniumBase settings.)\n-D env=ENV (Set the test env. Access with \"self.env\" in tests.)\n-D data=DATA (Extra test data. Access with \"self.data\" in tests.)\n-D disable-csp (Disable the Content Security Policy of websites.)\n-D remote-debug (Sync to Ch-R-Debugger chrome://inspect/#devices)\n-D server=SERVER (The Selenium Grid server/IP used for tests.)\n-D port=PORT (The Selenium Grid port used by the test server.)\n-D proxy=SERVER:PORT (Connect to a proxy server:port for tests.)\n-D proxy=USER:PASS@SERVER:PORT (Use authenticated proxy server.)\n\nFor the full list of command-line options, type: \"behave --help\".\n
gui / commander sbase gui [OPTIONAL PATH or TEST FILE]\nsbase commander [OPTIONAL PATH or TEST FILE]\n
behave-gui sbase behave-gui [OPTIONAL PATH or TEST FILE]\nsbase gui-behave [OPTIONAL PATH or TEST FILE]\n
sbase behave-gui\nsbase behave-gui -i=calculator\nsbase behave-gui features/\nsbase behave-gui features/calculator.feature\n
Launches SeleniumBase Commander / GUI for Behave.
caseplanssbase caseplans [OPTIONAL PATH or TEST FILE]\n
sbase caseplans\nsbase caseplans -k agent\nsbase caseplans -m marker2\nsbase caseplans test_suite.py\nsbase caseplans offline_examples/\n
Launches the SeleniumBase Case Plans Generator.
mkdirsbase mkdir [DIRECTORY] [OPTIONS]\n
sbase mkdir ui_tests\n
-b
/ --basic
(Only config files. No tests added.)
Creates a new folder for running SBase scripts. The new folder contains default config files, sample tests for helping new users get started, and Python boilerplates for setting up customized test frameworks.
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 my_first_test.py\n\u251c\u2500\u2500 parameterized_test.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 test_demo_site.py\n\u2514\u2500\u2500 boilerplates/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 base_test_case.py\n \u251c\u2500\u2500 boilerplate_test.py\n \u251c\u2500\u2500 classic_obj_test.py\n \u251c\u2500\u2500 page_objects.py\n \u251c\u2500\u2500 sb_fixture_test.py\n \u2514\u2500\u2500 samples/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 google_objects.py\n \u251c\u2500\u2500 google_test.py\n \u251c\u2500\u2500 sb_swag_test.py\n \u2514\u2500\u2500 swag_labs_test.py\n
If running with the -b
or --basic
option:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u2514\u2500\u2500 setup.cfg\n
mkfile sbase mkfile [FILE.py] [OPTIONS]\n
sbase mkfile new_test.py\n
-b
/ --basic
(Basic boilerplate / single-line test) -r
/ --rec
(adds Pdb+ breakpoint for Recorder Mode) --url=URL
(makes the test start on a specific page)
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
--bc
/ --basecase
(BaseCase class inheritance) --pf
/ --pytest-fixture
(sb pytest fixture) --cf
/ --class-fixture
(class + sb pytest fixture) --cm
/ --context-manager
(SB context manager) --dc
/ --driver-context
(DriverContext manager) --dm
/ --driver-manager
(Driver manager)
Creates a new SBase test file with boilerplate code. If the file already exists, an error is raised. By default, uses English with BaseCase inheritance, and creates a boilerplate with common SeleniumBase methods: \"open\", \"type\", \"click\", \"assert_element\", and \"assert_text\". If using the basic boilerplate option, only the \"open\" method is included. Only the BaseCase format supports Languages or Recorder Mode.
mkrec / record / codegensbase mkrec [FILE.py] [OPTIONS]\nsbase codegen [FILE.py] [OPTIONS]\n
sbase mkrec new_test.py\nsbase mkrec new_test.py --url=seleniumbase.io\nsbase codegen new_test.py\nsbase codegen new_test.py --url=wikipedia.org\n
--url=URL
(Sets the initial start page URL.) --edge
(Use Edge browser instead of Chrome.) --gui
/ --headed
(Use headed mode on Linux.) --uc
/ --undetected
(Use undetectable mode.) --ee
(Use SHIFT + ESC to end the recording.) --overwrite
(Overwrite file when it exists.) --behave
(Also output Behave/Gherkin files.)
Creates a new SeleniumBase test using the Recorder. If the filename already exists, an error is raised.
recordersbase recorder [OPTIONS]\n
--uc
/ --undetected
(Use undetectable mode.) --behave
(Also output Behave/Gherkin files.)
Launches the SeleniumBase Recorder Desktop App.
mkpressbase mkpres [FILE.py] [LANG]\n
sbase mkpres new_presentation.py --en\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
Creates a new presentation with 3 example slides. If the file already exists, an error is raised. By default, the slides are written in English, and use \"serif\" theme with \"slide\" transition. The slides can be used as a basic boilerplate.
mkchartsbase mkchart [FILE.py] [LANG]\n
sbase mkchart new_chart.py --en\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
Creates a new SeleniumBase chart presentation. If the file already exists, an error is raised. By default, the slides are written in English, and use a \"sky\" theme with \"slide\" transition. The chart can be used as a basic boilerplate.
printsbase print [FILE] [OPTIONS]\n
-n
(Add line Numbers to the rows)
Prints the code/text of any file with syntax-highlighting.
translatesbase translate [SB_FILE.py] [LANGUAGE] [ACTION]\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
-p
/ --print
(Print translation output to the screen) -o
/ --overwrite
(Overwrite the file being translated) -c
/ --copy
(Copy the translation to a new .py
file)
-n
(include line Numbers when using the Print action)
Translates a SeleniumBase Python file into the language specified. Method calls and \"import\" lines get swapped. Both a language and an action must be specified. The -p
action can be paired with one other action. When running with -c
(or --copy
), the new file name will be the original name appended with an underscore plus the 2-letter language code of the new language. (Example: Translating \"test_1.py\" into Japanese with -c
will create a new file called \"test_1_ja.py\".)
sbase extract-objects [SB_FILE.py]\n
Creates page objects based on selectors found in a seleniumbase Python file and saves those objects to the \"page_objects.py\" file in the same folder as the tests.
inject-objectssbase inject-objects [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Add object selectors to the comments.)
Takes the page objects found in the \"page_objects.py\" file and uses those to replace matching selectors in the selected seleniumbase Python file.
objectifysbase objectify [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Add object selectors to the comments.)
A modified version of the file where the selectors have been replaced with variable names defined in \"page_objects.py\", supporting the Page Object Pattern. (This has the same outcome as combining extract-objects
with inject-objects
)
sbase revert-objects [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Keep existing comments for the lines.)
Reverts the changes made by seleniumbase objectify ...
or seleniumbase inject-objects ...
when run against a seleniumbase Python file. Objects will get replaced by selectors stored in the \"page_objects.py\" file.
sbase convert [WEBDRIVER_UNITTEST_FILE.py]\n
Converts a Selenium IDE exported WebDriver unittest file into a SeleniumBase file. Adds _SB
to the new filename while keeping the original file intact. Works on both Selenium IDE & Katalon Recorder scripts.
sbase encrypt
OR sbase obfuscate
Runs the password encryption/obfuscation tool. (Where you can enter a password to encrypt/obfuscate.)
decrypt / unobfuscatesbase decrypt
OR sbase unobfuscate
Runs the password decryption/unobfuscation tool. (Where you can enter an encrypted password to decrypt.)
proxysbase proxy [OPTIONS]\n
--hostname=HOSTNAME
(Set hostname
) (Default: 127.0.0.1
) --port=PORT
(Set port
) (Default: 8899
) --help
/ -h
(Display list of all available proxy
options.)
Launch a basic proxy server on the current machine. (Uses 127.0.0.1:8899
as the default address.)
sbase download server\n
Downloads the Selenium Server JAR file for Grid usage. (That JAR file is required when using a Selenium Grid)
grid-hubsbase grid-hub {start|stop|restart} [OPTIONS]\n
-v
, --verbose
(Increases verbosity of logging output.) --timeout=TIMEOUT
(Close idle browser windows after TIMEOUT seconds.)
Controls the Selenium Grid Hub server, which allows for running tests on multiple machines in parallel to speed up test runs and reduce the total time of test suite execution. You can start, restart, or stop the Grid Hub server.
grid-nodesbase grid-node {start|stop|restart} [OPTIONS]\n
--hub=HUB_IP
(The Grid Hub IP Address to connect to.) (Default: 127.0.0.1
) -v
, --verbose
(Increases verbosity of logging output.)
Controls the Selenium Grid node, which serves as a worker machine for your Selenium Grid Hub server. You can start, restart, or stop the Grid node.
"}, {"location": "seleniumbase/utilities/selenium_grid/ReadMe/", "title": "\ud83c\udf10 Selenium Grid", "text": "The Selenium Grid Hub:The Selenium Grid Hub lets you distribute tests to run in parallel across multiple node machines. Each node machine can then run its own allocation of tests. This allows you to run a large suite of tests very quickly.
Running the Selenium Grid Hub:The following commands will work once you've installed seleniumbase.
Downloading the Selenium Server JAR file:seleniumbase download server\n
seleniumbase grid-hub {start|stop|restart} [OPTIONS]\n
Options:
seleniumbase grid-node {start|stop|restart} --hub=[HUB_IP] [OPTIONS]\n
Options:
When the Grid Hub Console is up and running, you'll be able to find it here: http://127.0.0.1:4444/grid/console
Now you can run your tests on the Selenium Grid:
pytest test_demo_site.py --server=IP_ADDRESS --port=4444\n
You can also run your tests on someone else's Selenium Grid to avoid managing your own. Here are some Selenium Grids that you can use (and the run command format):
pytest test_demo_site.py --server=USERNAME:KEY@hub.browserstack.com --port=80\n
pytest test_demo_site.py --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https\n
pytest test_demo_site.py --server=USERNAME:KEY@hub.crossbrowsertesting.com --port=80\n
To use a server on the https
protocol, add --protocol=https
: (SeleniumBase 1.65.2 and newer uses https
automatically for --port=443
.)
pytest test_demo_site.py --protocol=https --server=IP_ADDRESS --port=PORT\n
(For setting browser desired capabilities while running Selenium remotely, see the desired capabilities documentation and the sample files located in SeleniumBase/examples/capabilities)
More info about the Selenium Grid Hub can be found here:All-in-one Browser Automation Framework:Web Crawling / Testing / Scraping / Stealth
\ud83d\ude80 Start | \ud83c\udff0 Features | \ud83d\udcda Examples | \ud83c\udf9b\ufe0f Options | \ud83c\udf20 Scripts | \ud83d\udcf1 Mobile \ud83d\udcd8 APIs | \ud83d\udd21 Formats | \ud83d\udcca Dashboard | \ud83d\udd34 Recorder | \ud83d\uddfe Locales | \ud83c\udf10 Grid \ud83c\udf96\ufe0f GUI | \ud83d\udcf0 TestPage | \ud83d\uddc2\ufe0f CasePlans | \ud83d\udc64 UC Mode | \ud83e\uddec Hybrid | \ud83d\udcbb Farm \ud83d\udc41\ufe0f How | \ud83d\ude9d Migrate | \u267b\ufe0f Templates | \ud83d\ude89 NodeGUI | \ud83d\udcf6 Charts | \ud83d\ude8e Tours \ud83e\udd16 CI/CD | \ud83d\udd79\ufe0f JSMgr | \ud83c\udf0f Translator | \ud83c\udf9e\ufe0f Presenter | \ud83d\udec2 Dialog | \ud83d\uddbc\ufe0f Visual
\ud83d\udcda Learn from over 200 examples in the SeleniumBase/examples/ folder.
\ud83d\udc64 Note that SeleniumBase UC Mode / Stealth Mode has its own ReadMe.
\u2139\ufe0f Scripts can be called via python
, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover & collect tests automatically).
\ud83d\udcd7 Here's my_first_test.py, which tests login, shopping, and checkout:
pytest my_first_test.py\n
pytest
uses --chrome
by default unless set differently.
\ud83d\udcd7 Here's test_coffee_cart.py, which verifies an e-commerce site:
pytest test_coffee_cart.py --demo\n
(--demo
mode slows down tests and highlights actions)
\ud83d\udcd7 Here's test_demo_site.py, which covers several actions:
pytest test_demo_site.py\n
Easy to type, click, select, toggle, drag & drop, and more.
(For more examples, see the SeleniumBase/examples/ folder.)
Explore the README:
\ud83d\udca1 SeleniumBase is a Python framework for browser automation and testing. SeleniumBase uses Selenium/WebDriver APIs and incorporates test-runners such as pytest
, pynose
, and behave
to provide organized structure, test discovery, test execution, test state (eg. passed, failed, or skipped), and command-line options for changing default settings (eg. browser selection). With raw Selenium, you would need to set up your own options-parser for configuring tests from the command-line.
\ud83d\udca1 SeleniumBase's driver manager gives you more control over automatic driver downloads. (Use --driver-version=VER
with your pytest
run command to specify the version.) By default, SeleniumBase will download a driver version that matches your major browser version if not set.
\ud83d\udca1 SeleniumBase automatically detects between CSS Selectors and XPath, which means you don't need to specify the type of selector in your commands (but optionally you could).
\ud83d\udca1 SeleniumBase methods often perform multiple actions in a single method call. For example, self.type(selector, text)
does the following:1. Waits for the element to be visible.2. Waits for the element to be interactive.3. Clears the text field.4. Types in the new text.5. Presses Enter/Submit if the text ends in \"\\n\"
.With raw Selenium, those actions require multiple method calls.
\ud83d\udca1 SeleniumBase uses default timeout values when not set: \u2705 self.click(\"button\")
With raw Selenium, methods would fail instantly (by default) if an element needed more time to load: \u274c self.driver.find_element(by=\"css selector\", value=\"button\").click()
(Reliable code is better than unreliable code.)
\ud83d\udca1 SeleniumBase lets you change the explicit timeout values of methods: \u2705 self.click(\"button\", timeout=10)
With raw Selenium, that requires more code: \u274c WebDriverWait(driver, 10).until(EC.element_to_be_clickable(\"css selector\", \"button\")).click()
(Simple code is better than complex code.)
\ud83d\udca1 SeleniumBase gives you clean error output when a test fails. With raw Selenium, error messages can get very messy.
\ud83d\udca1 SeleniumBase gives you the option to generate a dashboard and reports for tests. It also saves screenshots from failing tests to the ./latest_logs/
folder. Raw Selenium does not have these options out-of-the-box.
\ud83d\udca1 SeleniumBase includes desktop GUI apps for running tests, such as SeleniumBase Commander for pytest
and SeleniumBase Behave GUI for behave
.
\ud83d\udca1 SeleniumBase has its own Recorder / Test Generator for creating tests from manual browser actions.
\ud83d\udca1 SeleniumBase comes with test case management software, (\"CasePlans\"), for organizing tests and step descriptions.
\ud83d\udca1 SeleniumBase includes tools for building data apps, (\"ChartMaker\"), which can generate JavaScript from Python.
\ud83d\udcda Learn about different ways of writing tests:
\ud83d\udcd8\ud83d\udcdd Here's test_simple_login.py, which uses BaseCase
class inheritance, and runs with pytest or pynose. (Use self.driver
to access Selenium's raw driver
.)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass TestSimpleLogin(BaseCase):\n def test_simple_login(self):\n self.open(\"seleniumbase.io/simple/login\")\n self.type(\"#username\", \"demo_user\")\n self.type(\"#password\", \"secret_pass\")\n self.click('a:contains(\"Sign in\")')\n self.assert_exact_text(\"Welcome!\", \"h1\")\n self.assert_element(\"img#image1\")\n self.highlight(\"#image1\")\n self.click_link(\"Sign out\")\n self.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd7\ud83d\udcdd Here's a test from sb_fixture_tests.py, which uses the sb
pytest
fixture. Runs with pytest. (Use sb.driver
to access Selenium's raw driver
.)
def test_sb_fixture_with_no_class(sb):\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd9\ud83d\udcdd Here's raw_login_sb.py, which uses the SB
Context Manager. Runs with pure python
. (Use sb.driver
to access Selenium's raw driver
.)
from seleniumbase import SB\n\nwith SB() as sb:\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd4\ud83d\udcdd Here's raw_login_context.py, which uses the DriverContext
Manager. Runs with pure python
. (The driver
is an improved version of Selenium's raw driver
, with more methods.)
from seleniumbase import DriverContext\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\n
\ud83d\udcd4\ud83d\udcdd Here's raw_login_driver.py, which uses the Driver
Manager. Runs with pure python
. (The driver
is an improved version of Selenium's raw driver
, with more methods.)
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
\ud83d\udcd5\ud83d\udcdd Here's login_app.feature, which uses behave-BDD Gherkin syntax. Runs with behave
. (Learn about the SeleniumBase behave-BDD integration)
Feature: SeleniumBase scenarios for the Simple App\n\n Scenario: Verify the Simple App (Login / Logout)\n Given Open \"seleniumbase.io/simple/login\"\n And Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Click 'a:contains(\"Sign in\")'\n And Assert exact text \"Welcome!\" in \"h1\"\n And Assert element \"img#image1\"\n And Highlight \"#image1\"\n And Click link \"Sign out\"\n And Assert text \"signed out\" in \"#top_message\"\n
Set up Python & Git: \ud83d\udd35 Add Python and Git to your System PATH.
\ud83d\udd35 Using a Python virtual env is recommended.
Install SeleniumBase:You can install seleniumbase
from PyPI or GitHub:
\ud83d\udd35 How to install seleniumbase
from PyPI:
pip install seleniumbase\n
--upgrade
OR -U
to upgrade SeleniumBase.)--force-reinstall
to upgrade indirect packages.)pip3
if multiple versions of Python are present.)\ud83d\udd35 How to install seleniumbase
from a GitHub clone:
git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install -e .\n
\ud83d\udd35 How to upgrade an existing install from a GitHub clone:
git pull\npip install -e .\n
\ud83d\udd35 Type seleniumbase
or sbase
to verify that SeleniumBase was installed successfully:
______ __ _ ____ \n / ____/__ / /__ ____ (_)_ ______ ___ / _ \\____ ________ \n \\__ \\/ _ \\/ / _ \\/ __ \\/ / / / / __ `__ \\ / /_) / __ \\/ ___/ _ \\\n ___/ / __/ / __/ / / / / /_/ / / / / / // /_) / (_/ /__ / __/\n/____/\\___/_/\\___/_/ /_/_/\\__,_/_/ /_/ /_//_____/\\__,_/____/\\___/ \n------------------------------------------------------------------\n\n * USAGE: \"seleniumbase [COMMAND] [PARAMETERS]\"\n * OR: \"sbase [COMMAND] [PARAMETERS]\"\n\nCOMMANDS:\n get / install [DRIVER] [OPTIONS]\n methods (List common Python methods)\n options (List common pytest options)\n behave-options (List common behave options)\n gui / commander [OPTIONAL PATH or TEST FILE]\n behave-gui (SBase Commander for Behave)\n caseplans [OPTIONAL PATH or TEST FILE]\n mkdir [DIRECTORY] [OPTIONS]\n mkfile [FILE.py] [OPTIONS]\n mkrec / codegen [FILE.py] [OPTIONS]\n recorder (Open Recorder Desktop App.)\n record (If args: mkrec. Else: App.)\n mkpres [FILE.py] [LANG]\n mkchart [FILE.py] [LANG]\n print [FILE] [OPTIONS]\n translate [SB_FILE.py] [LANG] [ACTION]\n convert [WEBDRIVER_UNITTEST_FILE.py]\n extract-objects [SB_FILE.py]\n inject-objects [SB_FILE.py] [OPTIONS]\n objectify [SB_FILE.py] [OPTIONS]\n revert-objects [SB_FILE.py] [OPTIONS]\n encrypt / obfuscate\n decrypt / unobfuscate\n download server (Get Selenium Grid JAR file)\n grid-hub [start|stop] [OPTIONS]\n grid-node [start|stop] --hub=[HOST/IP]\n * (EXAMPLE: \"sbase get chromedriver latest\") *\n\n Type \"sbase help [COMMAND]\" for specific command info.\n For info on all commands, type: \"seleniumbase --help\".\n Use \"pytest\" for running tests.\n
\ud83d\udd35 Downloading webdrivers: \u2705 SeleniumBase automatically downloads webdrivers as needed, such as chromedriver
.
*** chromedriver to download = 121.0.6167.85 (Latest Stable) \n\nDownloading chromedriver-mac-arm64.zip from:\nhttps://storage.googleapis.com/chrome-for-testing-public/121.0.6167.85/mac-arm64/chromedriver-mac-arm64.zip ...\nDownload Complete!\n\nExtracting ['chromedriver'] from chromedriver-mac-arm64.zip ...\nUnzip Complete!\n\nThe file [chromedriver] was saved to:\n/Users/michael/github/SeleniumBase/seleniumbase/drivers/chromedriver\n\nMaking [chromedriver 121.0.6167.85] executable ...\n[chromedriver 121.0.6167.85] is now ready for use!\n
Basic Example / Usage: \ud83d\udd35 If you've cloned SeleniumBase, you can run tests from the examples/ folder.
Here's my_first_test.py:
cd examples/\npytest my_first_test.py\n
Here's the code for my_first_test.py:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n def test_swag_labs(self):\n self.open(\"https://www.saucedemo.com\")\n self.type(\"#user-name\", \"standard_user\")\n self.type(\"#password\", \"secret_sauce\\n\")\n self.assert_element(\"div.inventory_list\")\n self.assert_exact_text(\"Products\", \"span.title\")\n self.click('button[name*=\"backpack\"]')\n self.click(\"#shopping_cart_container a\")\n self.assert_exact_text(\"Your Cart\", \"span.title\")\n self.assert_text(\"Backpack\", \"div.cart_item\")\n self.click(\"button#checkout\")\n self.type(\"#first-name\", \"SeleniumBase\")\n self.type(\"#last-name\", \"Automation\")\n self.type(\"#postal-code\", \"77123\")\n self.click(\"input#continue\")\n self.assert_text(\"Checkout: Overview\")\n self.assert_text(\"Backpack\", \"div.cart_item\")\n self.assert_text(\"29.99\", \"div.inventory_item_price\")\n self.click(\"button#finish\")\n self.assert_exact_text(\"Thank you for your order!\", \"h2\")\n self.assert_element('img[alt=\"Pony Express\"]')\n self.js_click(\"a#logout_sidebar_link\")\n self.assert_element(\"div#login_button_container\")\n
self.open(url) # Navigate the browser window to the URL.\nself.type(selector, text) # Update the field with the text.\nself.click(selector) # Click the element with the selector.\nself.click_link(link_text) # Click the link containing text.\nself.go_back() # Navigate back to the previous URL.\nself.select_option_by_text(dropdown_selector, option)\nself.hover_and_click(hover_selector, click_selector)\nself.drag_and_drop(drag_selector, drop_selector)\nself.get_text(selector) # Get the text from the element.\nself.get_current_url() # Get the URL of the current page.\nself.get_page_source() # Get the HTML of the current page.\nself.get_attribute(selector, attribute) # Get element attribute.\nself.get_title() # Get the title of the current page.\nself.switch_to_frame(frame) # Switch into the iframe container.\nself.switch_to_default_content() # Leave the iframe container.\nself.open_new_window() # Open a new window in the same browser.\nself.switch_to_window(window) # Switch to the browser window.\nself.switch_to_default_window() # Switch to the original window.\nself.get_new_driver(OPTIONS) # Open a new driver with OPTIONS.\nself.switch_to_driver(driver) # Switch to the browser driver.\nself.switch_to_default_driver() # Switch to the original driver.\nself.wait_for_element(selector) # Wait until element is visible.\nself.is_element_visible(selector) # Return element visibility.\nself.is_text_visible(text, selector) # Return text visibility.\nself.sleep(seconds) # Do nothing for the given amount of time.\nself.save_screenshot(name) # Save a screenshot in .png format.\nself.assert_element(selector) # Verify the element is visible.\nself.assert_text(text, selector) # Verify text in the element.\nself.assert_exact_text(text, selector) # Verify text is exact.\nself.assert_title(title) # Verify the title of the web page.\nself.assert_downloaded_file(file) # Verify file was downloaded.\nself.assert_no_404_errors() # Verify there are no broken links.\nself.assert_no_js_errors() # Verify there are no JS errors.\n
\ud83d\udd35 For the complete list of SeleniumBase methods, see: Method Summary
Fun Facts / Learn More:\u2705 SeleniumBase automatically handles common WebDriver actions such as launching web browsers before tests, saving screenshots during failures, and closing web browsers after tests.
\u2705 SeleniumBase lets you customize tests via command-line options.
\u2705 SeleniumBase uses simple syntax for commands. Example:
self.type(\"input\", \"dogs\\n\") # (The \"\\n\" presses ENTER)\n
Most SeleniumBase scripts can be run with pytest
, pynose
, or pure python
. Not all test runners can run all test formats. For example, tests that use the sb
pytest fixture can only be run with pytest
. (See Syntax Formats) There's also a Gherkin test format that runs with behave.
pytest coffee_cart_tests.py --rs\npytest test_sb_fixture.py --demo\npytest test_suite.py --rs --html=report.html --dashboard\n\npynose basic_test.py --mobile\npynose test_suite.py --headless --report --show-report\n\npython raw_sb.py\npython raw_test_scripts.py\n\nbehave realworld.feature\nbehave calculator.feature -D rs -D dashboard\n
\u2705 pytest
includes automatic test discovery. If you don't specify a specific file or folder to run, pytest
will automatically search through all subdirectories for tests to run based on the following criteria:
test_
or end with _test.py
.test_
.With a SeleniumBase pytest.ini file present, you can modify default discovery settings. The Python class name can be anything because seleniumbase.BaseCase
inherits unittest.TestCase
to trigger autodiscovery.
\u2705 You can do a pre-flight check to see which tests would get discovered by pytest
before the actual run:
pytest --co -q\n
\u2705 You can be more specific when calling pytest
or pynose
on a file:
pytest [FILE_NAME.py]::[CLASS_NAME]::[METHOD_NAME]\n\npynose [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]\n
\u2705 No More Flaky Tests! SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (up to a timeout limit). This means you no longer need random time.sleep()
statements in your scripts.
\u2705 SeleniumBase supports all major browsers and operating systems:
Browsers: Chrome, Edge, Firefox, and Safari.
Systems: Linux/Ubuntu, macOS, and Windows.
\u2705 SeleniumBase works on all popular CI/CD platforms:
\u2705 SeleniumBase includes an automated/manual hybrid solution called MasterQA to speed up manual testing with automation while manual testers handle validation.
\u2705 SeleniumBase supports running tests while offline (assuming webdrivers have previously been downloaded when online).
\u2705 For a full list of SeleniumBase features, Click Here.
Demo Mode / Debugging:\ud83d\udd35 Demo Mode helps you see what a test is doing. If a test is moving too fast for your eyes, run it in Demo Mode to pause the browser briefly between actions, highlight page elements being acted on, and display assertions:
pytest my_first_test.py --demo\n
\ud83d\udd35 time.sleep(seconds)
can be used to make a test wait at a specific spot:
import time; time.sleep(3) # Do nothing for 3 seconds.\n
\ud83d\udd35 Debug Mode with Python's built-in pdb library helps you debug tests:
import pdb; pdb.set_trace()\nimport pytest; pytest.set_trace()\nbreakpoint() # Shortcut for \"import pdb; pdb.set_trace()\"\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
)
\ud83d\udd35 To pause an active test that throws an exception or error, (and keep the browser window open while Debug Mode begins in the console), add --pdb
as a pytest
option:
pytest test_fail.py --pdb\n
\ud83d\udd35 To start tests in Debug Mode, add --trace
as a pytest
option:
pytest test_coffee_cart.py --trace\n
\ud83d\udd35 Command-line Options: \u2705 Here are some useful command-line options that come with pytest
:
-v # Verbose mode. Prints the full name of each test and shows more details.\n-q # Quiet mode. Print fewer details in the console output when running tests.\n-x # Stop running the tests after the first failure is reached.\n--html=report.html # Creates a detailed pytest-html report after tests finish.\n--co | --collect-only # Show what tests would get run. (Without running them)\n--co -q # (Both options together!) - Do a dry run with full test names shown.\n-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)\n-s # See print statements. (Should be on by default with pytest.ini present.)\n--junit-xml=report.xml # Creates a junit-xml report after tests finish.\n--pdb # If a test fails, enter Post Mortem Debug Mode. (Don't use with CI!)\n--trace # Enter Debug Mode at the beginning of each test. (Don't use with CI!)\n-m=MARKER # Run tests with the specified pytest marker.\n
\u2705 SeleniumBase provides additional pytest
command-line options for tests:
--browser=BROWSER # (The web browser to use. Default: \"chrome\".)\n--chrome # (Shortcut for \"--browser=chrome\". On by default.)\n--edge # (Shortcut for \"--browser=edge\".)\n--firefox # (Shortcut for \"--browser=firefox\".)\n--safari # (Shortcut for \"--browser=safari\".)\n--settings-file=FILE # (Override default SeleniumBase settings.)\n--env=ENV # (Set the test env. Access with \"self.env\" in tests.)\n--account=STR # (Set account. Access with \"self.account\" in tests.)\n--data=STRING # (Extra test data. Access with \"self.data\" in tests.)\n--var1=STRING # (Extra test data. Access with \"self.var1\" in tests.)\n--var2=STRING # (Extra test data. Access with \"self.var2\" in tests.)\n--var3=STRING # (Extra test data. Access with \"self.var3\" in tests.)\n--variables=DICT # (Extra test data. Access with \"self.variables\".)\n--user-data-dir=DIR # (Set the Chrome user data directory to use.)\n--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)\n--server=SERVER # (The Selenium Grid server/IP used for tests.)\n--port=PORT # (The Selenium Grid port used by the test server.)\n--cap-file=FILE # (The web browser's desired capabilities to use.)\n--cap-string=STRING # (The web browser's desired capabilities to use.)\n--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)\n--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)\n--proxy-bypass-list=STRING # (\";\"-separated hosts to bypass, Eg \"*.foo.com\")\n--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)\n--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)\n--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)\n--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)\n--agent=STRING # (Modify the web browser's User-Agent string.)\n--mobile # (Use the mobile device emulator while running tests.)\n--metrics=STRING # (Set mobile metrics: \"CSSWidth,CSSHeight,PixelRatio\".)\n--chromium-arg=\"ARG=N,ARG2\" # (Set Chromium args, \",\"-separated, no spaces.)\n--firefox-arg=\"ARG=N,ARG2\" # (Set Firefox args, comma-separated, no spaces.)\n--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)\n--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)\n--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)\n--disable-features=\"F1,F2\" # (Disable features, comma-separated, no spaces.)\n--binary-location=PATH # (Set path of the Chromium browser binary to use.)\n--driver-version=VER # (Set the chromedriver or uc_driver version to use.)\n--sjw # (Skip JS Waits for readyState to be \"complete\" or Angular to load.)\n--pls=PLS # (Set pageLoadStrategy on Chrome: \"normal\", \"eager\", or \"none\".)\n--headless # (Run tests in headless mode. The default arg on Linux OS.)\n--headless2 # (Use the new headless mode, which supports extensions.)\n--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)\n--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)\n--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)\n--interval=SECONDS # (The autoplay interval for presentations & tour steps)\n--start-page=URL # (The starting URL for the web browser when tests begin.)\n--archive-logs # (Archive existing log files instead of deleting them.)\n--archive-downloads # (Archive old downloads instead of deleting them.)\n--time-limit=SECONDS # (Safely fail any test that exceeds the time limit.)\n--slow # (Slow down the automation. Faster than using Demo Mode.)\n--demo # (Slow down and visually see test actions as they occur.)\n--demo-sleep=SECONDS # (Set the wait time after Slow & Demo Mode actions.)\n--highlights=NUM # (Number of highlight animations for Demo Mode actions.)\n--message-duration=SECONDS # (The time length for Messenger alerts.)\n--check-js # (Check for JavaScript errors after page loads.)\n--ad-block # (Block some types of display ads from loading.)\n--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)\n--block-images # (Block images from loading during tests.)\n--do-not-track # (Indicate to websites that you don't want to be tracked.)\n--verify-delay=SECONDS # (The delay before MasterQA verification checks.)\n--ee | --esc-end # (Lets the user end the current test via the ESC key.)\n--recorder # (Enables the Recorder for turning browser actions into code.)\n--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)\n--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)\n--rec-print # (If the Recorder is enabled, prints output after tests end.)\n--disable-js # (Disable JavaScript on websites. Pages might break!)\n--disable-csp # (Disable the Content Security Policy of websites.)\n--disable-ws # (Disable Web Security on Chromium-based browsers.)\n--enable-ws # (Enable Web Security on Chromium-based browsers.)\n--enable-sync # (Enable \"Chrome Sync\" on websites.)\n--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)\n--uc-cdp-events # (Capture CDP events when running in \"--undetected\" mode.)\n--log-cdp # (\"goog:loggingPrefs\", {\"performance\": \"ALL\", \"browser\": \"ALL\"})\n--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)\n--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)\n--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)\n--dash-title=STRING # (Set the title shown for the generated dashboard.)\n--enable-3d-apis # (Enables WebGL and 3D APIs.)\n--swiftshader # (Chrome \"--use-gl=angle\" / \"--use-angle=swiftshader-webgl\")\n--incognito # (Enable Chrome's Incognito mode.)\n--guest # (Enable Chrome's Guest mode.)\n--dark # (Enable Chrome's Dark mode.)\n--devtools # (Open Chrome's DevTools when the browser opens.)\n--rs | --reuse-session # (Reuse browser session for all tests.)\n--rcs | --reuse-class-session # (Reuse session for tests in class.)\n--crumbs # (Delete all cookies between tests reusing a session.)\n--disable-beforeunload # (Disable the \"beforeunload\" event on Chrome.)\n--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)\n--maximize # (Start tests with the browser window maximized.)\n--screenshot # (Save a screenshot at the end of each test.)\n--no-screenshot # (No screenshots saved unless tests directly ask it.)\n--visual-baseline # (Set the visual baseline for Visual/Layout tests.)\n--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)\n--external-pdf # (Set Chromium \"plugins.always_open_pdf_externally\":True.)\n--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)\n--list-fail-page # (After each failing test, list the URL of the failure.)\n
(See the full list of command-line option definitions here. For detailed examples of command-line options, see customizing_test_runs.md)
\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. Those logs will get moved to archived_logs/
if you add --archive_logs to command-line options, or have ARCHIVE_EXISTING_LOGS
set to True in settings.py, otherwise log files with be cleaned up at the start of the next test run. The test_suite.py
collection contains tests that fail on purpose so that you can see how logging works.
cd examples/\n\npytest test_suite.py --chrome\n\npytest test_suite.py --firefox\n
An easy way to override seleniumbase/config/settings.py is by using a custom settings file. Here's the command-line option to add to tests: (See examples/custom_settings.py) --settings_file=custom_settings.py
(Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
\ud83d\udd35 To pass additional data from the command-line to tests, add --data=\"ANY STRING\"
. Inside your tests, you can use self.data
to access that.
\ud83d\udd35 When running tests with pytest
, you'll want a copy of pytest.ini in your root folders. When running tests with pynose
, you'll want a copy of setup.cfg in your root folders. These files specify default configuration details for tests. Test folders should also include a blank init.py file to allow your test files to import other files from that folder.
\ud83d\udd35 sbase mkdir DIR
creates a folder with config files and sample tests:
sbase mkdir ui_tests\n
That new folder will have these files:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 my_first_test.py\n\u251c\u2500\u2500 parameterized_test.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 test_demo_site.py\n\u2514\u2500\u2500 boilerplates/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 base_test_case.py\n \u251c\u2500\u2500 boilerplate_test.py\n \u251c\u2500\u2500 classic_obj_test.py\n \u251c\u2500\u2500 page_objects.py\n \u251c\u2500\u2500 sb_fixture_test.py\n \u2514\u2500\u2500 samples/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 google_objects.py\n \u251c\u2500\u2500 google_test.py\n \u251c\u2500\u2500 sb_swag_test.py\n \u2514\u2500\u2500 swag_labs_test.py\n
ProTip\u2122: You can also create a boilerplate folder without any sample tests in it by adding -b
or --basic
to the sbase mkdir
command:
sbase mkdir ui_tests --basic\n
That new folder will have these files:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u2514\u2500\u2500 setup.cfg\n
Of those files, the pytest.ini
config file is the most important, followed by a blank __init__.py
file. There's also a setup.cfg
file (for pynose). Finally, the requirements.txt
file can be used to help you install seleniumbase into your environments (if it's not already installed).
Let's try an example of a test that fails:
\"\"\" test_fail.py \"\"\"\nfrom seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n\n def test_find_army_of_robots_on_xkcd_desert_island(self):\n self.open(\"https://xkcd.com/731/\")\n self.assert_element(\"div#ARMY_OF_ROBOTS\", timeout=1) # This should fail\n
You can run it from the examples/
folder like this:
pytest test_fail.py\n
\ud83d\udd35 You'll notice that a logs folder, \"latest_logs\", was created to hold information about the failing test, and screenshots. During test runs, past results get moved to the archived_logs folder if you have ARCHIVE_EXISTING_LOGS set to True in settings.py, or if your run tests with --archive-logs
. If you choose not to archive existing logs, they will be deleted and replaced by the logs of the latest test run.
\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py test_image_saving.py --dashboard --rs --headless\n
Generating Test Reports: \ud83d\udd35 pytest
HTML Reports: \u2705 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\u2705 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\u2705 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest html reports in Jenkins, you may need to configure Jenkins settings for the html to render correctly. This is due to Jenkins CSP changes.
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
\ud83d\udd35 pynose
Reports: The --report
option gives you a fancy report after your test suite completes.
pynose test_suite.py --report\n
(NOTE: You can add --show-report
to immediately display pynose reports after the test suite completes. Only use --show-report
when running tests locally because it pauses the test run.)
behave
Dashboard & Reports: (The behave_bdd/ folder can be found in the examples/ folder.)
behave behave_bdd/features/ -D dashboard -D headless\n
You can also use --junit
to get .xml
reports for each behave
feature. Jenkins can use these files to display better reporting for your tests.
behave behave_bdd/features/ --junit -D rs -D headless\n
\ud83d\udd35 Allure Reports: See: https://allurereport.org/docs/pytest/
SeleniumBase no longer includes allure-pytest
as part of installed dependencies. If you want to use it, install it first:
pip install allure-pytest\n
Now your tests can create Allure results files, which can be processed by Allure Reports.
pytest test_suite.py --alluredir=allure_results\n
Using a Proxy Server: If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add --proxy=IP_ADDRESS:PORT
as an argument on the command line.
pytest proxy_test.py --proxy=IP_ADDRESS:PORT\n
If the proxy server that you wish to use requires authentication, you can do the following (Chromium only):
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n
SeleniumBase also supports SOCKS4 and SOCKS5 proxies:
pytest proxy_test.py --proxy=\"socks4://IP_ADDRESS:PORT\"\n\npytest proxy_test.py --proxy=\"socks5://IP_ADDRESS:PORT\"\n
To make things easier, you can add your frequently-used proxies to PROXY_LIST in proxy_list.py, and then use --proxy=KEY_FROM_PROXY_LIST
to use the IP_ADDRESS:PORT of that key.
pytest proxy_test.py --proxy=proxy1\n
Changing the User-Agent: \ud83d\udd35 If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add --agent=\"USER AGENT STRING\"
as an argument on the command-line.
pytest user_agent_test.py --agent=\"Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU\"\n
Handling Pop-Up Alerts: \ud83d\udd35 self.accept_alert()
automatically waits for and accepts alert pop-ups. self.dismiss_alert()
automatically waits for and dismisses alert pop-ups. On occasion, some methods like self.click(SELECTOR)
might dismiss a pop-up on its own because they call JavaScript to make sure that the readyState
of the page is complete
before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call self.find_element(SELECTOR).click()
instead, (which will let the pop-up remain on the screen), and then use self.accept_alert()
to accept the pop-up (more on that here). If pop-ups are intermittent, wrap code in a try/except block.
\ud83d\udd35 Learn about SeleniumBase Interactive Walkthroughs (in the examples/tour_examples/
folder). It's great for prototyping a website onboarding experience.
--with-s3-logging
on the command-line when running your tests.pytest [YOUR_TEST_FILE.py] --with-db-reporting --with-s3-logging\n
Detailed Method Specifications and Examples: \ud83d\udd35 Navigating to a web page: (and related commands)
self.open(\"https://xkcd.com/378/\") # This method opens the specified page.\n\nself.go_back() # This method navigates the browser to the previous page.\n\nself.go_forward() # This method navigates the browser forward in history.\n\nself.refresh_page() # This method reloads the current page.\n\nself.get_current_url() # This method returns the current page URL.\n\nself.get_page_source() # This method returns the current page source.\n
ProTip\u2122: You can use the self.get_page_source()
method with Python's find()
command to parse through HTML to find something specific. (For more advanced parsing, see the BeautifulSoup example.)
source = self.get_page_source()\nhead_open_tag = source.find('<head>')\nhead_close_tag = source.find('</head>', head_open_tag)\neverything_inside_head = source[head_open_tag+len('<head>'):head_close_tag]\n
\ud83d\udd35 Clicking:
To click an element on the page:
self.click(\"div#my_id\")\n
ProTip\u2122: In most web browsers, you can right-click on a page and select Inspect Element
to see the CSS selector details that you'll need to create your own scripts.
\ud83d\udd35 Typing Text:
self.type(selector, text)
# updates the text from the specified element with the specified value. An exception is raised if the element is missing or if the text field is not editable. Example:
self.type(\"input#id_value\", \"2012\")\n
You can also use self.add_text()
or the WebDriver .send_keys()
command, but those won't clear the text box first if there's already text inside.
\ud83d\udd35 Getting the text from an element on a page:
text = self.get_text(\"header h2\")\n
\ud83d\udd35 Getting the attribute value from an element on a page:
attribute = self.get_attribute(\"#comic img\", \"title\")\n
\ud83d\udd35 Asserting existence of an element on a page within some number of seconds:
self.wait_for_element_present(\"div.my_class\", timeout=10)\n
(NOTE: You can also use: self.assert_element_present(ELEMENT)
)
\ud83d\udd35 Asserting visibility of an element on a page within some number of seconds:
self.wait_for_element_visible(\"a.my_class\", timeout=5)\n
(NOTE: The short versions of that are self.find_element(ELEMENT)
and self.assert_element(ELEMENT)
. The find_element()
version returns the element.)
Since the line above returns the element, you can combine that with .click()
as shown below:
self.find_element(\"a.my_class\", timeout=5).click()\n\n# But you're better off using the following statement, which does the same thing\nself.click(\"a.my_class\") # DO IT THIS WAY!\n
ProTip\u2122: You can use dots to signify class names (Ex: div.class_name
) as a simplified version of div[class=\"class_name\"]
within a CSS selector.
You can also use *=
to search for any partial value in a CSS selector as shown below:
self.click('a[name*=\"partial_name\"]')\n
\ud83d\udd35 Asserting visibility of text inside an element on a page within some number of seconds:
self.assert_text(\"Make it so!\", \"div#trek div.picard div.quotes\")\nself.assert_text(\"Tea. Earl Grey. Hot.\", \"div#trek div.picard div.quotes\", timeout=3)\n
(NOTE: self.find_text(TEXT, ELEMENT)
and self.wait_for_text(TEXT, ELEMENT)
also do this. For backwards compatibility, older method names were kept, but the default timeout may be different.)
\ud83d\udd35 Asserting Anything:
self.assert_true(var1 == var2)\n\nself.assert_false(var1 == var2)\n\nself.assert_equal(var1, var2)\n
\ud83d\udd35 Useful Conditional Statements: (with creative examples)
\u2753 is_element_visible(selector):
(visible on the page)
if self.is_element_visible('div#warning'):\n print(\"Red Alert: Something bad might be happening!\")\n
\u2753 is_element_present(selector):
(present in the HTML)
if self.is_element_present('div#top_secret img.tracking_cookie'):\n self.contact_cookie_monster() # Not a real SeleniumBase method\nelse:\n current_url = self.get_current_url()\n self.contact_the_nsa(url=current_url, message=\"Dark Zone Found\") # Not a real SeleniumBase method\n
def is_there_a_cloaked_klingon_ship_on_this_page():\n if self.is_element_present(\"div.ships div.klingon\"):\n return not self.is_element_visible(\"div.ships div.klingon\")\n return False\n
\u2753 is_text_visible(text, selector):
(text visible on element)
if self.is_text_visible(\"You Shall Not Pass!\", \"h1\"):\n self.open(\"https://www.youtube.com/watch?v=3xYXUeSmb-Y\")\n
\u25b6\ufe0f Click for a longer example of is_text_visible():
def get_mirror_universe_captain_picard_superbowl_ad(superbowl_year):\n selector = \"div.superbowl_%s div.commercials div.transcript div.picard\" % superbowl_year\n if self.is_text_visible(\"Yes, it was I who summoned you all here.\", selector):\n return \"Picard Paramount+ Superbowl Ad 2020\"\n elif self.is_text_visible(\"Commander, signal the following: Our Network is Secure!\"):\n return \"Picard Mirror Universe iboss Superbowl Ad 2018\"\n elif self.is_text_visible(\"For the Love of Marketing and Earl Grey Tea!\", selector):\n return \"Picard Mirror Universe HubSpot Superbowl Ad 2015\"\n elif self.is_text_visible(\"Delivery Drones... Engage\", selector):\n return \"Picard Mirror Universe Amazon Superbowl Ad 2015\"\n elif self.is_text_visible(\"Bing it on Screen!\", selector):\n return \"Picard Mirror Universe Microsoft Superbowl Ad 2015\"\n elif self.is_text_visible(\"OK Glass, Make it So!\", selector):\n return \"Picard Mirror Universe Google Superbowl Ad 2015\"\n elif self.is_text_visible(\"Number One, I've Never Seen Anything Like It.\", selector):\n return \"Picard Mirror Universe Tesla Superbowl Ad 2015\"\n elif self.is_text_visible(\"Let us make sure history never forgets the name ... Facebook\", selector):\n return \"Picard Mirror Universe Facebook Superbowl Ad 2015\"\n elif self.is_text_visible(\"\"\"With the first link, the chain is forged.\n The first speech censored, the first thought forbidden,\n the first freedom denied, chains us all irrevocably.\"\"\", selector):\n return \"Picard Mirror Universe Wikimedia Superbowl Ad 2015\"\n else:\n raise Exception(\"Reports of my assimilation are greatly exaggerated.\")\n
\u2753 is_link_text_visible(link_text):
if self.is_link_text_visible(\"Stop! Hammer time!\"):\n self.click_link(\"Stop! Hammer time!\")\n
\ud83d\udd35 Switching Tabs: If your test opens up a new tab/window, you can switch to it. (SeleniumBase automatically switches to new tabs that don't open to about:blank
URLs.)
self.switch_to_window(1) # This switches to the new tab (0 is the first one)\n
\ud83d\udd35 How to handle iframes: \ud83d\udd35 iframes follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
self.switch_to_frame(\"iframe\")\n# ... Now perform actions inside the iframe\nself.switch_to_parent_frame() # Exit the current iframe\n
To exit from multiple iframes, use self.switch_to_default_content()
. (If inside a single iframe, this has the same effect as self.switch_to_parent_frame()
.)
self.switch_to_frame('iframe[name=\"frame1\"]')\nself.switch_to_frame('iframe[name=\"frame2\"]')\n# ... Now perform actions inside the inner iframe\nself.switch_to_default_content() # Back to the main page\n
\ud83d\udd35 You can also use a context manager to act inside iframes:
with self.frame_switch(\"iframe\"):\n # ... Now perform actions while inside the code block\n# You have left the iframe\n
This also works with nested iframes:
with self.frame_switch('iframe[name=\"frame1\"]'):\n with self.frame_switch('iframe[name=\"frame2\"]'):\n # ... Now perform actions while inside the code block\n # You are now back inside the first iframe\n# You have left all the iframes\n
\ud83d\udd35 How to execute custom jQuery scripts: jQuery is a powerful JavaScript library that allows you to perform advanced actions in a web browser. If the web page you're on already has jQuery loaded, you can start executing jQuery scripts immediately. You'd know this because the web page would contain something like the following in the HTML:
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js\"></script>\n
\ud83d\udd35 It's OK if you want to use jQuery on a page that doesn't have it loaded yet. To do so, run the following command first:
self.activate_jquery()\n
\u25b6\ufe0f Here are some examples of using jQuery in your scripts. (click to expand) self.execute_script(\"jQuery, window.scrollTo(0, 600)\") # Scrolling the page\n\nself.execute_script(\"jQuery('#annoying-widget').hide()\") # Hiding elements on a page\n\nself.execute_script(\"jQuery('#hidden-widget').show(0)\") # Showing hidden elements on a page\n\nself.execute_script(\"jQuery('#annoying-button a').remove()\") # Removing elements on a page\n\nself.execute_script(\"jQuery('%s').mouseover()\" % (mouse_over_item)) # Mouse-over elements on a page\n\nself.execute_script(\"jQuery('input#the_id').val('my_text')\") # Fast text input on a page\n\nself.execute_script(\"jQuery('div#dropdown a.link').click()\") # Click elements on a page\n\nself.execute_script(\"return jQuery('div#amazing')[0].text\") # Returns the css \"text\" of the element given\n\nself.execute_script(\"return jQuery('textarea')[2].value\") # Returns the css \"value\" of the 3rd textarea element on the page\n
(Most of the above commands can be done directly with built-in SeleniumBase methods.) \ud83d\udd35 How to handle a restrictive CSP: \u2757 Some websites have a restrictive Content Security Policy to prevent users from loading jQuery and other external libraries onto their websites. If you need to use jQuery or another JS library on those websites, add --disable-csp
as a pytest
command-line option to load a Chromium extension that bypasses the CSP.
start_page = \"https://xkcd.com/465/\"\ndestination_page = \"https://github.com/seleniumbase/SeleniumBase\"\nself.open(start_page)\nreferral_link = '''<a class='analytics test' href='%s'>Free-Referral Button!</a>''' % destination_page\nself.execute_script('''document.body.innerHTML = \\\"%s\\\"''' % referral_link)\nself.click(\"a.analytics\") # Clicks the generated button\n
(Due to popular demand, this traffic generation example has been included in SeleniumBase with the self.generate_referral(start_page, end_page)
and the self.generate_traffic(start_page, end_page, loops)
methods.) \ud83d\udd35 How to use deferred asserts: Let's say you want to verify multiple different elements on a web page in a single test, but you don't want the test to fail until you verified several elements at once so that you don't have to rerun the test to find more missing elements on the same page. That's where deferred asserts come in. Here's an example:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass DeferredAssertTests(BaseCase):\n def test_deferred_asserts(self):\n self.open(\"https://xkcd.com/993/\")\n self.wait_for_element(\"#comic\")\n self.deferred_assert_element('img[alt=\"Brand Identity\"]')\n self.deferred_assert_element('img[alt=\"Rocket Ship\"]') # Will Fail\n self.deferred_assert_element(\"#comicmap\")\n self.deferred_assert_text(\"Fake Item\", \"ul.comicNav\") # Will Fail\n self.deferred_assert_text(\"Random\", \"ul.comicNav\")\n self.deferred_assert_element('a[name=\"Super Fake !!!\"]') # Will Fail\n self.deferred_assert_exact_text(\"Brand Identity\", \"#ctitle\")\n self.deferred_assert_exact_text(\"Fake Food\", \"#comic\") # Will Fail\n self.process_deferred_asserts()\n
deferred_assert_element()
and deferred_assert_text()
will save any exceptions that would be raised. To flush out all the failed deferred asserts into a single exception, make sure to call self.process_deferred_asserts()
at the end of your test method. If your test hits multiple pages, you can call self.process_deferred_asserts()
before navigating to a new page so that the screenshot from your log files matches the URL where the deferred asserts were made.
If you need access to any commands that come with standard WebDriver, you can call them directly like this:
self.driver.delete_all_cookies()\ncapabilities = self.driver.capabilities\nself.driver.find_elements(\"partial link text\", \"GitHub\")\n
(In general, you'll want to use the SeleniumBase versions of methods when available.)
\ud83d\udd35 How to retry failing tests automatically:You can use pytest --reruns=NUM
to retry failing tests that many times. Add --reruns-delay=SECONDS
to wait that many seconds between retries. Example:
pytest --reruns=1 --reruns-delay=1\n
You can use the @retry_on_exception()
decorator to retry failing methods. (First import: from seleniumbase import decorators
). To learn more about SeleniumBase decorators, click here.
\"Catch bugs in QA before deploying code to Production!\"
Wrap-UpIf you see something, say something!
https://github.com/mdmintz
"}, {"location": "examples/ReadMe/", "title": "\ud83d\udcda Running Example Tests", "text": ""}, {"location": "examples/ReadMe/#example-tests", "title": "Example Tests", "text": "./latest_logs/
.(NOTE: Some example tests fail on purpose to demonstrate logging features.)
Example tests with run commands to help you get started:Run an example test: (Default option: --chrome
)
pytest my_first_test.py\n
Here's one way of changing the browser to Firefox:
pytest my_first_test.py --firefox\n
Another example test for a web page that has lots of different HTML items:
pytest test_demo_site.py\n
Run an example test in --demo
mode: (highlight assertions)
pytest test_swag_labs.py --demo\n
Run test_coffee_cart.py to test the Coffee Cart app:
pytest test_coffee_cart.py --demo\n
Run a Wordle-solver example:
pytest wordle_test.py\n
Run an example test in --headless
mode: (invisible browser)
pytest my_first_test.py --headless\n
Run an example test using Chrome's mobile device emulator: (default settings)
pytest test_swag_labs.py --mobile\n
Run an example test in --demo
mode: (highlight assertions)
pytest test_xkcd.py --demo\n
Run a test suite with verbose output: (see more details)
pytest test_suite.py -v\n
Run a test suite using multiple parallel processes (-n=NUM
):
pytest test_suite.py -n=8\n
Run a parameterized test: (Generates multiple tests from one)
pytest parameterized_test.py -v\n
Run a test suite and generate a SeleniumBase Dashboard:
pytest test_suite.py --dashboard\n
Run a test suite and generate a pytest
report:
pytest test_suite.py --html=report.html\n
Run a failing test: (See the latest_logs/
folder for logs and screenshots)
pytest test_fail.py\n
Run a failing test that activates pdb
debug mode on failure:
pytest test_fail.py --pdb -s\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
)
Run a test suite that demonstrates the use of pytest
markers:
pytest -m marker_test_suite -v\n
Run a test suite that reuses the browser session between tests:
pytest test_suite.py --rs\n
Run an example test demonstrating the rate_limited
Python decorator:
pytest rate_limiting_test.py\n
Run an example test that demonstrates how to upload a file to a website:
pytest upload_file_test.py\n
\ud83c\udf96\ufe0f SeleniumBase Commander is a GUI for pytest
:
sbase gui\n
SeleniumBase tests can also be run with pynose
:
pynose my_first_test.py\n
Run an example test suite and generate a pynose
test report:
pynose test_suite.py --report --show-report\n
Run an example test using a pynose
configuration file:
pynose my_first_test.py --config=example_config.cfg\n
For more advanced run commands, such as using a proxy server, see ../help_docs/customizing_test_runs.md
If you just need to perform some quick website verification on various devices, you can use the SeleniumBase Device Farm. Just plug in a website URL, and it will display how the website looks on four different devices:
To make things easier, here's a simple GUI program that allows you to run a few example tests by pressing a button:
python gui_test_runner.py\n
(The newer SeleniumBase Commander improves on that.)
"}, {"location": "examples/behave_bdd/ReadMe/", "title": "\ud83d\udc1d Behave-BDD ReadMe", "text": ""}, {"location": "examples/behave_bdd/ReadMe/#behave-test-runner-for-seleniumbase", "title": "\ud83d\udc1d Behave test runner for SeleniumBase \ud83d\udc1d", "text": "
\ud83d\udc1d (Utilizes the Behave BDD Python library. For more info, see the Behave tutorial and read about Behave's Gherkin model.)
\ud83d\udc1d Behave examples with SeleniumBase: SeleniumBase/examples/behave_bdd
> cd examples/behave_bdd/\n> behave features/realworld.feature -T -D dashboard -k\n\nDashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n********************************************************************************\nFeature: SeleniumBase scenarios for the RealWorld App # features/realworld.feature:1\n\n Scenario: Verify RealWorld App (log in / sign out) # features/realworld.feature:3\n Given Open \"seleniumbase.io/realworld/login\" # ../../sbase/steps.py:10\n And Clear Session Storage # ../../sbase/steps.py:669\n When Type \"demo_user\" into \"#username\" # ../../sbase/steps.py:40\n And Type \"secret_pass\" into \"#password\" # ../../sbase/steps.py:40\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\" # ../../sbase/steps.py:322\n Then Assert exact text \"Welcome!\" in \"h1\" # ../../sbase/steps.py:157\n And Highlight \"img#image1\" # ../../sbase/steps.py:184\n And Click 'a:contains(\"This Page\")' # ../../sbase/steps.py:27\n And Save screenshot to logs # ../../sbase/steps.py:239\n When Click link \"Sign out\" # ../../sbase/steps.py:195\n Then Assert element 'a:contains(\"Sign in\")' # ../../sbase/steps.py:120\n And Assert text \"You have been signed out!\" # ../../sbase/steps.py:145\n \u2705 Scenario Passed!\n\n- Dashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n--- LogPath: /Users/michael/github/SeleniumBase/examples/behave_bdd/latest_logs/\n==================================================================================\n1 feature passed, 0 failed, 0 skipped\n1 scenario passed, 0 failed, 0 skipped\n12 steps passed, 0 failed, 0 skipped, 0 undefined\nTook 0m4.682s\n
\ud83d\udc1d Another example, which uses higher-level Behave steps to simplify the .feature
file:
> cd examples/behave_bdd/\n> behave features/calculator.feature:61 -T -D dashboard -k\n\nDashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n********************************************************************************\nFeature: SeleniumBase scenarios for the Calculator App # features/calculator.feature:1\n\n Background: # features/calculator.feature:3\n\n Scenario: 7.0 \u00d7 (3 + 3) = 42 # features/calculator.feature:49\n Given Open the Calculator App # features/steps/calculator.py:4\n When Press C # features/steps/calculator.py:9\n And Press 7 # features/steps/calculator.py:79\n And Press . # features/steps/calculator.py:104\n And Press 0 # features/steps/calculator.py:94\n And Press \u00d7 # features/steps/calculator.py:29\n And Press ( # features/steps/calculator.py:14\n And Press 3 # features/steps/calculator.py:59\n And Press + # features/steps/calculator.py:39\n And Press 3 # features/steps/calculator.py:59\n And Press ) # features/steps/calculator.py:19\n Then Verify output is \"7.0\u00d7(3+3)\" # features/steps/calculator.py:135\n When Press = # features/steps/calculator.py:44\n Then Verify output is \"42\" # features/steps/calculator.py:135\n \u2705 Scenario Passed!\n\n- Dashboard: /Users/michael/github/SeleniumBase/examples/behave_bdd/dashboard.html\n--- LogPath: /Users/michael/github/SeleniumBase/examples/behave_bdd/latest_logs/\n==================================================================================\n1 feature passed, 0 failed, 0 skipped\n1 scenario passed, 0 failed, 8 skipped\n14 steps passed, 0 failed, 60 skipped, 0 undefined\nTook 0m1.672s\n
\ud83d\udc1d\u26aa With the Dashboard enabled, you'll get one of these:
"}, {"location": "examples/behave_bdd/ReadMe/#behave-gherkin-files", "title": "\ud83d\udc1d Behave-Gherkin files", "text": "\ud83d\udc1d The *.feature
files can use any step seen from:
behave --steps-catalog\n
\ud83d\udc1d SeleniumBase includes several pre-made Behave steps, which you can use by creating a Python file with the following line in your features/steps/
directory:
from seleniumbase.behave import steps # noqa\n
\ud83d\udc1d Inside your features/environment.py
file, you should have the following:
from seleniumbase import BaseCase\nfrom seleniumbase.behave import behave_sb\nbehave_sb.set_base_class(BaseCase) # Accepts a BaseCase subclass\nfrom seleniumbase.behave.behave_sb import before_all # noqa\nfrom seleniumbase.behave.behave_sb import before_feature # noqa\nfrom seleniumbase.behave.behave_sb import before_scenario # noqa\nfrom seleniumbase.behave.behave_sb import before_step # noqa\nfrom seleniumbase.behave.behave_sb import after_step # noqa\nfrom seleniumbase.behave.behave_sb import after_scenario # noqa\nfrom seleniumbase.behave.behave_sb import after_feature # noqa\nfrom seleniumbase.behave.behave_sb import after_all # noqa\n
\ud83d\udc1d If you've already created a subclass of BaseCase
with custom methods, you can swap BaseCase
in with your own subclass, which will allow you to easily use your own custom methods in your Behave step definitions.
\ud83d\udc1d Here's an example Python file in the features/steps/
folder:
from behave import step\n\n\n@step(\"Open the Swag Labs Login Page\")\ndef go_to_swag_labs(context):\n sb = context.sb\n sb.open(\"https://www.saucedemo.com\")\n sb.clear_local_storage()\n\n\n@step(\"Login to Swag Labs with {user}\")\ndef login_to_swag_labs(context, user):\n sb = context.sb\n sb.type(\"#user-name\", user)\n sb.type(\"#password\", \"secret_sauce\\n\")\n\n\n@step(\"Verify that the current user is logged in\")\ndef verify_logged_in(context):\n sb = context.sb\n sb.assert_element(\"#header_container\")\n sb.assert_element(\"#react-burger-menu-btn\")\n sb.assert_element(\"#shopping_cart_container\")\n\n\n@step('Add \"{item}\" to cart')\ndef add_item_to_cart(context, item):\n sb = context.sb\n sb.click('div.inventory_item:contains(\"%s\") button[name*=\"add\"]' % item)\n
\ud83d\udc1d A *.feature
file could look like this:
Feature: SeleniumBase scenarios for the Swag Labs App\n\n Background:\n Given Open the Swag Labs Login Page\n\n Scenario: User can order a backpack from the store\n When Login to Swag Labs with standard_user\n Then Verify that the current user is logged in\n And Save price of \"Backpack\" to <item_price>\n When Add \"Backpack\" to Cart\n Then Verify shopping cart badge shows 1 item(s)\n When Click on shopping cart icon\n And Click Checkout\n And Enter checkout info: First, Last, 12345\n And Click Continue\n Then Verify 1 \"Backpack\"(s) in cart\n And Verify cost of \"Backpack\" is <item_price>\n And Verify item total is $29.99\n And Verify tax amount is $2.40\n And Verify total cost is $32.39\n When Click Finish\n Then Verify order complete\n When Logout from Swag Labs\n Then Verify on Login page\n
\ud83d\udc1d Here's another example of a *.feature
file:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert text \"Welcome!\" in \"h1\"\n And Highlight element \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n When Click link \"Sign out\"\n Then Assert element 'a:contains(\"Sign in\")'\n And Assert text \"You have been signed out!\"\n
\ud83d\udc1d If there's a test failure, that's easy to spot:
Feature: SeleniumBase scenarios for the Fail Page # features/fail_page.feature:1\n\n Scenario: Fail test on purpose to see what happens # features/fail_page.feature:3\n When Open the Fail Page # features/steps/fail_page.py:4\n Then Fail test on purpose # features/steps/fail_page.py:9\n Assertion Failed: This test fails on purpose!\n Captured stdout:\n >>> STEP FAILED: (#2) Fail test on purpose\n Class / Feature: SeleniumBase scenarios for the Fail Page\n Test / Scenario: Fail test on purpose to see what happens\n\n \u274c Scenario Failed!\n
\ud83d\udc1d\ud83c\udf96\ufe0f For convenience, the SeleniumBase Behave GUI lets you run behave
scripts from a Desktop app.
\ud83d\udc1d\ud83c\udf96\ufe0f To launch it, call sbase behave-gui
or sbase gui-behave
:
sbase behave-gui\n* Starting the SeleniumBase Behave Commander GUI App...\n
\ud83d\udc1d\ud83c\udf96\ufe0f You can customize the tests that show up there:
sbase behave-gui # all tests\nsbase behave-gui -i=calculator # tests with \"calculator\" in the name\nsbase behave-gui features/ # tests located in the \"features/\" folder\nsbase behave-gui features/calculator.feature # tests in that feature\n
To learn more about SeleniumBase, check out the Docs Site: All the code is on GitHub:
"}, {"location": "examples/chart_maker/ReadMe/", "title": "\ud83d\udcf6 Chart Maker", "text": ""}, {"location": "examples/chart_maker/ReadMe/#chartmaker", "title": "\ud83d\udcca ChartMaker \ud83d\udcf6 ChartMaker API", "text": "
SeleniumBase ChartMaker lets you use Python to generate HTML charts.
(Click to see a presentation with multiple charts)
Here's how to run a simple pie chart presentation from GitHub => seleniumbase/SeleniumBase/examples/chart_maker:
cd examples/chart_maker\npytest my_chart.py\n
Here's the code for that pie chart presentation (GitHub => seleniumbase/SeleniumBase/examples/chart_maker/my_chart.py):
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker(self):\n self.create_presentation()\n self.create_pie_chart(title=\"Automated Tests\")\n self.add_data_point(\"Passed\", 7, color=\"#95d96f\")\n self.add_data_point(\"Untested\", 2, color=\"#eaeaea\")\n self.add_data_point(\"Failed\", 1, color=\"#f1888f\")\n self.add_slide(\"<p>Pie Chart</p>\" + self.extract_chart())\n self.begin_presentation(filename=\"my_chart.html\")\n
Here's how to run an example presentation with multiple charts:
cd examples/chart_maker\npytest chart_presentation.py\n
Here are screenshots from the examples:
Here's a line chart example:from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker(self):\n self.create_presentation()\n self.create_line_chart(\n title=\"Time Outside\", subtitle=\"Last Week\", unit=\"Minutes\")\n self.add_data_point(\"Sun\", 5)\n self.add_data_point(\"Mon\", 10)\n self.add_data_point(\"Tue\", 20)\n self.add_data_point(\"Wed\", 40)\n self.add_data_point(\"Thu\", 80)\n self.add_data_point(\"Fri\", 65)\n self.add_data_point(\"Sat\", 50)\n self.add_slide(\"<p>Line Chart</p>\" + self.extract_chart())\n self.begin_presentation(filename=\"line_chart.html\", interval=8)\n
This example is from test_line_chart.py, which you can run from the examples/chart_maker
folder with the following command:
pytest test_line_chart.py\n
Because that presentation above has an interval
set to 8
, it will automatically advance to the next slide after 8 seconds. (Or exit if there are no more slides.)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyChartMakerClass(BaseCase):\n def test_chart_maker_presentation(self):\n self.create_presentation(theme=\"sky\")\n\n self.create_pie_chart(title=\"Automated Tests\")\n self.add_data_point(\"Passed\", 7, color=\"#95d96f\")\n self.add_data_point(\"Untested\", 2, color=\"#eaeaea\")\n self.add_data_point(\"Failed\", 1, color=\"#f1888f\")\n self.add_slide(\"<p>Pie Chart</p>\" + self.extract_chart())\n\n self.create_bar_chart(title=\"Language\")\n self.add_data_point(\"Python\", 33, color=\"Orange\")\n self.add_data_point(\"JavaScript\", 27, color=\"Teal\")\n self.add_data_point(\"HTML + CSS\", 21, color=\"Purple\")\n self.add_slide(\"<p>Bar Chart</p>\" + self.extract_chart())\n\n self.create_column_chart(title=\"Colors\")\n self.add_data_point(\"Red\", 10, color=\"Red\")\n self.add_data_point(\"Green\", 25, color=\"Green\")\n self.add_data_point(\"Blue\", 15, color=\"Blue\")\n self.add_slide(\"<p>Column Chart</p>\" + self.extract_chart())\n\n self.create_line_chart(title=\"Last Week's Data\")\n self.add_data_point(\"Sun\", 5)\n self.add_data_point(\"Mon\", 10)\n self.add_data_point(\"Tue\", 20)\n self.add_data_point(\"Wed\", 40)\n self.add_data_point(\"Thu\", 80)\n self.add_data_point(\"Fri\", 65)\n self.add_data_point(\"Sat\", 50)\n self.add_slide(\"<p>Line Chart</p>\" + self.extract_chart())\n\n self.begin_presentation(filename=\"chart_presentation.html\")\n
Here's how to run that example:
cd examples/chart_maker\npytest chart_presentation.py\n
(Press the Right Arrow to advance to the next slide in that chart presentation)
(Click to see a live example of that presentation)
Multi-Series charts can also be created. Try the available examples to learn more.
self.create_pie_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript pie chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_bar_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript bar chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_column_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True):\n\"\"\" Creates a JavaScript column chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_line_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True):\n\"\"\" Creates a JavaScript line chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n zero - If True, the y-axis always starts at 0. (Default: False).\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
self.create_area_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True):\n\"\"\" Creates a JavaScript area chart using \"HighCharts\".\n @Params\n chart_name - If creating multiple charts,\n use this to select which one.\n title - The title displayed for the chart.\n subtitle - The subtitle displayed for the chart.\n data_name - The series name. Useful for multi-series charts.\n If no data_name, will default to using \"Series 1\".\n unit - The description label given to the chart's y-axis values.\n zero - If True, the y-axis always starts at 0. (Default: False).\n libs - The option to include Chart libraries (JS and CSS files).\n Should be set to True (default) for the first time creating\n a chart on a web page. If creating multiple charts on the\n same web page, you won't need to re-import the libraries\n when creating additional charts.\n labels - If True, displays labels on the chart for data points.\n legend - If True, displays the data point legend on the chart.\n\"\"\"\n
If creating multiple charts at the same time, you can pass the chart_name
parameter to distinguish between different charts.
self.add_data_point(label, value, color=None, chart_name=None):\n\"\"\" Add a data point to a SeleniumBase-generated chart.\n @Params\n label - The label name for the data point.\n value - The numeric value of the data point.\n color - The HTML color of the data point.\n Can be an RGB color. Eg: \"#55ACDC\".\n Can also be a named color. Eg: \"Teal\".\n chart_name - If creating multiple charts,\n use this to select which one.\n\"\"\"\n
Adding a new data series to an existing chart: self.add_series_to_chart(self, data_name=None, chart_name=None):\n\"\"\" Add a new data series to an existing chart.\n This allows charts to have multiple data sets.\n @Params\n data_name - Set the series name. Useful for multi-series charts.\n chart_name - If creating multiple charts,\n use this to select which one.\n\"\"\"\n
Saving a chart to a file: self.save_chart(chart_name=None, filename=None):\n\"\"\" Saves a SeleniumBase-generated chart to a file for later use.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n filename - The name of the HTML file that you wish to\n save the chart to. (filename must end in \".html\")\n\"\"\"\n
The full HTML of the chart is saved to the saved_charts/
folder.
self.extract_chart(chart_name=None):\n\"\"\" Extracts the HTML from a SeleniumBase-generated chart.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n\"\"\"\n
Displaying a chart in the browser window: self.display_chart(chart_name=None, filename=None):\n\"\"\" Displays a SeleniumBase-generated chart in the browser window.\n @Params\n chart_name - If creating multiple charts at the same time,\n use this to select the one you wish to use.\n filename - The name of the HTML file that you wish to\n save the chart to. (filename must end in \".html\")\n interval - The delay time for auto-advancing charts. (in seconds)\n If set to 0 (default), auto-advancing is disabled.\n\"\"\"\n
All methods have the optional chart_name
argument, which is only needed when storing multiple charts at the same time.
SeleniumBase Dialog Boxes let your users provide input in the middle of automation scripts.
cd examples/dialog_boxes\npytest test_dialog_boxes.py\n
Here's a code snippet from that: self.open(\"https://xkcd.com/1920/\")\nskip_button = [\"SKIP\", \"red\"] # Can be a [text, color] list or tuple.\nbuttons = [\"Fencing\", \"Football\", \"Metaball\", \"Go/Chess\", skip_button]\nmessage = \"Choose a sport:\"\nchoice = self.get_jqc_button_input(message, buttons)\nif choice == \"Fencing\":\n self.open(\"https://xkcd.com/1424/\")\n
choice = self.get_jqc_button_input(\"Ready?\", [\"YES\", \"NO\"])\nprint(choice) # This prints \"YES\" or \"NO\"\n\n# You may want to customize the color of buttons\nbuttons = [(\"YES\", \"green\"), (\"NO\", \"red\")]\nchoice = self.get_jqc_button_input(\"Ready?\", buttons)\n
Here's a simple form with an input field: text = self.get_jqc_text_input(\"Enter text:\", [\"Search\"])\nprint(text) # This prints the text entered\n
This form has an input field and buttons: message = \"Type your name and choose a language:\"\nbuttons = [\"Python\", \"JavaScript\"]\ntext, choice = self.get_jqc_form_inputs(message, buttons)\nprint(\"Your name is: %s\" % text)\nprint(\"You picked %s!\" % choice)\n
You can customize options if you want: # Themes: bootstrap, modern, material, supervan, light, dark, seamless\noptions = [(\"theme\", \"modern\"), (\"width\", \"50%\")]\nself.get_jqc_text_input(\"You Won!\", [\"OK\"], options)\n
Default options can be set with set_jqc_theme()
: self.set_jqc_theme(\"light\", color=\"green\", width=\"38%\")\n\n# To reset jqc theme settings to factory defaults\nself.reset_jqc_theme()\n
All methods for Dialog Boxes: self.get_jqc_button_input(message, buttons, options=None)\n\nself.get_jqc_text_input(message, button=None, options=None)\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\nself.set_jqc_theme(theme, color=None, width=None)\n\nself.reset_jqc_theme()\n\nself.activate_jquery_confirm() # Automatic for jqc methods\n
Detailed method summaries for Dialog Boxes: self.get_jqc_button_input(message, buttons, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the text of the button clicked.\nIf running in headless mode, the last button text is returned.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbuttons: A list of tuples for text and color.\n Example: [(\"Yes!\", \"green\"), (\"No!\", \"red\")]\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.get_jqc_text_input(message, button=None, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the text submitted by the input.\nIf running in headless mode, the text returned is \"\" by default.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbutton: A 2-item list or tuple for text and color. Or just the text.\n Example: [\"Submit\", \"blue\"] -> (default button if not specified)\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\"\"\"\nPop up a jquery-confirm box and return the input/button texts as tuple.\nIf running in headless mode, returns the (\"\", buttons[-1][0]) tuple.\n@Params\nmessage: The message to display in the jquery-confirm dialog.\nbuttons: A list of tuples for text and color.\n Example: [(\"Yes!\", \"green\"), (\"No!\", \"red\")]\n Available colors: blue, green, red, orange, purple, default, dark.\n A simple text string also works: \"My Button\". (Uses default color.)\noptions: A list of tuples for options to set.\n Example: [(\"theme\", \"bootstrap\"), (\"width\", \"450px\")]\n Available theme options: bootstrap, modern, material, supervan,\n light, dark, and seamless.\n Available colors: (For the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\n Example option for changing the border color: (\"color\", \"default\")\n Width can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.set_jqc_theme(theme, color=None, width=None)\n\"\"\" Sets the default jquery-confirm theme and width (optional).\nAvailable themes: \"bootstrap\", \"modern\", \"material\", \"supervan\",\n \"light\", \"dark\", and \"seamless\".\nAvailable colors: (This sets the BORDER color, NOT the button color.)\n \"blue\", \"default\", \"green\", \"red\", \"purple\", \"orange\", \"dark\".\nWidth can be set using percent or pixels. Eg: \"36.0%\", \"450px\".\n\"\"\"\n\nself.reset_jqc_theme()\n\"\"\" Resets the jqc theme settings to factory defaults. \"\"\"\n\nself.activate_jquery_confirm() # Automatic for jqc methods\n\"\"\" See https://craftpip.github.io/jquery-confirm/ for usage. \"\"\"\n
\u2705 \ud83d\udec2 Automated/Manual Hybrid Mode (MasterQA) MasterQA uses SeleniumBase Dialog Boxes to speed up manual testing by having automation perform all the browser actions while the manual tester handles validation. See the MasterQA GitHub page for examples.
"}, {"location": "examples/example_logs/ReadMe/", "title": "\ud83d\udcca Dashboard / Reports", "text": ""}, {"location": "examples/example_logs/ReadMe/#logs-the-dashboard-and-reports", "title": "Logs, The Dashboard, and Reports", "text": "\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. If --archive-logs
is specified (or if ARCHIVE_EXISTING_LOGS is set to True in settings.py), test logs will also get archived to the archived_logs/
folder. Otherwise, the log files will be cleaned out when the next test run begins (by default).
pytest test_fail.py\n
(Log files in SeleniumBase/examples/example_logs were generated when test_fail.py ran and failed.)
Examples of expected log files generated during failures:
In addition to log files, you can also generate dashboards and test reports.
The SeleniumBase Dashboard:\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python 3's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py test_image_saving.py --dashboard --rs --headless\n
Pytest Reports: \ud83d\udd35 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\ud83d\udd35 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\ud83d\udd35 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest-html
reports in Jenkins, you may need to configure Jenkins settings for the HTML to render correctly. This is due to Jenkins CSP changes. That setting can be changed from Manage Jenkins
> Script Console
by running:
System.setProperty(\"hudson.model.DirectoryBrowserSupport.CSP\", \"\")\n
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
pynose Test Reports: The pynose
--report
option gives you a fancy report after your tests complete.
pynose test_suite.py --report\n
(NOTE: You can add --show-report
to immediately display pynose reports after the test suite completes. Only use --show-report
when running tests locally because it pauses the test run.)
(The behave_bdd/ folder can be found in the examples/ folder.)
behave behave_bdd/features/ -D dashboard -D headless\n
You can also use --junit
to get .xml
reports for each Behave feature. Jenkins can use these files to display better reporting for your tests.
behave behave_bdd/features/ --junit -D rs -D headless\n
"}, {"location": "examples/master_qa/ReadMe/", "title": "\ud83d\udec2 MasterQA Mode", "text": "MasterQA combines automation with manual verification steps. Here's code from basic_masterqa_test_0.py:
from seleniumbase import MasterQA\n\nclass MasterQATests(MasterQA):\n def test_masterqa(self):\n self.open(\"https://xkcd.com/1700/\")\n self.verify(\"Do you see a webcomic?\")\n self.open(\"https://seleniumbase.io/demo_page\")\n self.highlight('table')\n self.verify(\"Do you see elements in a table?\")\n self.open(\"https://seleniumbase.io/devices/\")\n self.highlight(\"div.mockup-wrapper\")\n self.verify(\"Do you see 4 computer devices?\")\n
After each automation checkpoint, a pop-up window will ask the user questions for each verification command.
When the test run completes, as seen from this longer example, you'll reach the results page that appears after answering all the verification questions. (Failed verifications generate links to screenshots and log files.)
You may have noticed the Incomplete Test Runs
row on the results page. If the value for that is not zero, it means that one of the automated steps failed. This could happen if you tell your script to perform an action on an element that doesn't exist. Now that we're mixing automation with manual QA, it's good to tell apart the failures from each. The results_table CSV file contains a spreadsheet with the details of each failure (if any) for both manual and automated steps.
How to run the example tests from scratch:
git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase\npip install .\ncd examples/master_qa\npytest basic_masterqa_test_0.py\npytest masterqa_test_1.py\n
At the end of your test run, you'll receive a report with results, screenshots, and log files. Close the Results Page window when you're done.
Check out masterqa_test_1.py to learn how to write your own MasterQA tests:
You'll notice that tests are written the same way as regular SeleniumBase tests, with the key difference being a different import: from seleniumbase import MasterQA
rather than from seleniumbase import BaseCase
. Now your Python test class will import MasterQA
instead of BaseCase
.
To add a manual verification step, use self.verify()
in the code after each part of your test that needs a manual verification step. If you want to include a custom question, add text inside that call (in quotes). Example:
self.verify()\n\nself.verify(\"Can you find the moon?\")\n
MasterQA is powered by SeleniumBase, the most advanced open-source automation framework on the Planet.
"}, {"location": "examples/presenter/ReadMe/", "title": "\ud83c\udf9e\ufe0f Presentation Maker", "text": ""}, {"location": "examples/presenter/ReadMe/#presenter", "title": "\ud83d\udcd1 Presenter \ud83c\udf9e\ufe0f", "text": "SeleniumBase Presenter (slide-maker) lets you use Python to generate HTML presentations.
Here's a sample presentation:
(Click on the image/GIF for the actual presentation)
(Here's the code for that presentation)
Slides can include HTML, code, images, and iframes.
Here's how to run the example presentation:
cd examples/presenter\npytest my_presentation.py\n
Here's a presentation with a chart:
(Click on the image/GIF for the actual presentation)
(Here's the code for that presentation)
Here's how to run that example:
cd examples/presenter\npytest core_presentation.py\n
Creating a new presentation: self.create_presentation(name=None, theme=\"serif\", transition=\"default\")\n\"\"\" Creates a Reveal-JS presentation that you can add slides to.\n @Params\n name - If creating multiple presentations at the same time,\n use this to specify the name of the current presentation.\n theme - Set a theme with a unique style for the presentation.\n Valid themes: \"serif\" (default), \"sky\", \"white\", \"black\",\n \"simple\", \"league\", \"moon\", \"night\",\n \"beige\", \"blood\", and \"solarized\".\n transition - Set a transition between slides.\n Valid transitions: \"none\" (default), \"slide\", \"fade\",\n \"zoom\", \"convex\", and \"concave\".\n\"\"\"\n
If creating multiple presentations at the same time, you can pass the name
parameter to distinguish between different presentations. Notes are disabled by default. You can enable notes by specifying: show_notes=True
self.add_slide(content=None, image=None, code=None, iframe=None,\n content2=None, notes=None, transition=None, name=None)\n\"\"\" Allows the user to add slides to a presentation.\n @Params\n content - The HTML content to display on the presentation slide.\n image - Attach an image (from a URL link) to the slide.\n code - Attach code of any programming language to the slide.\n Language-detection will be used to add syntax formatting.\n iframe - Attach an iFrame (from a URL link) to the slide.\n content2 - HTML content to display after adding an image or code.\n notes - Additional notes to include with the slide.\n ONLY SEEN if show_notes is set for the presentation.\n transition - Set a transition between slides. (overrides previous)\n Valid transitions: \"none\" (default), \"slide\", \"fade\",\n \"zoom\", \"convex\", and \"concave\".\n name - If creating multiple presentations at the same time,\n use this to select the presentation to add slides to.\n\"\"\"\n
Running a presentation: self.begin_presentation(\n filename=\"my_presentation.html\", show_notes=False, interval=0)\n\"\"\" Begin a Reveal-JS Presentation in the web browser.\n @Params\n name - If creating multiple presentations at the same time,\n use this to select the one you wish to add slides to.\n filename - The name of the HTML file that you wish to\n save the presentation to. (filename must end in \".html\")\n show_notes - When set to True, the Notes feature becomes enabled,\n which allows presenters to see notes next to slides.\n interval - The delay time between autoplaying slides. (in seconds)\n If set to 0 (default), autoplay is disabled.\n\"\"\"\n
Before the presentation is run, the full HTML is saved to the saved_presentations/
folder.
All methods have the optional name
argument, which is only needed if you're creating multiple presentations at once.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyPresenterClass(BaseCase):\n def test_presenter(self):\n self.create_presentation(theme=\"serif\")\n self.add_slide(\n '<h1>Welcome</h1><br />\\n'\n '<h3>Press the <b>Right Arrow</b></h3>')\n self.add_slide(\n '<h3>SeleniumBase Presenter</h3><br />\\n'\n '<img width=\"240\" src=\"https://seleniumbase.io/img/logo3a.png\" />'\n '<span style=\"margin:144px;\" />'\n '<img src=\"https://seleniumbase.io/other/python_3d_logo.png\" />'\n '<br /><br />\\n<h4>Create presentations with <b>Python</b></h4>')\n self.add_slide(\n '<h3>Make slides using <b>HTML</b>:</h3><br />\\n'\n '<table style=\"padding:10px;border:4px solid black;font-size:50;\">'\n '\\n<tr style=\"background-color:CDFFFF;\">\\n'\n '<th>Row ABC</th><th>Row XYZ</th></tr>\\n'\n '<tr style=\"background-color:DCFDDC;\">'\n '<td>Value ONE</td><td>Value TWO</td></tr>\\n'\n '<tr style=\"background-color:DFDFFB;\">\\n'\n '<td>Value THREE</td><td>Value FOUR</td></tr>\\n'\n '</table><br />\\n<h4>(HTML <b>table</b> example)</h4>')\n self.add_slide(\n '<h3>Keyboard Shortcuts:</h3>\\n'\n '<table style=\"padding:10px;border:4px solid black;font-size:30;'\n 'background-color:FFFFDD;\">\\n'\n '<tr><th>Key</th><th>Action</th></tr>\\n'\n '<tr><td><b>=></b></td><td>Next Slide (N also works)</td></tr>\\n'\n '<tr><td><b><=</b></td><td>Previous Slide (P also works)</td></tr>'\n '\\n<tr><td>F</td><td>Full Screen Mode</td></tr>\\n'\n '<tr><td>O</td><td>Overview Mode Toggle</td></tr>\\n'\n '<tr><td>esc</td><td>Exit Full Screen / Overview Mode</td></tr>\\n'\n '<tr><td><b>.</b></td><td>Pause/Resume Toggle</td></tr>\\n'\n '<tr><td>space</td><td>Next Slide (alternative)</td></tr></table>')\n self.add_slide(\n '<h3>Add <b>images</b> to slides:</h3>',\n image=\"https://seleniumbase.github.io/other/seagulls.jpg\")\n self.add_slide(\n '<h3>Add <b>code</b> to slides:</h3>',\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n 'class MyTestClass(BaseCase):\\n\\n'\n ' def test_basics(self):\\n'\n ' self.open(\"https://store.xkcd.com/search\")\\n'\n ' self.type(\\'input[name=\"q\"]\\', \"xkcd book\\\\n\")\\n'\n ' self.assert_text(\"xkcd: volume 0\", \"h3\")\\n'\n ' self.open(\"https://xkcd.com/353/\")\\n'\n ' self.assert_title(\"xkcd: Python\")\\n'\n ' self.assert_element(\\'img[alt=\"Python\"]\\')\\n'\n ' self.click(\\'a[rel=\"license\"]\\')\\n'\n ' self.assert_text(\"free to copy and reuse\")\\n'\n ' self.go_back()\\n'\n ' self.click_link(\"About\")\\n'\n ' self.assert_exact_text(\"xkcd.com\", \"h2\")'))\n self.add_slide(\n \"<h3>Highlight <b>code</b> in slides:</h3>\",\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n '<mark>class MyTestClass(BaseCase):</mark>\\n\\n'\n ' def test_basics(self):\\n'\n ' self.open(\"https://store.xkcd.com/search\")\\n'\n ' self.type(\\'input[name=\"q\"]\\', \"xkcd book\\\\n\")\\n'\n ' self.assert_text(\"xkcd: volume 0\", \"h3\")'))\n self.add_slide(\n '<h3>Add <b>iFrames</b> to slides:</h3>',\n iframe=\"https://seleniumbase.io/demo_page\")\n self.add_slide(\n '<h3>Getting started is <b>easy</b>:</h3>',\n code=(\n 'from seleniumbase import BaseCase\\n\\n'\n 'class MyPresenterClass(BaseCase):\\n\\n'\n ' def test_presenter(self):\\n'\n ' self.create_presentation(theme=\"serif\")\\n'\n ' self.add_slide(\"Welcome to Presenter!\")\\n'\n ' self.add_slide(\\n'\n ' \"Add code to slides:\",\\n'\n ' code=(\\n'\n ' \"from seleniumbase import BaseCase\\\\n\\\\n\"\\n'\n ' \"class MyPresenterClass(BaseCase):\\\\n\\\\n\"\\n'\n ' \" def test_presenter(self):\\\\n\"\\n'\n ' \" self.create_presentation()\\\\n\"))\\n'\n ' self.begin_presentation(\\n'\n ' filename=\"demo.html\", show_notes=True)'))\n self.add_slide(\n '<h3>Include <b>notes</b> with slides:</h3><br />',\n code=('self.add_slide(\"[Your HTML goes here]\",\\n'\n ' code=\"[Your software code goes here]\",\\n'\n ' content2=\"[Additional HTML goes here]\",\\n'\n ' notes=\"[Attached speaker notes go here]\"\\n'\n ' \"[Note A! -- Note B! -- Note C! ]\")'),\n notes='<h2><ul><li>Note A!<li>Note B!<li>Note C!<li>Note D!</h2>',\n content2=\"<h4>(Notes can include HTML tags)</h4>\")\n self.add_slide(\n '<h3>Multiple <b>themes</b> available:</h3>',\n code=(\n 'self.create_presentation(theme=\"serif\")\\n\\n'\n 'self.create_presentation(theme=\"sky\")\\n\\n'\n 'self.create_presentation(theme=\"simple\")\\n\\n'\n 'self.create_presentation(theme=\"white\")\\n\\n'\n 'self.create_presentation(theme=\"moon\")\\n\\n'\n 'self.create_presentation(theme=\"black\")\\n\\n'\n 'self.create_presentation(theme=\"night\")\\n\\n'\n 'self.create_presentation(theme=\"beige\")\\n\\n'\n 'self.create_presentation(theme=\"league\")'))\n self.add_slide(\n '<h2><b>The End</b></h2>',\n image=\"https://seleniumbase.github.io/img/sb_logo_10.png\")\n self.begin_presentation(\n filename=\"presenter.html\", show_notes=True, interval=0)\n
That example is from my_presentation.py, which you can run from the examples/presenter
folder with the following command:
pytest my_presentation.py\n
Saving a presentation: If you want to save the presentation you created as an HTML file, use:
self.save_presentation(filename=\"my_presentation.html\", show_notes=True)\n
Presentations automatically get saved when calling:
self.begin_presentation(show_notes=True)\n
Special abilities: If you want to highlight multiple lines at different times in the same slide with the <mark>
/ </mark>
tags, you can use the new <mk-0>
-</mk-0>
, <mk-1>
-</mk-1>
tags, which will generate multiple HTML slides from one Python slide.
Example:
self.add_slide(\n code=(\n <p><mk-0>Highlight this on the 1st generated slide</mk-0></p>\n <p><mk-1>Highlight this on the 2nd generated slide</mk-1></p>\n <p><mk-2>Highlight this on the 3rd generated slide</mk-2></p>\n <p><mk-3>Highlight this on the 4th generated slide</mk-3></p>\n )\n)\n
Those should automatically get converted to <mark>
... </mark>
on their turn:
Eg. First generated slide:
<p><mark>Highlight this on the first generated slide</mark></p>\n<p>Highlight this on the second generated slide</p>\n<p>Highlight this on the third generated slide</p>\n<p>Highlight this on the fourth generated slide></p>\n
Eg. Second generated slide:
<p>Highlight this on the first generated slide</p>\n<p><mark>Highlight this on the second generated slide</mark></p>\n<p>Highlight this on the third generated slide</p>\n<p>Highlight this on the fourth generated slide></p>\n
Etc...
"}, {"location": "examples/tour_examples/ReadMe/", "title": "\ud83d\ude8e Tour Maker", "text": ""}, {"location": "examples/tour_examples/ReadMe/#interactive-product-tours", "title": "Interactive Product Tours \ud83d\ude8e", "text": "Increase SaaS Product Adoption by 10x or more.
IntroJS, Bootstrap Tour, DriverJS, Shepherd, and Hopscotch.
A tour demo: (with autoplay)
SeleniumBase maps_introjs_tour.py
cd examples/tour_examples\npytest maps_introjs_tour.py --interval=1\n
Here's a longer version:
SeleniumBase google_tour.py
cd examples/tour_examples\npytest google_tour.py\n
(From GitHub => SeleniumBase/examples/tour_examples)
"}, {"location": "examples/tour_examples/ReadMe/#creating-a-new-tour", "title": "Creating a new tour", "text": ""}, {"location": "examples/tour_examples/ReadMe/#to-create-a-tour-utilizing-the-shepherd-library-use-one-of-the-following", "title": "To create a tour utilizing the Shepherd Library, use one of the following", "text": "self.create_shepherd_tour()
OR
self.create_tour(theme=\"shepherd\")
You can pass a custom theme to change the look & feel of Shepherd tours. Valid themes for Shepherd Tours are dark
, light
/ arrows
, default
, square
, and square-dark
.
self.create_bootstrap_tour()
OR
self.create_tour(theme=\"bootstrap\")
self.create_introjs_tour()
OR
self.create_tour(theme=\"introjs\")
self.create_driverjs_tour()
OR
self.create_tour(theme=\"driverjs\")
self.create_hopscotch_tour()
OR
self.create_tour(theme=\"hopscotch\")
self.add_tour_step(message, css_selector, title, alignment, theme)
With the self.add_tour_step()
method, you must first pass a message to display. You can then specify a web element to attach to (by using CSS selectors). If no element is specified, the tour step will tether to the top of the screen by default. You can also add an optional title above the message to display with the tour step, as well as change the theme for that step (Shepherd tours only), and even specify the alignment (which is the side of the element that you want the tour message to tether to).
You can play a tour by calling:
self.play_tour(interval)
If you specify an interval
(optional), the tour will automatically walk through each step after that many seconds have passed.
All methods have the optional name
argument, which is only needed if you're creating multiple tours at once. Then, when you're adding a step or playing a tour, SeleniumBase knows which tour you're referring too. You can avoid using the name
arg for multiple tours if you play a tour before creating a new one.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTourClass(BaseCase):\n\n def test_google_tour(self):\n self.open('https://google.com/ncr')\n self.wait_for_element('input[title=\"Search\"]')\n self.hide_elements(\"iframe\")\n\n self.create_tour(theme=\"dark\")\n self.add_tour_step(\"Welcome to Google!\", title=\"SeleniumBase Tours\")\n self.add_tour_step(\"Type in your query here.\", '[title=\"Search\"]')\n self.play_tour()\n\n self.highlight_type('input[title=\"Search\"]', \"Google\")\n self.wait_for_element('[role=\"listbox\"]') # Wait for autocomplete\n\n self.create_tour(theme=\"light\")\n self.add_tour_step(\"Then click to search.\", '[value=\"Google Search\"]')\n self.add_tour_step(\"Or press [ENTER] after entry.\", '[title=\"Search\"]')\n self.play_tour()\n
"}, {"location": "examples/tour_examples/ReadMe/#that-code-is-from-google_tourpy-which-you-can-run-from-the-tour_examples-folder-with-the-following-command", "title": "That code is from google_tour.py, which you can run from the tour_examples/
folder with the following command", "text": "pytest google_tour.py\n
"}, {"location": "examples/tour_examples/ReadMe/#exporting-a-tour", "title": "Exporting a Tour", "text": "If you want to save the tour you created as a JavaScript file, use:
self.export_tour()
OR
self.export_tour(name=None, filename=\"my_tour.js\")
(name
is optional unless you gave custom names to your tours when you created them. filename
is the name of the file to save the JavaScript to.) Once you've exported your tour, you can use it outside of SeleniumBase. You can even copy the tour's JavaScript code to the Console of your web browser to play the tour from there (you need to be on the correct web page for it to work).
Automated Visual Regression Testing can help you detect when the layout of a web page has changed. Instead of comparing pixels from screenshots, layout differences can be detected by comparing HTML tags and attributes with a baseline. If a change is detected, it could mean that something broke, the web page was redesigned, or dynamic content changed.
To handle automated visual testing, SeleniumBase uses the self.check_window()
method, which can set visual baselines for comparison and then compare the latest versions of web pages to the existing baseline.
The first time a test calls self.check_window()
with a unique name
parameter, the visual baseline is set, which means a folder is created with the following files:
After the first time self.check_window()
is called, later calls will compare the HTML tags and attributes of the latest window to the ones from the first call (or to the ones from the call when the baseline was last reset). Additionally, a latest.png
screenshot is saved in the same folder, which can help you determine if/when the existing baseline needs to be reset.
Here's an example call:
self.check_window(name=\"first_test)\", level=3)\n
On the first run (or if the baseline is being set/reset) the \"level\" doesn't matter because that's only used for comparing the current layout to the existing baseline.
Here's how the level system works:
As shown, Level-3 is the most strict, Level-1 is the least strict. If the comparisons from the latest window to the existing baseline don't match, the current test will fail, except for Level-0 checks, which print Level-3 results without failing the test.
You can reset the visual baseline on the command line by adding the following parameter at runtime:
--visual_baseline\n
As long as --visual_baseline
is used on the command line while running tests, the self.check_window()
method cannot fail because it will rebuild the visual baseline rather than comparing the html tags of the latest run to the existing baseline. If there are any expected layout changes to a website that you're testing, you'll need to reset the baseline to prevent unnecessary failures.
self.check_window()
will fail with \"Page Domain Mismatch Failure\" if the domain of the current URL doesn't match the domain of the baseline URL.
If you want to use self.check_window()
to compare a web page to a later version of itself in the same test, add the baseline=True
parameter to your first self.check_window()
call to use that as the baseline. (This only makes sense if you're calling self.check_window()
more than once with the same \"name\" parameter in the same test.)
Automated Visual Testing with self.check_window()
is not very effective for websites that have dynamic content because that changes the layout and structure of web pages. For those pages, you're much better off using regular SeleniumBase functional testing, unless you can remove the dynamic content before performing the comparison, (such as by using self.ad_block()
to remove dynamic ad content on a web page).
Example usage of self.check_window()
with different levels:
self.check_window(name=\"testing\", level=0)\n self.check_window(name=\"xkcd_home\", level=1)\n self.check_window(name=\"github_page\", level=2)\n self.check_window(name=\"wikipedia_page\", level=3)\n\n self.check_window(name=\"helloworld\", baseline=True)\n ### Do something that may change the web page\n self.check_window(name=\"helloworld\", level=3)\n
Here's an example where clicking a button makes a hidden element visible:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_applitools_layout_change_failure(self):\n self.open('https://applitools.com/helloworld?diff1')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"helloworld\", baseline=True)\n # Click a button that changes the text of an element\n self.click('a[href=\"?diff1\"]')\n # Click a button that makes a hidden element visible\n self.click(\"button\")\n self.check_window(name=\"helloworld\", level=3)\n
Here's the output of that: (Text changes do not impact visual comparisons)
AssertionError:\nFirst differing element 39:\n['div', [['class', ['section', 'hidden-section', 'image-section']]]]\n['div', [['class', ['section', 'image-section']]]]\n\n- ['div', [['class', ['section', 'hidden-section', 'image-section']]]],\n? ------------------\n+ ['div', [['class', ['section', 'image-section']]]],\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
Here's an example where a button is removed from a web page:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_python_home_layout_change_failure(self):\n self.open('https://python.org/')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"python_home\", baseline=True)\n # Remove the \"Donate\" button\n self.remove_element('a.donate-button')\n self.check_window(name=\"python_home\", level=3)\n
Here's the output of that:
AssertionError:\nFirst differing element 33:\n['a', [['class', ['donate-button']], ['href', '/psf/donations/']]]\n['div', [['class', ['options-bar']]]]\n\n- ['a', [['class', ['donate-button']], ['href', '/psf/donations/']]],\n- 'display: list-item; opacity: 0.995722;']]],\n? -------------------\n+ 'display: list-item;']]],\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
Here's the side_by_side.html
file for that, (from the ./latest_logs/
folder), which shows a visual comparison of the two screenshots as a result of the missing \"Donate\" button:
Here's another example, where a web site logo is resized:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass VisualLayoutTest(BaseCase):\n def test_xkcd_layout_change_failure(self):\n self.open('https://xkcd.com/554/')\n print('\\nCreating baseline in \"visual_baseline\" folder.')\n self.check_window(name=\"xkcd_554\", baseline=True)\n # Change height: (83 -> 130) , Change width: (185 -> 120)\n self.set_attribute('[alt=\"xkcd.com logo\"]', \"height\", \"130\")\n self.set_attribute('[alt=\"xkcd.com logo\"]', \"width\", \"120\")\n self.check_window(name=\"xkcd_554\", level=3)\n
Here's the output of that:
AssertionError:\nFirst differing element 22:\n['img[30 chars]['height', '83'], ['src', '/s/0b7742.png'], ['width', '185']]]\n['img[30 chars]['height', '130'], ['src', '/s/0b7742.png'], ['width', '120']]]\n\n- ['height', '83'],\n? ^\n+ ['height', '130'],\n? ^ +\n- ['width', '185']]],\n? ^^\n+ ['width', '120']]],\n? ^^\n*\n*** Exception: <Level 3> Visual Diff Failure:\n* HTML tag attribute values don't match the baseline!\n
To run the example (from examples/visual_testing/) with a pytest HTML Report, use:
pytest test_layout_fail.py --html=report.html\n
Here's what the pytest HTML Report looks like:
In conclusion, open source automated visual testing tools are being built directly into test frameworks, and this trend is growing. Just like many years ago when free Wi-Fi at coffee shops replaced Internet cafes that charged money for Internet access, open source tools for visual testing will replace their paid counterparts in time. You'll remember this next time you're sipping your Starbucks\u00ae Pumpkin Spice Latte with your free Internet access, instead of paying for Internet at cybercafes.
"}, {"location": "help_docs/ReadMe/", "title": "\ud83d\udcd1 Table of Contents", "text": ""}, {"location": "help_docs/ReadMe/#help-docs", "title": "Help Docs", "text": "\ud83d\ude80 Start | \ud83d\udcca Dashboard \ud83c\udff0 Features | \ud83c\udf9b\ufe0f Options \ud83d\udcda Examples | \ud83d\udcf1 Emulator \ud83c\udf20 Console Scripts | \ud83c\udf10 Grid \ud83d\udcd8 Methods / APIs | \ud83d\ude8e Tours \ud83d\udd21 Syntax Formats | \ud83e\udd16 CI/CD \u267b\ufe0f Boilerplates | \ud83d\uddfe Locale Codes \ud83d\udd79\ufe0f JS Manager | \ud83d\uddbc\ufe0f Visual Testing \ud83c\udf0f Translator | \ud83d\udec2 Dialog Boxes \ud83d\udd34 Recorder | \ud83d\udcbb Device Farm \ud83c\udf9e\ufe0f Slides | \ud83d\udcf6 Chart Maker \ud83c\udf96\ufe0f GUI | \ud83d\udc64 UC Mode
Table of Contents (seleniumbase.io) Features List Command Line Tutorial Usage Examples Demo Page for Tests How SeleniumBase Works Installing Python, Pip, & Git Python Virtual Env Tutorial SeleniumBase Installation Webdriver Installation Verify Webdriver Works Console Scripts Tutorial The Dashboard Recorder Mode pytest Commander Method Summary Syntax Formats Behave BDD Behave Commander Mobile Device Testing Case Plans Chart Maker Language Translations Language Locale Codes JS Package Manager Tour Maker Presentation Maker Handling iframes Undetected Mode (UC Mode) MySQL Installation Overview Using the Selenium Grid Browser Desired Capabilities Safari Driver Detailed Info Seeing Hidden Files on macOS Case Studies Demo Pages / Web Examples Coffee Cart (Test Page) Demo Page (Test Page) Simple App (Test Page) MFA Login (Test Page) TinyMCE (Test Page) Error Page (Test Page) Drag & Drop (Test Page) Device Farm (Virtual) HTML Playground Page SeleniumBase in iframe Page with broken links Shadow DOM/Root W3Schools iframes W3Schools file upload W3Schools doubleclick W3Schools drag & drop W3Schools checkboxes W3Schools radio buttons Presentations Presenter Demo Core Presentation Chart Maker Demo Python Virtual Envs GitHub Pages (seleniumbase.dev) Features List Command Line Tutorial Usage Examples How SeleniumBase Works Installing Python, Pip, & Git Python Virtual Env Tutorial SeleniumBase Installation Webdriver Installation Verify Webdriver Works Console Scripts Tutorial The Dashboard Recorder Mode pytest Commander Syntax Formats Behave BDD Behave Commander Mobile Device Testing Method Summary (API Ref) Case Plans Language Translations Language Locale Codes JS Package Manager Tour Examples Presentation Maker Chart Maker Handling iframes MySQL Installation Overview Using the Selenium Grid Browser Desired Capabilities Safari Driver Detailed Info Seeing Hidden Files on macOS Case Studies"}, {"location": "help_docs/behave_gui/", "title": "\ud83d\udc1d Behave-BDD GUI App", "text": ""}, {"location": "help_docs/behave_gui/#seleniumbase-behave-gui-commander", "title": "SeleniumBase Behave GUI / Commander \ud83d\udc1d\ud83c\udf96\ufe0f", "text": "
\ud83d\udc1d\ud83c\udf96\ufe0f The SeleniumBase Behave GUI lets you run behave
scripts from a Desktop GUI.
\ud83d\udc1d\ud83c\udf96\ufe0f To launch it, call sbase behave-gui
or sbase gui-behave
:
> sbase behave-gui\n* Starting the SeleniumBase Behave Commander GUI App...\n
\ud83d\udc1d\ud83c\udf96\ufe0f SeleniumBase Behave GUI loads the same tests that are found by:
behave -d\n
\ud83d\udc1d\ud83c\udf96\ufe0f You can customize which tests are loaded by passing additional args:
sbase behave-gui [OPTIONAL PATH or TEST FILE]\n
\ud83d\udc1d\ud83c\udf96\ufe0f Here are examples of customizing test collection:
sbase behave-gui # all tests\nsbase behave-gui -i=calculator # tests with \"calculator\" in the name\nsbase behave-gui features/ # tests located in the \"features/\" folder\nsbase behave-gui features/calculator.feature # tests in that feature\n
\ud83d\udc1d\ud83c\udf96\ufe0f Once launched, you can further customize which tests to run and what settings to use. There are various controls for changing settings, modes, and other \"behave\" command line options that are specific to SeleniumBase. You can also set additional options that don't have a visible toggle. When you're ready to run the selected tests with the specified options, click on the Run Selected Tests
button.
\ud83d\udc1d\u26aa With the Dashboard enabled, you'll get one of these:
To learn more about SeleniumBase, check out the Docs Site:All the code is on GitHub:
"}, {"location": "help_docs/case_plans/", "title": "\ud83d\uddc2\ufe0f Case Plans", "text": ""}, {"location": "help_docs/case_plans/#seleniumbase-case-plans", "title": "SeleniumBase Case Plans \ud83d\uddc2\ufe0fSummary of existing Case Plans", "text": "
\ud83d\uddc2\ufe0f SeleniumBase Case Plans is Test Case Management Software that uses Markdown tables for displaying test plans directly in GitHub (and other source code management systems that support Markdown format).
\ud83d\uddc2\ufe0f The case_summary.md
file is generated from individual Case Plans that exist in the case_plans/
folders of your repository. (See the example below to learn how the Case Summary file may look.)
Example of a case_summary.md
file:
basic_test.py::MyTestClass::test_basics
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | | 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | | 4 | Remove the ``Backpack`` from the cart. | The ``Backpack`` is no longer in the cart. | | 5 | Log out from the website. | Logout was successful. | \ud83d\udd35 list_assert_test.py::MyTestClass::test_assert_list_of_elements
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/demo_page. | | | 2 | Use ``self.assert_elements_present(\"head\", \"style\", \"script\")`` to verify that multiple elements are present in the HTML. | The assertion is successful. | | 3 | Use ``self.assert_elements(\"h1\", \"h2\", \"h3\")`` to verify that multiple elements are visible. | The assertion is successful. | | 4 | Use ``self.assert_elements([\"#myDropdown\", \"#myButton\", \"#svgRect\"])`` to verify that multiple elements are visible. | The assertion is successful. | \u2b55 locale_code_test.py::LocaleCodeTests::test_locale_code
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Perform Action 1 | Verify Action 1 | | 2 | Perform Action 2 | Verify Action 2 | \ud83d\udd35 my_first_test.py::MyTestClass::test_swag_labs
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | | 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | | 4 | Click on the ``CHECKOUT`` button. Enter user details and click ``CONTINUE``. | The ``Backpack`` is seen in the cart on the ``CHECKOUT: OVERVIEW`` page. | | 5 | Click on the ``FINISH`` button. | There is a ``Thank You`` message and a ``Pony Express`` delivery logo. | | 6 | Log out from the website. | Logout was successful. | \u2b55 proxy_test.py::ProxyTests::test_proxy
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Perform Action 1 | Verify Action 1 | | 2 | Perform Action 2 | Verify Action 2 | \ud83d\udd35 shadow_root_test.py::ShadowRootTest::test_shadow_root
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/other/shadow_dom. Click each tab and verify the text contained within the Shadow Root sections. | Tab 1 text: ``Content Panel 1`` Tab 2 text: ``Content Panel 2`` Tab 3 text: ``Content Panel 3`` | \ud83d\udea7 test_agent.py::UserAgentTests::test_user_agent
test_calculator.py::CalculatorTests::test_6_times_7_plus_12_equals_54
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/apps/calculator. Perform the following calculation: ``6 \u00d7 7 + 12`` | The output is ``54`` after pressing ``=`` | \ud83d\udd35 test_demo_site.py::DemoSiteTests::test_demo_site
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/demo_page | | | 2 | Assert the title of the current web page. Assert that a given element is visible on the page. Assert that a text substring appears in an element's text. | The assertions were successful. | | 3 | Type text into various text fields and then verify. | The assertions were successful. | | 4 | Verify that a hover dropdown link changes page text. | The assertion was successful. | | 5 | Verify that a button click changes text on the page. | The assertion was successful. | | 6 | Verify that an SVG element is located on the page. | The assertion was successful. | | 7 | Verify that a slider control updates a progress bar. | The assertion was successful. | | 8 | Verify that a \"select\" option updates a meter bar. | The assertion was successful. | | 9 | Assert an element located inside an iFrame. | The assertion was successful. | | 10 | Assert text located inside an iFrame. | The assertion was successful. | | 11 | Verify that clicking a radio button selects it. | The assertion was successful. | | 12 | Verify that clicking an empty checkbox makes it selected. | The assertion was successful. | | 13 | Verify clicking on multiple elements with one call. | The assertions were successful. | | 14 | Verify that clicking an iFrame checkbox selects it. | The assertions were successful. | | 15 | Verify that Drag and Drop works. | The assertion was successful. | | 16 | Assert link text. | The assertion was successful. | | 17 | Verify clicking on link text. | The action was successful. | | 18 | Assert exact text in an element. | The assertion was successful. | | 19 | Highlight a page element. | The action was successful. | | 20 | Verify that Demo Mode works. | The assertion was successful. | \ud83d\udd35 test_login.py::SwagLabsLoginTests::test_swag_labs_login
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | | 2 | Log out from the website. | Logout was successful. | \ud83d\udd35 test_mfa_login.py::TestMFALogin::test_mfa_login
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Open https://seleniumbase.io/realworld/login Enter credentials and Sign In. | Sign In was successful. | | 2 | Click the ``This Page`` button. Save a screenshot to the logs. | | | 3 | Click to Sign Out | Sign Out was successful. | \ud83d\uddc2\ufe0f Before you can generate a case_summary.md
file that includes your existing Case Plans, first you'll need to select which existing tests you want to create boilerplate Case Plans from. For that, you can use the SeleniumBase Case Plans GUI:
sbase caseplans\n
\ud83d\uddc2\ufe0f Once you are running the Case Plans GUI, select the existing tests that need Case Plans, and then click: Generate boilerplate Case Plans for selected tests missing them
. For each selected test that didn't already have a Case Plan file, one will be generated. Each new Case Plan file starts with default boilerplate code with a Markdown table. Eg:
``proxy_test.py::ProxyTests::test_proxy``\n---\n| # | Step Description | Expected Result |\n| - | ---------------- | --------------- |\n| 1 | Perform Action 1 | Verify Action 1 |\n| 2 | Perform Action 2 | Verify Action 2 |\n
\ud83d\uddc2\ufe0f When rendered as a Markdown table, the result looks like this:
"}, {"location": "help_docs/case_plans/#proxy_testpyproxyteststest_proxy", "title": "proxy_test.py::ProxyTests::test_proxy
", "text": "# Step Description Expected Result 1 Perform Action 1 Verify Action 1 2 Perform Action 2 Verify Action 2 \ud83d\uddc2\ufe0f Markdown tables are flexible, but must be constructed correctly to be displayed. For a Markdown table to render, it's important that you place pipes (|
), dashes (-
), and spaces in the correct locations. If you want a line break in a step, use <br />
. If you want an empty step, put a space between pipes, eg: | |
.
\ud83d\uddc2\ufe0f Here's an example of a Case Plan for my_first_test.py:
"}, {"location": "help_docs/case_plans/#my_first_testpymytestclasstest_swag_labs", "title": "my_first_test.py::MyTestClass::test_swag_labs
", "text": "# Step Description Expected Result 1 Log in to https://www.saucedemo.com with standard_user
. Login was successful. 2 Click on the Backpack
ADD TO CART
button. The button text changed to REMOVE
. 3 Click on the cart icon. The Backpack
is seen in the cart. 4 Click on the CHECKOUT
button. Enter user details and click CONTINUE
. The Backpack
is seen in the cart on the CHECKOUT: OVERVIEW
page. 5 Click on the FINISH
button. There is a Thank you
message. 6 Log out from the website. Logout was successful. \ud83d\uddc2\ufe0f After you've created some Case Plans, you can use the Generate Summary of existing Case Plans
button in the Case Plans GUI to generate the Case Plans Summary file.
\ud83d\uddc2\ufe0f The generated Case Plans summary file, case_summary.md
, gets created in the same location where the Case Plans GUI was launched. This is NOT the same location where individual Case Plan boilerplates are generated, which is in the case_plans/
folders. The case_plans/
folders are generated where individual tests live, which means that if you have your tests in multiple folders, then you could also have multiple case_plans/
folders. A case_summary.md
file may look like this when rendered:
\ud83d\uddc2\ufe0f When calling sbase caseplans
, you can provide additional arguments to limit the tests that appear in the list. The same discovery rules apply as when using pytest
. Eg:
sbase caseplans\nsbase caseplans -k agent\nsbase caseplans -m marker2\nsbase caseplans test_suite.py\nsbase caseplans offline_examples/\n
To learn more about SeleniumBase, check out the Docs Site: All the code is on GitHub:
"}, {"location": "help_docs/commander/", "title": "\ud83c\udf96\ufe0f GUI / Commander", "text": ""}, {"location": "help_docs/commander/#seleniumbase-commander", "title": "SeleniumBase Commander \ud83c\udf96\ufe0f", "text": "
\ud83c\udf96\ufe0f SeleniumBase Commander lets you run pytest
scripts from a Desktop GUI.
\ud83c\udf96\ufe0f To launch it, call sbase commander
or sbase gui
:
sbase gui\n* Starting the SeleniumBase Commander Desktop App...\n
\ud83c\udf96\ufe0f SeleniumBase Commander loads the same tests that are found by:
pytest --co -q\n
\ud83c\udf96\ufe0f You can customize which tests are loaded by passing additional args:
sbase commander [OPTIONAL PATH or TEST FILE]\nsbase gui [OPTIONAL PATH or TEST FILE]\n
\ud83c\udf96\ufe0f Here are examples of customizing test collection:
sbase gui\nsbase gui -k agent\nsbase gui -m marker2\nsbase gui test_suite.py\nsbase gui offline_examples/\n
\ud83c\udf96\ufe0f Once launched, you can further customize which tests to run and what settings to use. There are various controls for changing settings, modes, and other pytest command line options that are specific to SeleniumBase. You can also set additional options that don't have a visible toggle. When you're ready to run the selected tests with the specified options, click on the Run Selected Tests
button.
All the code is on GitHub:
"}, {"location": "help_docs/customizing_test_runs/", "title": "\ud83c\udf9b\ufe0f Command Line Options", "text": ""}, {"location": "help_docs/customizing_test_runs/#pytest-options-for-seleniumbase", "title": "pytest options for SeleniumBase", "text": "
\ud83c\udf9b\ufe0f SeleniumBase's pytest plugin lets you customize test runs from the CLI (Command-Line Interface), which adds options for setting/enabling the browser type, Dashboard Mode, Demo Mode, Headless Mode, Mobile Mode, Multi-threading Mode, Recorder Mode, reuse-session mode, proxy config, user agent config, browser extensions, html-report mode, and more.
\ud83c\udf9b\ufe0f Here are some examples of configuring tests, which can be run from the examples/ folder:
# Run a test in Chrome (default browser)\npytest my_first_test.py\n\n# Run a test in Firefox\npytest test_swag_labs.py --firefox\n\n# Run a test in Demo Mode (highlight assertions)\npytest test_demo_site.py --demo\n\n# Run a test in Headless Mode (invisible browser)\npytest test_demo_site.py --headless\n\n# Run tests multi-threaded using [n] threads\npytest test_suite.py -n4\n\n# Reuse the browser session for all tests (\"--reuse-session\")\npytest test_suite.py --rs\n\n# Reuse the browser session, but erase cookies between tests\npytest test_suite.py --rs --crumbs\n\n# Create a real-time dashboard for test results\npytest test_suite.py --dashboard\n\n# Create a pytest html report after tests are done\npytest test_suite.py --html=report.html\n\n# Activate Debug Mode on failures (\"c\" to continue)\npytest test_fail.py --pdb -s\n\n# Rerun failing tests more times\npytest test_suite.py --reruns=1\n\n# Activate Debug Mode as the test begins (\"n\": next. \"c\": continue)\npytest test_null.py --trace -s\n\n# Activate Recorder/Debug Mode as the test begins (\"c\" to continue)\npytest test_null.py --recorder --trace -s\n\n# Pass extra data into tests (retrieve by calling self.data)\npytest my_first_test.py --data=\"ABC,DEF\"\n\n# Run tests on a local Selenium Grid\npytest test_suite.py --server=\"127.0.0.1\"\n\n# Run tests on a remote Selenium Grid\npytest test_suite.py --server=IP_ADDRESS --port=4444\n\n# Run tests on a remote Selenium Grid with authentication\npytest test_suite.py --server=USERNAME:KEY@IP_ADDRESS --port=80\n\n# Run tests through a proxy server\npytest proxy_test.py --proxy=IP_ADDRESS:PORT\n\n# Run tests through a proxy server with authentication\npytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n\n# Run tests while setting the web browser's User Agent\npytest user_agent_test.py --agent=\"USER-AGENT-STRING\"\n\n# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"360,640,2\"\n\n# Run a test with an option to evade bot-detection services\npytest verify_undetected.py --uc\n\n# Run tests while changing SeleniumBase default settings\npytest my_first_test.py --settings-file=custom_settings.py\n
\ud83c\udf9b\ufe0f You can interchange pytest
with nosetests
for most tests, but using pytest
is recommended. (chrome
is the default browser if not specified.)
\ud83c\udf9b\ufe0f If you're using pytest
for running tests outside of the SeleniumBase repo, you'll want a copy of pytest.ini at the base of the new folder structure. If using nosetests
, the same applies for setup.cfg.
\ud83c\udf9b\ufe0f Here are some useful command-line options that come with pytest
:
-v # Verbose mode. Prints the full name of each test and shows more details.\n-q # Quiet mode. Print fewer details in the console output when running tests.\n-x # Stop running the tests after the first failure is reached.\n--html=report.html # Creates a detailed pytest-html report after tests finish.\n--co | --collect-only # Show what tests would get run. (Without running them)\n--co -q # (Both options together!) - Do a dry run with full test names shown.\n-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)\n-s # See print statements. (Should be on by default with pytest.ini present.)\n--junit-xml=report.xml # Creates a junit-xml report after tests finish.\n--pdb # If a test fails, enter Post Mortem Debug Mode. (Don't use with CI!)\n--trace # Enter Debug Mode at the beginning of each test. (Don't use with CI!)\n-m=MARKER # Run tests with the specified pytest marker.\n
\ud83c\udf9b\ufe0f SeleniumBase provides additional pytest
command-line options for tests:
--browser=BROWSER # (The web browser to use. Default: \"chrome\".)\n--chrome # (Shortcut for \"--browser=chrome\". On by default.)\n--edge # (Shortcut for \"--browser=edge\".)\n--firefox # (Shortcut for \"--browser=firefox\".)\n--safari # (Shortcut for \"--browser=safari\".)\n--settings-file=FILE # (Override default SeleniumBase settings.)\n--env=ENV # (Set the test env. Access with \"self.env\" in tests.)\n--account=STR # (Set account. Access with \"self.account\" in tests.)\n--data=STRING # (Extra test data. Access with \"self.data\" in tests.)\n--var1=STRING # (Extra test data. Access with \"self.var1\" in tests.)\n--var2=STRING # (Extra test data. Access with \"self.var2\" in tests.)\n--var3=STRING # (Extra test data. Access with \"self.var3\" in tests.)\n--variables=DICT # (Extra test data. Access with \"self.variables\".)\n--user-data-dir=DIR # (Set the Chrome user data directory to use.)\n--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)\n--server=SERVER # (The Selenium Grid server/IP used for tests.)\n--port=PORT # (The Selenium Grid port used by the test server.)\n--cap-file=FILE # (The web browser's desired capabilities to use.)\n--cap-string=STRING # (The web browser's desired capabilities to use.)\n--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)\n--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)\n--proxy-bypass-list=STRING # (\";\"-separated hosts to bypass, Eg \"*.foo.com\")\n--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)\n--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)\n--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)\n--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)\n--agent=STRING # (Modify the web browser's User-Agent string.)\n--mobile # (Use the mobile device emulator while running tests.)\n--metrics=STRING # (Set mobile metrics: \"CSSWidth,CSSHeight,PixelRatio\".)\n--chromium-arg=\"ARG=N,ARG2\" # (Set Chromium args, \",\"-separated, no spaces.)\n--firefox-arg=\"ARG=N,ARG2\" # (Set Firefox args, comma-separated, no spaces.)\n--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)\n--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)\n--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)\n--disable-features=\"F1,F2\" # (Disable features, comma-separated, no spaces.)\n--binary-location=PATH # (Set path of the Chromium browser binary to use.)\n--driver-version=VER # (Set the chromedriver or uc_driver version to use.)\n--sjw # (Skip JS Waits for readyState to be \"complete\" or Angular to load.)\n--pls=PLS # (Set pageLoadStrategy on Chrome: \"normal\", \"eager\", or \"none\".)\n--headless # (Run tests in headless mode. The default arg on Linux OS.)\n--headless2 # (Use the new headless mode, which supports extensions.)\n--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)\n--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)\n--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)\n--interval=SECONDS # (The autoplay interval for presentations & tour steps)\n--start-page=URL # (The starting URL for the web browser when tests begin.)\n--archive-logs # (Archive existing log files instead of deleting them.)\n--archive-downloads # (Archive old downloads instead of deleting them.)\n--time-limit=SECONDS # (Safely fail any test that exceeds the time limit.)\n--slow # (Slow down the automation. Faster than using Demo Mode.)\n--demo # (Slow down and visually see test actions as they occur.)\n--demo-sleep=SECONDS # (Set the wait time after Slow & Demo Mode actions.)\n--highlights=NUM # (Number of highlight animations for Demo Mode actions.)\n--message-duration=SECONDS # (The time length for Messenger alerts.)\n--check-js # (Check for JavaScript errors after page loads.)\n--ad-block # (Block some types of display ads from loading.)\n--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)\n--block-images # (Block images from loading during tests.)\n--do-not-track # (Indicate to websites that you don't want to be tracked.)\n--verify-delay=SECONDS # (The delay before MasterQA verification checks.)\n--ee | --esc-end # (Lets the user end the current test via the ESC key.)\n--recorder # (Enables the Recorder for turning browser actions into code.)\n--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)\n--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)\n--rec-print # (If the Recorder is enabled, prints output after tests end.)\n--disable-js # (Disable JavaScript on websites. Pages might break!)\n--disable-csp # (Disable the Content Security Policy of websites.)\n--disable-ws # (Disable Web Security on Chromium-based browsers.)\n--enable-ws # (Enable Web Security on Chromium-based browsers.)\n--enable-sync # (Enable \"Chrome Sync\" on websites.)\n--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)\n--uc-cdp-events # (Capture CDP events when running in \"--undetected\" mode.)\n--log-cdp # (\"goog:loggingPrefs\", {\"performance\": \"ALL\", \"browser\": \"ALL\"})\n--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)\n--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)\n--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)\n--dash-title=STRING # (Set the title shown for the generated dashboard.)\n--enable-3d-apis # (Enables WebGL and 3D APIs.)\n--swiftshader # (Chrome \"--use-gl=angle\" / \"--use-angle=swiftshader-webgl\")\n--incognito # (Enable Chrome's Incognito mode.)\n--guest # (Enable Chrome's Guest mode.)\n--dark # (Enable Chrome's Dark mode.)\n--devtools # (Open Chrome's DevTools when the browser opens.)\n--rs | --reuse-session # (Reuse browser session for all tests.)\n--rcs | --reuse-class-session # (Reuse session for tests in class.)\n--crumbs # (Delete all cookies between tests reusing a session.)\n--disable-beforeunload # (Disable the \"beforeunload\" event on Chrome.)\n--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)\n--maximize # (Start tests with the browser window maximized.)\n--screenshot # (Save a screenshot at the end of each test.)\n--no-screenshot # (No screenshots saved unless tests directly ask it.)\n--visual-baseline # (Set the visual baseline for Visual/Layout tests.)\n--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)\n--external-pdf # (Set Chromium \"plugins.always_open_pdf_externally\":True.)\n--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)\n--list-fail-page # (After each failing test, list the URL of the failure.)\n
(For more details, see the full list of command-line options here.)
\ud83c\udf9b\ufe0f You can also view a list of popular pytest
options for SeleniumBase by typing:
seleniumbase options\n
Or the short form:
sbase options\n
Example tests using Logging: To see logging abilities, you can run a test suite that includes tests that fail on purpose:
pytest test_suite.py\n
\ud83d\udd35 During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/
folder. If --archive-logs
is specified (or if ARCHIVE_EXISTING_LOGS is set to True in settings.py), test logs will also get archived to the archived_logs/
folder. Otherwise, the log files will be cleaned out when the next test run begins (by default).
\ud83d\udd35 If any test is moving too fast for your eyes to see what's going on, you can run it in Demo Mode by adding --demo
on the command line, which pauses the browser briefly between actions, highlights page elements being acted on, and lets you know what test assertions are happening in real time:
pytest my_first_test.py --demo\n
\ud83d\udd35 You can override the default wait time by either updating settings.py or by using --demo-sleep=NUM
when using Demo Mode. (NOTE: If you use --demo-sleep=NUM
without using --demo
, nothing will happen.)
pytest my_first_test.py --demo --demo-sleep=1.2\n
Passing additional data to tests: If you want to pass additional data from the command line to your tests, you can use --data=STRING
. Now inside your tests, you can use self.data
to access that.
To run pytest
with multiple processes, add -n=NUM
, -n NUM
, or -nNUM
on the command line, where NUM
is the number of CPUs you want to use.
pytest -n=8\npytest -n 8\npytest -n8\n
How to retry failing tests automatically: You can use pytest --reruns=NUM
to retry failing tests that many times. Add --reruns-delay=SECONDS
to wait that many seconds between retries. Example:
pytest --reruns=1 --reruns-delay=1\n
Debugging tests: \ud83d\udd35 You can use the following calls in your scripts to help you debug issues:
import time; time.sleep(5) # Makes the test wait and do nothing for 5 seconds.\nimport pdb; pdb.set_trace() # Debug Mode. n: next, c: continue, s: step, u: up, d: down.\nimport pytest; pytest.set_trace() # Debug Mode. n: next, c: continue, s: step, u: up, d: down.\n
\ud83d\udd35 To pause an active test that throws an exception or error, (and keep the browser window open while Debug Mode begins in the console), add --pdb
as a pytest
option:
pytest test_fail.py --pdb\n
\ud83d\udd35 To start tests in Debug Mode, add --trace
as a pytest
option:
pytest test_coffee_cart.py --trace\n
(pdb
commands: n
, c
, s
, u
, d
=> next
, continue
, step
, up
, down
).
\ud83c\udf9b\ufe0f There are times when you'll want to combine various command-line options for added effect. For instance, the multi-process option, -n8
, can be customized by adding: --dist=loadscope
or --dist=loadfile
to it. There's more info on that here: pytest-xdist:
-n8 --dist=loadscope
: Tests are grouped by module for test functions and by class for test methods. Groups are distributed to available workers as whole units. This guarantees that all tests in a group run in the same process. This can be useful if you have expensive module-level or class-level fixtures. Grouping by class takes priority over grouping by module.
-n8 --dist=loadfile
: Tests are grouped by their containing file. Groups are distributed to available workers as whole units. This guarantees that all tests in a file run in the same worker.
-n8 --dist=loadgroup
(click to expand) xdist_group
mark. Groups are distributed to available workers as whole units. This guarantees that all tests with the same xdist_group
name run in the same worker.@pytest.mark.xdist_group(name=\"group1\")\ndef test_1():\n pass\n\nclass Test:\n @pytest.mark.xdist_group(\"group1\")\n def test_2():\n pass\n
This makes test_1
and Test::test_2
run in the same worker. Tests without the xdist_group
mark are distributed normally.
\ud83c\udf9b\ufe0f You might also want to combine multiple options at once. For example:
pytest --headless -n8 --dashboard --html=report.html -v --rs --crumbs\n
The above not only runs tests in parallel processes, but it also tells tests in the same process to share the same browser session, runs the tests in headless mode, displays the full name of each test on a separate line, creates a realtime dashboard of the test results, and creates a full report after all tests complete.
The SeleniumBase Dashboard:\ud83d\udd35 The --dashboard
option for pytest generates a SeleniumBase Dashboard located at dashboard.html
, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headless\n
\ud83d\udd35 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python 3's http.server
:
python -m http.server 1948\n
\ud83d\udd35 Now you can navigate to http://localhost:1948/dashboard.html
in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
\ud83d\udd35 Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py --dashboard --rs --headless\n
Pytest Reports: \ud83d\udd35 Using --html=report.html
gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.html\n
\ud83d\udd35 When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html
), then the Dashboard will become an advanced html report when all the tests complete.
\ud83d\udd35 Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.html\n
If viewing pytest html reports in Jenkins, you may need to configure Jenkins settings for the html to render correctly. This is due to Jenkins CSP changes.
You can also use --junit-xml=report.xml
to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xml\n
Nosetest Reports: The --report
option gives you a fancy report after your test suite completes.
nosetests test_suite.py --report\n
(NOTE: You can add --show_report
to immediately display Nosetest reports after the test suite completes. Only use --show_report
when running tests locally because it pauses the test run.)
You can specify a Language Locale Code to customize web pages on supported websites. With SeleniumBase, you can change the web browser's Locale on the command line by doing this:
pytest --locale=CODE # Example: --locale=ru\n
Visit \ud83d\uddfe Locales for a full list of codes.
Changing the default driver version:\ud83d\udd35 By default, SeleniumBase will make sure that the major driver version matches the major browser version for Chromium tests. (Eg. If Chrome 117.X
is installed and you have chromedriver 117.X
, then nothing happens, but if you had chromedriver 116.X
instead, then SeleniumBase would download chromedriver 117.X
to match the browser version.)
\ud83c\udf9b\ufe0f To change this default behavior, you can use:
pytest --driver-version=VER\n
The VER
in --driver-version=VER
can be: * A major driver version. Eg. 117
. (milestone) * An exact driver version. Eg. 117.0.5938.92
. * \"browser\"
(exact match on browser version) * \"keep\"
(keep using the driver you already have) * \"latest\"
/ \"stable\"
(latest stable version) * \"previous\"
/ \"latest-1\"
(latest minus one) * \"beta\"
(latest beta version) * \"dev\"
(latest dev version) * \"canary\"
(latest canary version) * \"mlatest\"
(latest version for the milestone)
Note that different options could lead to the same result. (Eg. If you have the latest version of a browser for a milestone, then \"browser\"
and \"mlatest\"
should give you the same driver if the latest driver version for that milestone matches the browser version.)
\ud83c\udf9b\ufe0f An easy way to override seleniumbase/config/settings.py is by using a custom settings file. Here's the command-line option to add to tests: (See examples/custom_settings.py)
pytest --settings-file=custom_settings.py\n
(Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
Running tests on a remote Selenium Grid:\ud83c\udf10 SeleniumBase lets you run tests on remote Selenium Grids such as BrowserStack's Selenium Grid, Sauce Labs's Selenium Grid, other Grids, and even your own Grid:
\ud83c\udf10 For setting browser desired capabilities while running Selenium remotely, see the ReadMe located here: https://github.com/seleniumbase/SeleniumBase/tree/master/examples/capabilities
Here's how to connect to a BrowserStack Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@hub.browserstack.com --port=80\n
Here's how to connect to a Sauce Labs Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https\n
Here's how to connect to a CrossBrowserTesting Selenium Grid server for running tests:
pytest test_demo_site.py --server=USERNAME:KEY@hub.crossbrowsertesting.com --port=80\n
\ud83c\udf10 Or you can create your own Selenium Grid for test distribution. (See this ReadMe for details)
\ud83c\udf10 To use a server on the https
protocol, add --protocol=https
: (Now automatic if the port is 443.)
pytest test_demo_site.py --protocol=https --server=IP_ADDRESS --port=PORT\n
Using a Proxy Server: \ud83c\udf10 If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add --proxy=IP_ADDRESS:PORT
as an argument on the command line.
pytest proxy_test.py --proxy=IP_ADDRESS:PORT\n
\ud83c\udf10 If the proxy server that you wish to use requires authentication, you can do the following (Chromium only):
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT\n
\ud83c\udf10 SeleniumBase also supports SOCKS4 and SOCKS5 proxies:
pytest proxy_test.py --proxy=\"socks4://IP_ADDRESS:PORT\"\n\npytest proxy_test.py --proxy=\"socks5://IP_ADDRESS:PORT\"\n
To make things easier, you can add your frequently-used proxies to PROXY_LIST in proxy_list.py, and then use --proxy=KEY_FROM_PROXY_LIST
to use the IP_ADDRESS:PORT of that key.
pytest proxy_test.py --proxy=proxy1\n
Changing the User-Agent: \ud83d\udd24 If you wish to change the User-Agent for your browser tests (Chrome and Firefox only), you can add --agent=\"USER-AGENT-STRING\"
as an argument on the command line.
pytest user_agent_test.py --agent=\"Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU\"\n
Mobile Device Testing: \ud83d\udcf1 Use --mobile
to quickly run your tests using Chrome's mobile device emulator with default values for device metrics (CSS Width, CSS Height, Pixel-Ratio) and a default value set for the user agent. To configure the mobile device metrics, use --metrics=\"CSS_Width,CSS_Height,Pixel_Ratio\"
to set those values. You'll also be able to set the user agent with --agent=\"USER-AGENT-STRING\"
(a default user agent will be used if not specified). To find real values for device metrics, see this GitHub Gist. For a list of available user agent strings, check out this page.
# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"411,731,3\"\n\n# Run mobile tests specifying the user agent\npytest test_swag_labs.py --mobile --agent=\"Mozilla/5.0 (Linux; Android 9; Pixel 3 XL)\"\n
"}, {"location": "help_docs/demo_mode/", "title": "\ud83c\udfa6 Demo Mode", "text": ""}, {"location": "help_docs/demo_mode/#demo-mode", "title": "Demo Mode \ud83c\udfa6", "text": "\ud83d\udd35 Demo Mode helps you see what a test is doing.
\ud83c\udfc7\ud83d\udca8 \ud83d\udc40 If a test runs too fast for your eyes, use Demo Mode to slow it down, highlight actions, and display assertions. Example usage:
cd examples/\npytest test_coffee_cart.py --demo\n
(--demo
mode slows down tests and highlights actions)
Another example:
pytest my_first_test.py --demo\n
Here's how to run test_swag_labs.py from examples/ in Demo Mode:
pytest test_swag_labs.py --demo\n
Here's an example that only uses the highlight()
method for highlighting browser actions:
(test_error_page.py from examples/)
pytest test_error_page.py\n
Here's an example of a mobile test in Demo Mode:
"}, {"location": "help_docs/desired_capabilities/", "title": "\ud83d\udcc3 Desired Capabilities", "text": ""}, {"location": "help_docs/desired_capabilities/#using-desired-capabilities", "title": "Using Desired Capabilities", "text": "You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as BrowserStack or Sauce Labs).
Sample run commands may look like this when run from the SeleniumBase/examples/ folder: (The browser is now specified in the capabilities file.)
pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@hub.browserstack.com --port=80 --cap_file=capabilities/sample_cap_file_BS.py\n
pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https --cap_file=capabilities/sample_cap_file_SL.py\n
(Parameters: --browser=remote
, --server=SERVER
, --port=PORT
, and --cap_file=CAP_FILE.py
)
Here's an example desired capabilities file for BrowserStack using the newer SDK format in a .yml
/ .yaml
file:
platforms:\n - browserName: safari\n osVersion: 17\n deviceName: iPhone 15 Pro Max\nbuildIdentifier: ${BUILD_NUMBER}\nparallelsPerPlatform: 1\nprojectName: My Project\nbrowserstackLocal: true\ndebug: true\nnetworkLogs: true\n
Here's an example desired capabilities file for BrowserStack using the legacy JSONWP format in a .py
file:
desired_cap = {\n \"browser\": \"Chrome\",\n \"os\": \"Windows\",\n \"os_version\": \"11\",\n \"browser_version\": \"latest\",\n \"browserstack.console\": \"info\",\n \"browserstack.debug\": \"true\",\n \"browserstack.networkLogs\": \"true\",\n \"browserstack.local\": \"true\",\n}\n
Here's an example desired capabilities file for Sauce Labs:
capabilities = {\n \"browserName\": \"chrome\",\n \"browserVersion\": \"latest\",\n \"platformName\": \"macOS 10.14\",\n \"sauce:options\": {},\n}\n
(Note that the browser is now being specified in the capabilities file, rather than with --BROWSER
when using a remote Selenium Grid. If using a local Selenium Grid, specify the browser, eg: --firefox
.)
SeleniumBase has a desired capabilities parser that can capture all lines from the specified file in the following formats:
'KEY': 'VALUE'\n'KEY': True\n'KEY': False\ncaps['KEY'] = \"VALUE\"\ncaps['KEY'] = True\ncaps['KEY'] = False\n
(Each pair must be on a separate line. You can interchange single and double quotes.)
You can also swap --browser=remote
with an actual browser, eg --browser=chrome
, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using --cap_file=FILE.py
. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser.
You'll need default SeleniumBase capabilities for: * Using a proxy server (not the same as a Selenium Grid server) * Downloading files to a desired folder * Disabling some warnings on Chrome * Overriding a website's Content Security Policy on Chrome * Other possible reasons
You can also set browser desired capabilities from a command-line string. Eg:
pytest test_swag_labs.py --cap-string='{\"browserName\":\"chrome\",\"name\":\"test1\"}' --server=\"127.0.0.1\" --browser=remote\n
(Enclose cap-string in single quotes. Enclose parameter keys in double quotes.)
If you pass \"*\"
into the \"name\"
field of --cap-string
, the name will become the test identifier. Eg:
pytest my_first_test.py --cap-string='{\"browserName\":\"chrome\",\"name\":\"*\"}' --server=\"127.0.0.1\" --browser=chrome\n
Example name: \"my_first_test.MyTestClass.test_basics\"
If using a local Selenium Grid with SeleniumBase, start up the Grid Hub and nodes first:
sbase grid-hub start\nsbase grid-node start\n
(The Selenium Server JAR file will be automatically downloaded for first-time Grid users. You'll also need Java installed to start up the Grid.)
"}, {"location": "help_docs/features_list/", "title": "\ud83c\udff0 List of Features", "text": ""}, {"location": "help_docs/features_list/#seleniumbase-features", "title": "SeleniumBase Features: \ud83c\udff0", "text": "--headless
)-n NUM_THREADS
)--reuse-session
/--rs
)--mobile
)--proxy=IP_ADDRESS:PORT
)--proxy-pac-url=URL.pac
)--proxy=USER:PASS@HOST:PORT
)--proxy-pac-url=USER:PASS@URL.pac
)--agent=USER_AGENT_STRING
)--user-data-dir=DIR
)--undetected
/--uc
)--wire
)--extension-zip=ZIP
)--extension-dir=DIR
)seleniumbase
or sbase
to use.)self.driver
)self.execute_script()
)::shadow
to CSS fragments.)(Watch the original tutorial on YouTube)
"}, {"location": "help_docs/handling_iframes/", "title": "\ud83d\uddbc\ufe0f How to handle iframes", "text": ""}, {"location": "help_docs/handling_iframes/#how-to-handle-iframes", "title": "How to handle iframes", "text": "\ud83d\uddbc\ufe0f iframes follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
self.switch_to_frame(\"iframe\")\n# ... Now perform actions inside the iframe\nself.switch_to_parent_frame() # Exit the current iframe\n
To exit from multiple iframes, use self.switch_to_default_content()
. (If inside a single iframe, this has the same effect as self.switch_to_parent_frame()
.)
self.switch_to_frame('iframe[name=\"frame1\"]')\nself.switch_to_frame('iframe[name=\"frame2\"]')\n# ... Now perform actions inside the inner iframe\nself.switch_to_default_content() # Back to the main page\n
\ud83d\uddbc\ufe0f You can also use a context manager to act inside iframes:
with self.frame_switch(\"iframe\"):\n # ... Now perform actions while inside the code block\n# You have left the iframe\n
This also works with nested iframes:
with self.frame_switch('iframe[name=\"frame1\"]'):\n with self.frame_switch('iframe[name=\"frame2\"]'):\n # ... Now perform actions while inside the code block\n # You are now back inside the first iframe\n# You have left all the iframes\n
\ud83d\uddbc\ufe0f In special cases, you may want to set the page to the content of an iframe:
self.set_content_to_frame(\"iframe\")\n
To back out of one call of that, use:
self.set_content_to_parent()\n
To back out of all nested calls of that, use:
self.set_content_to_default()\n
\ud83d\uddbc\ufe0f See SeleniumBase/examples/iframe_tests.py for tests that use all available iframe commands.
"}, {"location": "help_docs/happy_customers/", "title": "\ud83d\udccb Case Studies", "text": ""}, {"location": "help_docs/happy_customers/#businesses-who-have-used-seleniumbase", "title": "Businesses who have used SeleniumBase", "text": "
HubSpot:
In addition to using SeleniumBase for testing the UI of their content management system, HubSpot used SeleniumBase to automate the migration of website pages from their old CMS to their new one, which saved them over one million USD and a significant amount of time.
Learn how HubSpot uses SeleniumBase for website testing by reading: Automated Testing with Selenium
For more reading about automation at HubSpot, see: The Classic \"QA Team\" is Obsolete
"}, {"location": "help_docs/happy_customers/#how-is-this-list-generated", "title": "How is this list generated?", "text": "Most of these rows come from LinkedIn search results of profile descriptions, where employees mentioned that they have used SeleniumBase at their company. These details may also be found in other public networks and social media sites, such as GitHub (where organizations could have public repos that use SeleniumBase).
"}, {"location": "help_docs/hidden_files_info/", "title": "\ud83d\udc65 macOS Hidden Files", "text": ""}, {"location": "help_docs/hidden_files_info/#showing-hidden-files-on-macos", "title": "Showing hidden files on macOS", "text": "Depending on your macOS settings, some files may be hidden from view in your Finder window, such as .gitignore
.
Press the \u201cCommand\u201d + \u201cShift\u201d + \u201c.\u201d (period) keys at the same time.
(The hidden files will show up as translucent in the folder. If you want to obscure the files again, press the same \u201cCommand\u201d + \u201cShift\u201d + \u201c.\u201d (period) combination.)
defaults write com.apple.finder AppleShowAllFiles -bool true\n
More info on that can be found here:
\ud83d\udc41\ufe0f\ud83d\udd0e The primary SeleniumBase syntax format works by extending pytest as a direct plugin. SeleniumBase automatically spins up web browsers for tests (using Selenium WebDriver), and then gives those tests access to the SeleniumBase libraries through the BaseCase class. Tests are also given access to SeleniumBase command-line options and SeleniumBase methods, which provide additional functionality.
\ud83d\udc41\ufe0f\ud83d\udd0e pytest
uses a feature called test discovery to automatically find and run Python methods that start with test_
when those methods are located in Python files that start with test_
or end with _test.py
.
\ud83d\udc41\ufe0f\ud83d\udd0e The primary SeleniumBase syntax format starts by importing BaseCase
:
from seleniumbase import BaseCase\n
\ud83d\udc41\ufe0f\ud83d\udd0e This next line activates pytest
when a file is called directly with python
by accident:
BaseCase.main(__name__, __file__)\n
\ud83d\udc41\ufe0f\ud83d\udd0e Classes can inherit BaseCase
to gain SeleniumBase functionality:
class MyTestClass(BaseCase):\n
\ud83d\udc41\ufe0f\ud83d\udd0e Test methods inside BaseCase
classes become SeleniumBase tests: (These tests automatically launch a web browser before starting, and quit the web browser after ending. Default settings can be changed via command-line options.)
class MyTestClass(BaseCase):\n def test_abc(self):\n # ...\n
\ud83d\udc41\ufe0f\ud83d\udd0e SeleniumBase APIs can be called from tests via self
:
class MyTestClass(BaseCase):\n def test_abc(self):\n self.open(\"https://example.com\")\n
\ud83d\udc41\ufe0f\ud83d\udd0e Here's what a full test might look like:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass TestSimpleLogin(BaseCase):\n def test_simple_login(self):\n self.open(\"https://seleniumbase.io/simple/login\")\n self.type(\"#username\", \"demo_user\")\n self.type(\"#password\", \"secret_pass\")\n self.click('a:contains(\"Sign in\")')\n self.assert_exact_text(\"Welcome!\", \"h1\")\n self.assert_element(\"img#image1\")\n self.highlight(\"#image1\")\n self.click_link(\"Sign out\")\n self.assert_text(\"signed out\", \"#top_message\")\n
(See the example, test_simple_login.py, for reference.)
\ud83d\udc41\ufe0f\ud83d\udd0e Here are some examples of running tests with pytest
:
pytest test_mfa_login.py\npytest --headless -n8 --dashboard --html=report.html -v --rs --crumbs\npytest -m marker2\npytest -k agent\npytest offline_examples/\n
\ud83d\udc41\ufe0f\ud83d\udd0e Here's a SeleniumBase syntax format that uses the raw driver
. Unlike the format mentioned earlier, it can be run with python
instead of pytest
. The driver
includes original driver
methods and new ones added by SeleniumBase:
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.get(\"https://seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
(See the example, raw_login_driver.py, for reference.)
\ud83d\udc41\ufe0f\ud83d\udd0e Note that regular SeleniumBase formats (ones that use BaseCase
, the SB
context manager, or the sb
pytest
fixture) have more methods than the improved driver
format. The regular formats also have more features. Some features, (such as the SeleniumBase dashboard), require a pytest
format.
SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (up to a timeout limit). This means you no longer need random time.sleep()
statements in your scripts.
There are three layers of protection that provide reliability for tests using SeleniumBase:
(1): Selenium's default pageLoadStrategy
is normal
: This strategy causes Selenium to wait for the full page to load, with HTML content and sub-resources downloaded and parsed.
(2): SeleniumBase includes methods such as wait_for_ready_state_complete()
, which run inside other SeleniumBase methods to ensure that it's safe to proceed with the next command.
(3): SeleniumBase methods automatically wait for elements to be visible and interactable before interacting with those elements.
If you want to speed up your tests and you think the third level of protection is enough by itself, you can use command-line options to remove the first, the second, or both of those first two levels of protection:
--pls=none
--> Set pageLoadStrategy
to \"none\"
: This strategy causes Selenium to return immediately after the initial HTML content is fully received by the browser.
--sjw
--> Skip JS Waits, such as wait_for_ready_state_complete()
.
\ud83d\udd75\ufe0f HTML Inspector provides useful info about a web page.
\ud83d\udd75\ufe0f (Based on: github.com/philipwalton/html-inspector)
\ud83d\udd75\ufe0f Example: examples/test_inspect_html.py (Chromium-only)
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass HtmlInspectorTests(BaseCase):\n def test_html_inspector(self):\n self.open(\"https://xkcd.com/1144/\")\n self.inspect_html()\n
pytest test_inspect_html.py\n============== test session starts ==============\n\n* HTML Inspection Results: https://xkcd.com/1144/\n\u26a0\ufe0f 'property' is not a valid attribute of the <meta> element.\n\u26a0\ufe0f Do not use <div> or <span> elements without any attributes.\n\u26a0\ufe0f 'srcset' is not a valid attribute of the <img> element.\n\u26a0\ufe0f The 'border' attribute is no longer valid on the <img> element.\n\u26a0\ufe0f The <center> element is obsolete.\n\u26a0\ufe0f The id 'comicLinks' appears more than once in the document.\n* (See the Console output for details!)\n
"}, {"location": "help_docs/install/", "title": "\ud83c\udfc4 Install SeleniumBase", "text": ""}, {"location": "help_docs/install/#seleniumbase-installation", "title": "SeleniumBase Installation", "text": "If installing seleniumbase
directly from PyPI, (the Python Package Index), use: pip install seleniumbase\n
To upgrade an existing seleniumbase
install from PyPI: pip install -U seleniumbase\n
If installing seleniumbase
from a Git clone, use: git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install .\n
For a development mode install in editable mode, use: git clone https://github.com/seleniumbase/SeleniumBase.git\ncd SeleniumBase/\npip install -e .\n
To upgrade an existing seleniumbase
install from GitHub: git pull # To pull the latest version\npip install -e . # Or \"pip install .\"\n
If installing seleniumbase
from a GitHub branch, use: pip install git+https://github.com/seleniumbase/SeleniumBase.git@master#egg=seleniumbase\n
pip install
can be customized: --upgrade
OR -U
to upgrade SeleniumBase.)--force-reinstall
to upgrade indirect libraries.)pip3
if multiple versions of Python are present.)(If you're not using a virtual environment, you may need to add --user
to your pip
command if you're seeing errors during installation.)
Git
, Python
, and pip
", "text": ""}, {"location": "help_docs/install_python_pip_git/#git", "title": "Git", "text": "You can download Git from here.
(A Git GUI tool like SourceTree or GitHub Desktop can help you with Git commands.)
(You can also download SeleniumBase from GitHub without using git-related commands.)
"}, {"location": "help_docs/install_python_pip_git/#python", "title": "Python", "text": "You can download Python from https://www.python.org/downloads/ if it's not already preinstalled on your machine.
"}, {"location": "help_docs/install_python_pip_git/#pip", "title": "pip", "text": "pip
already comes with Python! (It lets you install packages, such as seleniumbase
.)
\u26a0\ufe0f If something went wrong with your pip
installation, try this:
python -m ensurepip --default-pip\n
If your existing version of pip is old, upgrade to the latest version:
python -m pip install --upgrade pip setuptools\n
On CentOS 7 and some versions of Linux, you may need to install pip with yum
:
yum -y update\nyum -y install python-pip\n
If you're having any trouble getting pip, you can GET PIP HERE.
When done, make sure the location of pip is on your path, which is $PATH
for macOS/Linux. (On Windows, it's the System Variables Path
within System Environment Variables.)
You can also get pip (or fix pip) by using:
curl https://bootstrap.pypa.io/get-pip.py | python\n
Keep Pip and Setuptools up-to-date:
python -m pip install -U pip setuptools\n
--user
to the command if you're not inside a Python virtual environment, or use \"sudo\" on a UNIX-based OS if you're getting errors during installation.)\ud83c\udfa8 The following SeleniumBase solutions utilize this feature:
\ud83c\udfa6 (Demo Mode)
\ud83d\ude8e (Website Tours)
\ud83c\udf9e\ufe0f (Presentation Maker)
\ud83d\udcca (Chart Maker / Dashboard)
\ud83d\udec2 (Dialog Boxes / MasterQA)
\ud83d\uddfa\ufe0f Here's an example of loading a website-tour library into the browser for a Google Maps tour:
\ud83d\uddfa\ufe0f This example is from maps_introjs_tour.py. (The --interval=1
makes the tour go automatically to the next step after 1 second.)
cd examples/tour_examples\npytest maps_introjs_tour.py --interval=1\n
\ud83d\udd79\ufe0f SeleniumBase includes powerful JS code generators for converting Python into JavaScript for using the supported JS packages. A few lines of Python in your tests might generate hundreds of lines of JavaScript.
\ud83d\uddfa\ufe0f Here is some tour code in Python from maps_introjs_tour.py that expands into a lot of JavaScript.
self.open(\"https://www.google.com/maps/@42.3591234,-71.0915634,15z\")\nself.create_tour(theme=\"introjs\")\nself.add_tour_step(\"Welcome to Google Maps!\", title=\"SeleniumBase Tours\")\nself.add_tour_step(\"Enter Location\", \"#searchboxinput\", title=\"Search Box\")\nself.add_tour_step(\"See it\", \"#searchbox-searchbutton\", alignment=\"bottom\")\nself.add_tour_step(\"Thanks for using Tours!\", title=\"End of Guided Tour\")\nself.export_tour(filename=\"maps_introjs_tour.js\")\nself.play_tour()\n
\ud83d\udd79\ufe0f For existing features, SeleniumBase already takes care of loading all the necessary JS and CSS files into the web browser. To load other packages, here are a few useful methods that you should know about:
self.add_js_link(js_link)\n
\ud83d\udd79\ufe0f This example loads the IntroJS JavaScript library:
self.add_js_link(\"https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.9.3/intro.min.js\")\n
\ud83d\udd79\ufe0f You can load any JS package this way as long as you know the URL. \ud83d\udd79\ufe0f If you're wondering how SeleniumBase does this, here's the full Python code from js_utils.py, which uses WebDriver's execute_script()
method for making JS calls after escaping quotes with backslashes as needed:
def add_js_link(driver, js_link):\n script_to_add_js = (\n \"\"\"function injectJS(link) {\n var body = document.getElementsByTagName(\"body\")[0];\n var script = document.createElement(\"script\");\n script.src = link;\n script.defer;\n script.type=\"text/javascript\";\n script.crossorigin = \"anonymous\";\n script.onload = function() { null };\n body.appendChild(script);\n }\n injectJS(\"%s\");\"\"\")\n js_link = escape_quotes_if_needed(js_link)\n driver.execute_script(script_to_add_js % js_link)\n
\ud83d\udd79\ufe0f Now that you've loaded JavaScript into the browser, you may also want to load some CSS to go along with it:
self.add_css_link(css_link)\n
\ud83d\udd79\ufe0f Here's code that loads the IntroJS CSS:
self.add_css_link(\"https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.9.3/introjs.css\")\n
\ud83d\udd79\ufe0f And here's the Python WebDriver code that makes this possible:
def add_css_link(driver, css_link):\n script_to_add_css = (\n \"\"\"function injectCSS(css) {\n var head = document.getElementsByTagName(\"head\")[0];\n var link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.type = \"text/css\";\n link.href = css;\n link.crossorigin = \"anonymous\";\n head.appendChild(link);\n }\n injectCSS(\"%s\");\"\"\")\n css_link = escape_quotes_if_needed(css_link)\n driver.execute_script(script_to_add_css % css_link)\n
\ud83d\udd79\ufe0f Website tours are just one of the many uses of the JS Package Manager. \ud83d\udec2 The following example shows the JqueryConfirm package loaded into a website for creating fancy dialog boxes:
\u2195\ufe0f (Example: dialog_box_tour.py) \u2195\ufe0f Here's how to run that example:cd examples/dialog_boxes\npytest test_dialog_boxes.py\n
(Example from the Dialog Boxes ReadMe)
\ud83d\udd79\ufe0f Since packages are loaded directly from a CDN link, you won't need other package managers like NPM, Bower, or Yarn to get the packages that you need into the websites that you want. To learn more about SeleniumBase, check out the Docs Site:All the code is on GitHub:
"}, {"location": "help_docs/locale_codes/", "title": "\ud83d\uddfe Locale Codes", "text": ""}, {"location": "help_docs/locale_codes/#language-locale-codes", "title": "Language Locale Codes", "text": "
You can specify a Language Locale Code to customize web pages on supported websites. With SeleniumBase, you can change the web browser's Locale on the command line by doing this:
pytest --locale=CODE # Example: --locale=ru\n
List of Language Locale Codes: LanguageCode Afrikaansaf
Amharicam
Arabicar
Arabic (Egypt)ar_eg
Arabic (Saudi Arabia)ar_sa
Basqueeu
Belarusianbe
Bengalibn
Bulgarianbg
Catalanca
Chinesezh
Chinese (China Mainland)zh_cn
Chinese (Hong Kong)zh_hk
Chinese (Taiwan)zh_tw
Croatianhr
Czechcs
Danishda
Dutchnl
Englishen
English (United States)en_us
English (Australia)en_au
English (Canada)en_ca
English (United Kingdom)en_gb
English (Ireland)en_ie
English (India)en_in
English (Singapore)en_sg
English (South Africa)en_za
Estonianet
Farsifa
Filipinofil
Finnishfi
Frenchfr
French (Canada)fr_ca
French (Switzerland)fr_ch
Galiciangl
Germande
German (Austria)de_at
Greekel
Gujaratigu
Hebrewhe
Hindihi
Hungarianhu
Icelandicis
Indonesianid
Italianit
Japaneseja
Kannadakn
Koreanko
Laolo
Latvianlv
Lingalaln
Lithuanianlt
Malayms
Malayalamml
Marathimr
Norwegianno
Polishpl
Portuguesept
Portuguese (Brazil)pt_br
Portuguese (Portugal)pt_pt
Romanianro
Russianru
Serbiansr
Slovaksk
Sloveniansl
Spanishes
Spanish (Latin America)es_419
Spanish (Argentina)es_ar
Spanish (Chile)es_cl
Spanish (Colombia)es_co
Spanish (Costa Rica)es_cr
Spanish (Dominican Rep.)es_do
Spanish (Ecuador)es_ec
Spanish (El Salvador)es_sv
Spanish (Guatemala)es_gt
Spanish (Honduras)es_hn
Spanish (Mexico)es_mx
Spanish (Nicaragua)es_ni
Spanish (Panama)es_pa
Spanish (Peru)es_pe
Spanish (Puerto Rico)es_pr
Spanish (Paraguay)es_py
Spanish (United States)es_us
Spanish (Uruguay)es_uy
Spanish (Venezuela)es_ve
Swahilisw
Swedishsv
Swiss Germangsw
Tagalogtl
Tamilta
Telugute
Thaith
Turkishtr
Ukrainianuk
Urduur
Vietnamesevi
Zuluzu
"}, {"location": "help_docs/method_summary/", "title": "\ud83d\udcd8 API Reference", "text": ""}, {"location": "help_docs/method_summary/#seleniumbase-methods-api-reference", "title": "SeleniumBase Methods (API Reference)\ud83d\udd35 Examples", "text": "Here's a list of SeleniumBase method definitions, which are defined in base_case.py
For backwards compatibility, older versions of method names have remained to keep older scripts working. (E.g: wait_for_element_visible was shortened to wait_for_element and then to find_element.)
self.open(url)\n# Duplicates: self.open_url(url), self.visit(url), visit_url(url),\n# self.goto(url), self.go_to(url)\n\nself.get(url)\n# If the url parameter is a URL: Perform self.open(url)\n# Otherwise: return self.get_element(URL_AS_A_SELECTOR)\n\nself.click(selector, by=\"css selector\", timeout=None, delay=0, scroll=True)\n\nself.slow_click(selector, by=\"css selector\", timeout=None)\n\nself.double_click(selector, by=\"css selector\", timeout=None)\n\nself.context_click(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.right_click(selector, by=\"css selector\", timeout=None)\n\nself.click_chain(selectors_list, by=\"css selector\", timeout=None, spacing=0)\n\nself.type(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.update_text(selector, text, by=\"css selector\", timeout=None)\n# self.input(selector, text, by=\"css selector\", timeout=None)\n# self.fill(selector, text, by=\"css selector\", timeout=None)\n# self.write(selector, text, by=\"css selector\", timeout=None)\n\nself.send_keys(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.add_text(selector, text, by=\"css selector\", timeout=None)\n\nself.press_keys(selector, text, by=\"css selector\", timeout=None)\n\nself.submit(selector, by=\"css selector\")\n\nself.clear(selector, by=\"css selector\", timeout=None)\n\nself.focus(selector, by=\"css selector\", timeout=None)\n\nself.refresh()\n# Duplicates: self.refresh_page(), self.reload_page(), self.reload()\n\nself.get_current_url()\n\nself.get_origin()\n\nself.get_page_source()\n\nself.get_title()\n# Duplicates: self.get_page_title()\n\nself.get_user_agent()\n\nself.get_locale_code()\n\nself.go_back()\n\nself.go_forward()\n\nself.open_start_page()\n\nself.open_if_not_url(url)\n\nself.is_element_present(selector, by=\"css selector\")\n\nself.is_element_visible(selector, by=\"css selector\")\n\nself.is_element_clickable(selector, by=\"css selector\")\n\nself.is_element_enabled(selector, by=\"css selector\")\n\nself.is_text_visible(text, selector=\"html\", by=\"css selector\")\n\nself.is_exact_text_visible(text, selector=\"html\", by=\"css selector\")\n\nself.is_non_empty_text_visible(selector=\"html\", by=\"css selector\")\n\nself.is_attribute_present(selector, attribute, value=None, by=\"css selector\")\n\nself.is_link_text_visible(link_text)\n\nself.is_partial_link_text_visible(partial_link_text)\n\nself.is_link_text_present(link_text)\n\nself.is_partial_link_text_present(link_text)\n\nself.get_link_attribute(link_text, attribute, hard_fail=True)\n# Duplicates\n# self.get_link_text_attribute(link_text, attribute, hard_fail=True)\n\nself.get_partial_link_text_attribute(link_text, attribute, hard_fail=True)\n\nself.click_link(link_text, timeout=None)\n# Duplicates\n# self.click_link_text(link_text, timeout=None)\n\nself.click_partial_link(partial_link_text, timeout=None)\n# Duplicates\n# self.click_partial_link_text(partial_link_text, timeout=None)\n\nself.get_text(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.get_attribute(selector, attribute, by=\"css selector\", timeout=None, hard_fail=True)\n\nself.set_attribute(selector, attribute, value, by=\"css selector\", timeout=None, scroll=False)\n\nself.set_attributes(selector, attribute, value, by=\"css selector\")\n# Duplicates\n# self.set_attribute_all(selector, attribute, value, by=\"css selector\")\n\nself.remove_attribute(selector, attribute, by=\"css selector\", timeout=None)\n\nself.remove_attributes(selector, attribute, by=\"css selector\")\n\nself.get_property(selector, property, by=\"css selector\", timeout=None)\n\nself.get_text_content(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.get_property_value(selector, property, by=\"css selector\", timeout=None)\n\nself.get_image_url(selector, by=\"css selector\", timeout=None)\n\nself.find_elements(selector, by=\"css selector\", limit=0)\n\nself.find_visible_elements(selector, by=\"css selector\", limit=0)\n\nself.click_visible_elements(selector, by=\"css selector\", limit=0, timeout=None)\n\nself.click_nth_visible_element(selector, number, by=\"css selector\", timeout=None)\n\nself.click_if_visible(selector, by=\"css selector\", timeout=0)\n\nself.click_active_element()\n\nself.click_with_offset(\n selector, x, y, by=\"css selector\", mark=None, timeout=None, center=None)\n\nself.double_click_with_offset(\n selector, x, y, by=\"css selector\", mark=None, timeout=None, center=None)\n\nself.is_checked(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.is_selected(selector, by=\"css selector\", timeout=None)\n\nself.check_if_unchecked(selector, by=\"css selector\")\n# Duplicates\n# self.select_if_unselected(selector, by=\"css selector\")\n\nself.uncheck_if_checked(selector, by=\"css selector\")\n# Duplicates\n# self.unselect_if_selected(selector, by=\"css selector\")\n\nself.is_element_in_an_iframe(selector, by=\"css selector\")\n\nself.switch_to_frame_of_element(selector, by=\"css selector\")\n\nself.hover(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.hover_on_element(selector, by=\"css selector\", timeout=None)\n# self.hover_over_element(selector, by=\"css selector\", timeout=None)\n\nself.hover_and_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None, js_click=False)\n\nself.hover_and_js_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None)\n\nself.hover_and_double_click(\n hover_selector, click_selector,\n hover_by=\"css selector\", click_by=\"css selector\",\n timeout=None)\n\nself.drag_and_drop(\n drag_selector, drop_selector,\n drag_by=\"css selector\", drop_by=\"css selector\",\n timeout=None, jquery=False)\n\nself.drag_and_drop_with_offset(\n selector, x, y, by=\"css selector\", timeout=None)\n\nself.select_option_by_text(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.select_option_by_index(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.select_option_by_value(\n dropdown_selector, option, dropdown_by=\"css selector\", timeout=None)\n\nself.get_select_options(\n dropdown_selector, attribute=\"text\", by=\"css selector\", timeout=None)\n\nself.load_html_string(html_string, new_page=True)\n\nself.set_content(html_string, new_page=False)\n\nself.load_html_file(html_file, new_page=True)\n\nself.open_html_file(html_file)\n\nself.execute_script(script, *args, **kwargs)\n\nself.execute_cdp_cmd(script, *args, **kwargs)\n\nself.execute_async_script(script, timeout=None)\n\nself.safe_execute_script(script, *args, **kwargs)\n\nself.get_gui_element_rect(selector, by=\"css selector\")\n\nself.get_gui_element_center(selector, by=\"css selector\")\n\nself.get_window_rect()\n\nself.get_window_size()\n\nself.get_window_position()\n\nself.set_window_rect(x, y, width, height)\n\nself.set_window_size(width, height)\n\nself.set_window_position(x, y)\n\nself.maximize_window()\n\nself.switch_to_frame(frame=\"iframe\", timeout=None)\n\nself.switch_to_default_content()\n\nself.switch_to_parent_frame()\n\nwith self.frame_switch(frame, timeout=None):\n # Indented Code Block for Context Manager (Must use \"with\")\n\nself.set_content_to_frame(frame, timeout=None)\n\nself.set_content_to_default(nested=False)\n# Duplicates: self.set_content_to_default_content(nested=False)\n\nself.set_content_to_parent()\n# Duplicates: self.set_content_to_parent_frame()\n\nself.open_new_window(switch_to=True)\n# Duplicates: self.open_new_tab(switch_to=True)\n\nself.switch_to_window(window, timeout=None)\n# Duplicates: self.switch_to_tab(tab, timeout=None)\n\nself.switch_to_default_window()\n# Duplicates: self.switch_to_default_tab()\n\nself.switch_to_newest_window()\n# Duplicates: self.switch_to_newest_tab()\n\nself.get_new_driver(\n browser=None,\n headless=None,\n locale_code=None,\n protocol=None,\n servername=None,\n port=None,\n proxy=None,\n proxy_bypass_list=None,\n proxy_pac_url=None,\n multi_proxy=None,\n agent=None,\n switch_to=True,\n cap_file=None,\n cap_string=None,\n recorder_ext=None,\n disable_js=None,\n disable_csp=None,\n enable_ws=None,\n enable_sync=None,\n use_auto_ext=None,\n undetectable=None,\n uc_cdp_events=None,\n uc_subprocess=None,\n log_cdp_events=None,\n no_sandbox=None,\n disable_gpu=None,\n headless2=None,\n incognito=None,\n guest_mode=None,\n dark_mode=None,\n devtools=None,\n remote_debug=None,\n enable_3d_apis=None,\n swiftshader=None,\n ad_block_on=None,\n host_resolver_rules=None,\n block_images=None,\n do_not_track=None,\n chromium_arg=None,\n firefox_arg=None,\n firefox_pref=None,\n user_data_dir=None,\n extension_zip=None,\n extension_dir=None,\n disable_features=None,\n binary_location=None,\n driver_version=None,\n page_load_strategy=None,\n use_wire=None,\n external_pdf=None,\n is_mobile=None,\n d_width=None,\n d_height=None,\n d_p_r=None,\n)\n\nself.switch_to_driver(driver)\n\nself.switch_to_default_driver()\n\nself.save_screenshot(name, folder=None, selector=None, by=\"css selector\")\n\nself.save_screenshot_to_logs(name=None, selector=None, by=\"css selector\")\n\nself.save_data_to_logs(data, file_name=None)\n\nself.append_data_to_logs(data, file_name=None)\n\nself.save_page_source(name, folder=None)\n\nself.save_cookies(name=\"cookies.txt\")\n\nself.load_cookies(name=\"cookies.txt\")\n\nself.delete_all_cookies()\n# Duplicates: self.clear_all_cookies()\n\nself.delete_saved_cookies(name=\"cookies.txt\")\n\nself.get_saved_cookies(name=\"cookies.txt\")\n\nself.get_cookie(name)\n\nself.get_cookies()\n\nself.add_cookie(cookie_dict)\n\nself.add_cookies(cookies)\n\nself.wait_for_ready_state_complete(timeout=None)\n\nself.wait_for_angularjs(timeout=None)\n\nself.sleep(seconds)\n# Duplicates: self.wait(seconds)\n\nself.install_addon(xpi_file)\n\nself.activate_jquery()\n\nself.activate_demo_mode()\n\nself.deactivate_demo_mode()\n\nself.activate_design_mode()\n\nself.deactivate_design_mode()\n\nself.activate_recorder()\n\nself.save_recorded_actions()\n\nself.bring_active_window_to_front()\n\nself.bring_to_front(selector, by=\"css selector\")\n\nself.highlight_click(selector, by=\"css selector\", loops=3, scroll=True, timeout=None)\n\nself.highlight_type(selector, text, by=\"css selector\", loops=3, scroll=True, timeout=None)\n# Duplicates\n# self.highlight_update_text(\n# selector, text, by=\"css selector\", loops=3, scroll=True, timeout=None)\n\nself.highlight_if_visible(selector, by=\"css selector\", loops=4, scroll=True)\n\nself.highlight(selector, by=\"css selector\", loops=4, scroll=True, timeout=None)\n\nself.highlight_elements(selector, by=\"css selector\", loops=4, scroll=True, limit=0)\n\nself.press_up_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_down_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_left_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.press_right_arrow(selector=\"html\", times=1, by=\"css selector\")\n\nself.scroll_to(selector, by=\"css selector\", timeout=None)\n# Duplicates: self.scroll_to_element(selector, by=\"css selector\")\n\nself.slow_scroll_to(selector, by=\"css selector\", timeout=None)\n# Duplicates: self.slow_scroll_to_element(selector, by=\"css selector\")\n\nself.scroll_into_view(selector, by=\"css selector\", timeout=None)\n\nself.scroll_to_top()\n\nself.scroll_to_bottom()\n\nself.click_xpath(xpath)\n\nself.js_click(selector, by=\"css selector\", all_matches=False, timeout=None, scroll=True)\n\nself.js_click_if_present(selector, by=\"css selector\", timeout=0)\n\nself.js_click_if_visible(selector, by=\"css selector\", timeout=0)\n\nself.js_click_all(selector, by=\"css selector\", timeout=None)\n\nself.jquery_click(selector, by=\"css selector\", timeout=None)\n\nself.jquery_click_all(selector, by=\"css selector\", timeout=None)\n\nself.hide_element(selector, by=\"css selector\")\n\nself.hide_elements(selector, by=\"css selector\")\n\nself.show_element(selector, by=\"css selector\")\n\nself.show_elements(selector, by=\"css selector\")\n\nself.remove_element(selector, by=\"css selector\")\n\nself.remove_elements(selector, by=\"css selector\")\n\nself.ad_block()\n# Duplicates: self.block_ads()\n\nself.show_file_choosers()\n\nself.disable_beforeunload()\n\nself.get_domain_url(url)\n\nself.get_active_element_css()\n\nself.get_beautiful_soup(source=None)\n\nself.get_unique_links()\n\nself.get_link_status_code(link, allow_redirects=False, timeout=5, verify=False)\n\nself.assert_link_status_code_is_not_404(link)\n\nself.assert_no_404_errors(multithreaded=True, timeout=None)\n# Duplicates\n# self.assert_no_broken_links(multithreaded=True, timeout=None)\n\nself.print_unique_links_with_status_codes()\n\nself.get_pdf_text(\n pdf, page=None, maxpages=None, password=None,\n codec='utf-8', wrap=False, nav=False, override=False, caching=True)\n\nself.assert_pdf_text(\n pdf, text, page=None, maxpages=None, password=None,\n codec='utf-8', wrap=True, nav=False, override=False, caching=True)\n\nself.create_folder(folder)\n\nself.choose_file(selector, file_path, by=\"css selector\", timeout=None)\n\nself.save_element_as_image_file(selector, file_name, folder=None, overlay_text=\"\")\n\nself.download_file(file_url, destination_folder=None)\n\nself.save_file_as(file_url, new_file_name, destination_folder=None)\n\nself.save_data_as(data, file_name, destination_folder=None)\n\nself.append_data_to_file(data, file_name, destination_folder=None)\n\nself.get_file_data(file_name, folder=None)\n\nself.get_downloads_folder()\n\nself.get_browser_downloads_folder()\n\nself.get_downloaded_files(regex=None, browser=False)\n\nself.get_path_of_downloaded_file(file, browser=False)\n\nself.get_data_from_downloaded_file(file, timeout=None, browser=False)\n\nself.is_downloaded_file_present(file, browser=False)\n\nself.is_downloaded_file_regex_present(regex, browser=False)\n\nself.delete_downloaded_file_if_present(file, browser=False)\n# Duplicates: self.delete_downloaded_file(file, browser=False)\n\nself.assert_downloaded_file(file, timeout=None, browser=False)\n\nself.assert_downloaded_file_regex(regex, timeout=None, browser=False)\n\nself.assert_data_in_downloaded_file(data, file, timeout=None, browser=False)\n\nself.assert_true(expr, msg=None)\n\nself.assert_false(expr, msg=None)\n\nself.assert_equal(first, second, msg=None)\n\nself.assert_not_equal(first, second, msg=None)\n\nself.assert_in(first, second, msg=None)\n\nself.assert_not_in(first, second, msg=None)\n\nself.assert_raises(*args, **kwargs)\n\nself.wait_for_attribute(selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_attribute(selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_title(title)\n\nself.assert_title_contains(substring)\n\nself.assert_url(url)\n\nself.assert_url_contains(substring)\n\nself.assert_no_js_errors(exclude=[])\n\nself.inspect_html()\n\nself.is_valid_url(url)\n\nself.is_online()\n\nself.is_chromium()\n\nself.get_chrome_version()\n\nself.get_chromium_version()\n\nself.get_chromedriver_version()\n\nself.get_chromium_driver_version()\n\nself.get_mfa_code(totp_key=None)\n# Duplicates\n# self.get_totp_code(totp_key=None)\n# self.get_google_auth_password(totp_key=None)\n# self.get_google_auth_code(totp_key=None)\n\nself.enter_mfa_code(selector, totp_key=None, by=\"css selector\", timeout=None)\n# Duplicates\n# self.enter_totp_code(selector, totp_key=None, by=\"css selector\", timeout=None)\n\nself.convert_css_to_xpath(css)\n\nself.convert_xpath_to_css(xpath)\n\nself.convert_to_css_selector(selector, by)\n\nself.set_value(selector, text, by=\"css selector\", timeout=None, scroll=True)\n\nself.js_update_text(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.js_type(selector, text, by=\"css selector\", timeout=None)\n# self.set_text(selector, text, by=\"css selector\", timeout=None)\n\nself.set_text_content(selector, text, by=\"css selector\", timeout=None, scroll=False)\n\nself.jquery_update_text(selector, text, by=\"css selector\", timeout=None)\n# Duplicates\n# self.jquery_type(selector, text, by=\"css selector\", timeout=None)\n\nself.get_value(selector, by=\"css selector\", timeout=None)\n\nself.set_time_limit(time_limit)\n\nself.set_default_timeout(timeout)\n\nself.reset_default_timeout()\n\nself.fail(msg=None)\n\nself.skip(reason=\"\")\n\n############\n\nself.start_recording_console_logs()\n\nself.console_log_string(string)\n\nself.console_log_script(script)\n\nself.get_recorded_console_logs()\n\n############\n\nself.set_local_storage_item(key, value)\n\nself.get_local_storage_item(key)\n\nself.remove_local_storage_item(key)\n\nself.clear_local_storage()\n# Duplicates: delete_local_storage()\n\nself.get_local_storage_keys()\n\nself.get_local_storage_items()\n\nself.set_session_storage_item(key, value)\n\nself.get_session_storage_item(key)\n\nself.remove_session_storage_item(key)\n\nself.clear_session_storage()\n# Duplicates: delete_session_storage()\n\nself.get_session_storage_keys()\n\nself.get_session_storage_items()\n\n############\n\nself.set_wire_proxy(string) # Requires \"--wire\"!\n\n############\n\nself.add_css_link(css_link)\n\nself.add_js_link(js_link)\n\nself.add_css_style(css_style)\n\nself.add_js_code_from_link(js_link)\n\nself.add_js_code(js_code)\n\nself.add_meta_tag(http_equiv=None, content=None)\n\n############\n\nself.create_presentation(name=None, theme=\"default\", transition=\"default\")\n\nself.add_slide(\n content=None, image=None, code=None, iframe=None,\n content2=None, notes=None, transition=None, name=None)\n\nself.save_presentation(name=None, filename=None, show_notes=False, interval=0)\n\nself.begin_presentation(name=None, filename=None, show_notes=False, interval=0)\n\n############\n\nself.create_pie_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_bar_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_column_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, libs=True,\n labels=True, legend=True)\n\nself.create_line_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True,\n labels=True, legend=True)\n\nself.create_area_chart(\n chart_name=None, title=None, subtitle=None,\n data_name=None, unit=None, zero=False, libs=True,\n labels=True, legend=True)\n\nself.add_series_to_chart(data_name=None, chart_name=None)\n\nself.add_data_point(label, value, color=None, chart_name=None)\n\nself.save_chart(chart_name=None, filename=None, folder=None)\n\nself.display_chart(chart_name=None, filename=None, interval=0)\n\nself.extract_chart(chart_name=None)\n\n############\n\nself.create_tour(name=None, theme=None)\n\nself.create_shepherd_tour(name=None, theme=None)\n\nself.create_bootstrap_tour(name=None)\n\nself.create_hopscotch_tour(name=None)\n\nself.create_introjs_tour(name=None)\n\nself.set_introjs_colors(theme_color=None, hover_color=None)\n\nself.add_tour_step(message, selector=None, name=None, title=None, theme=None, alignment=None)\n\nself.play_tour(name=None, interval=0)\n# Duplicates\n# self.start_tour(name=None, interval=0):\n\nself.export_tour(name=None, filename=\"my_tour.js\", url=None)\n\n############\n\nself.activate_jquery_confirm()\n\nself.set_jqc_theme(theme, color=None, width=None)\n\nself.reset_jqc_theme()\n\nself.get_jqc_button_input(message, buttons, options=None)\n\nself.get_jqc_text_input(message, button=None, options=None)\n\nself.get_jqc_form_inputs(message, buttons, options=None)\n\n############\n\nself.activate_messenger()\n\nself.post_message(message, duration=None, pause=True, style=\"info\")\n\nself.post_message_and_highlight(message, selector, by=\"css selector\")\n\nself.post_success_message(message, duration=None, pause=True)\n\nself.post_error_message(message, duration=None, pause=True)\n\nself.set_messenger_theme(theme=\"default\", location=\"default\", max_messages=\"default\")\n\n############\n\nself.generate_referral(start_page, destination_page, selector=None)\n\nself.generate_traffic(start_page, destination_page, loops=1, selector=None)\n\nself.generate_referral_chain(pages)\n\nself.generate_traffic_chain(pages, loops=1)\n\n############\n\nself.get_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_selector(selector, by=\"css selector\", timeout=None)\n# self.locator(selector, by=\"css selector\", timeout=None)\n# self.wait_for_element_present(selector, by=\"css selector\", timeout=None)\n\nself.wait_for_query_selector(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_present(selector, by=\"css selector\", timeout=None)\n\nself.assert_elements_present(*args, **kwargs)\n\n############\n\nself.find_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_element(selector, by=\"css selector\", timeout=None)\n# self.wait_for_element_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_element(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_element_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_elements(*args, **kwargs)\n# Duplicates\n# self.assert_elements_visible(*args, **kwargs)\n\n############\n\nself.find_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.find_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_exact_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.find_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n# self.wait_for_non_empty_text_visible(selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_text_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_exact_text(text, selector=\"html\", by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_link_text_present(link_text, timeout=None)\n\nself.wait_for_partial_link_text_present(link_text, timeout=None)\n\nself.find_link_text(link_text, timeout=None)\n# Duplicates\n# self.wait_for_link_text(link_text, timeout=None)\n# self.wait_for_link_text_visible(link_text, timeout=None)\n\nself.assert_link_text(link_text, timeout=None)\n# Duplicates\n# self.assert_link(link_text, timeout=None)\n\n############\n\nself.find_partial_link_text(partial_link_text, timeout=None)\n# Duplicates\n# self.wait_for_partial_link_text(partial_link_text, timeout=None)\n\nself.assert_partial_link_text(partial_link_text, timeout=None)\n\n############\n\nself.wait_for_element_absent(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.wait_for_element_not_present(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_absent(selector, by=\"css selector\", timeout=None)\n# Duplicates\n# self.assert_element_not_present(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_element_clickable(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_element_not_visible(selector, by=\"css selector\", timeout=None)\n\nself.assert_element_not_visible(selector, by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.wait_for_exact_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_exact_text_not_visible(text, selector=\"html\", by=\"css selector\", timeout=None)\n\nself.assert_non_empty_text(selector=\"html\", by=\"css selector\", timeout=None)\n\n############\n\nself.wait_for_attribute_not_present(\n selector, attribute, value=None, by=\"css selector\", timeout=None)\n\nself.assert_attribute_not_present(\n selector, attribute, value=None, by=\"css selector\", timeout=None)\n\n############\n\nself.accept_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_accept_alert(timeout=None)\n\nself.dismiss_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_dismiss_alert(timeout=None)\n\nself.switch_to_alert(timeout=None)\n# Duplicates\n# self.wait_for_and_switch_to_alert(timeout=None)\n\n############\n\nself.quit_extra_driver(driver=None)\n\n############\n\nself.check_window(name=\"default\", level=0, baseline=False, check_domain=True, full_diff=False)\n\n############\n\nself.deferred_assert_element(selector, by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_element(\n# selector, by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_element_present(selector, by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_element_present(\n# selector, by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_text(text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_text(\n# text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_exact_text(\n text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_exact_text(\n# text, selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_assert_non_empty_text(\n selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n# Duplicates\n# self.delayed_assert_non_empty_text(\n# selector=\"html\", by=\"css selector\", timeout=None, fs=False)\n\nself.deferred_check_window(\n name=\"default\", level=0, baseline=False, check_domain=True, full_diff=False, fs=False)\n# Duplicates\n# self.delayed_check_window(\n# name=\"default\", level=0, baseline=False,\n# check_domain=True, full_diff=False, fs=False)\n\nself.process_deferred_asserts(print_only=False)\n# Duplicates: self.process_delayed_asserts(print_only=False)\n\n############\n\nself.fail(msg=None) # Inherited from \"unittest\"\n\nself._check_browser() # Fails test cleanly if the active window is closed\n\nself._print(TEXT) # Calls Python's print() / Allows for translations\n\n############ # \"driver\"-specific methods added (or modified) by SeleniumBase\ndriver.default_get(url) # Because driver.get(url) works differently in UC Mode\n\ndriver.open(url) # Like driver.get(), but allows partial URLs without protocol\n\ndriver.click(selector)\n\ndriver.click_link(link_text)\n\ndriver.click_if_visible(selector)\n\ndriver.click_active_element()\n\ndriver.send_keys(selector, text)\n\ndriver.press_keys(selector, text)\n\ndriver.type(selector, text)\n\ndriver.submit(selector)\n\ndriver.assert_element(selector)\n\ndriver.assert_element_present(selector)\n\ndriver.assert_element_not_visible(selector)\n\ndriver.assert_text(text, selector)\n\ndriver.assert_exact_text(text, selector)\n\ndriver.find_element(selector)\n\ndriver.find_elements(selector)\n\ndriver.wait_for_element(selector)\n\ndriver.wait_for_element_visible(selector)\n\ndriver.wait_for_element_present(selector)\n\ndriver.wait_for_selector(selector)\n\ndriver.wait_for_text(text, selector)\n\ndriver.wait_for_exact_text(text, selector)\n\ndriver.wait_for_and_accept_alert()\n\ndriver.wait_for_and_dismiss_alert()\n\ndriver.is_element_present(selector)\n\ndriver.is_element_visible(selector)\n\ndriver.is_text_visible(text, selector)\n\ndriver.is_exact_text_visible(text, selector)\n\ndriver.is_attribute_present(selector, attribute)\n\ndriver.get_text(selector)\n\ndriver.js_click(selector)\n\ndriver.get_active_element_css()\n\ndriver.get_locale_code()\n\ndriver.get_origin()\n\ndriver.get_user_agent()\n\ndriver.highlight(selector)\n\ndriver.highlight_click(selector)\n\ndriver.highlight_if_visible(selector)\n\ndriver.sleep(seconds)\n\ndriver.locator(selector)\n\ndriver.get_attribute(selector, attribute)\n\ndriver.get_page_source()\n\ndriver.get_title()\n\ndriver.switch_to_frame(frame=\"iframe\")\n\n############ # \"driver\"-specific methods added (or modified) by SeleniumBase for UC Mode\ndriver.get(url) # If UC Mode and site detects bots, then uc_open_with_tab(url)\n\ndriver.uc_open(url) # (Open in same tab with default reconnect_time)\n\ndriver.uc_open_with_tab(url) # (New tab with default reconnect_time)\n\ndriver.uc_open_with_reconnect(url, reconnect_time=None) # (New tab)\n\ndriver.uc_open_with_disconnect(url, timeout=None) # New tab + sleep()\n\ndriver.reconnect(timeout) # disconnect() + sleep(timeout) + connect()\n\ndriver.disconnect() # Stops the webdriver service to prevent detection\n\ndriver.connect() # Starts the webdriver service to allow actions again\n\ndriver.uc_click(selector) # A stealthy click for evading bot-detection\n\ndriver.uc_gui_press_key(key) # Use PyAutoGUI to press the keyboard key\n\ndriver.uc_gui_press_keys(keys) # Use PyAutoGUI to press a list of keys\n\ndriver.uc_gui_write(text) # Similar to uc_gui_press_keys(), but faster\n\ndriver.uc_gui_click_x_y(x, y, timeframe=0.25) # PyAutoGUI click screen\n\ndriver.uc_gui_click_captcha(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False) # reC\n\ndriver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False) # CFT\n\ndriver.uc_gui_handle_cf(frame=\"iframe\") # PyAutoGUI click CF Turnstile\n\ndriver.uc_switch_to_frame(frame=\"iframe\") # Stealthy switch_to_frame()\n
\u2705 Test Folder: SeleniumBase/examples
Use --mobile
to run SeleniumBase tests using Chrome's mobile device emulator with default values for Device Metrics and User-Agent.
Here's an example mobile test:
SeleniumBase/examples/test_skype_site.py
pytest test_skype_site.py --mobile\n
To configure Device Metrics, use:
--metrics=\"CSS_Width,CSS_Height,Pixel_Ratio\"\n
To configure the User-Agent, use:
--agent=\"USER-AGENT-STRING\"\n
To find real values for Device Metrics, see:
To find real User-Agent strings, see:
Here's another example of a mobile test:
SeleniumBase/examples/test_swag_labs.py
pytest test_swag_labs.py --mobile\n
Here's an example of configuring mobile settings for that test:
# Run tests using Chrome's mobile device emulator (default settings)\npytest test_swag_labs.py --mobile\n\n# Run mobile tests specifying CSS Width, CSS Height, and Pixel-Ratio\npytest test_swag_labs.py --mobile --metrics=\"360,640,2\"\n\n# Run mobile tests specifying the user agent\npytest test_swag_labs.py --mobile --agent=\"Mozilla/5.0 (Linux; Android 9; Pixel 3 XL)\"\n
For some SeleniumBase Syntax Formats, you can also use mobile=True
to run tests in Mobile Mode:
from seleniumbase import Driver\n\ndriver = Driver(mobile=True)\ntry:\n driver.open(\"https://www.skype.com/en/get-skype/\")\n driver.assert_element('[aria-label=\"Microsoft\"]')\n driver.assert_text(\"Download Skype\", \"h1\")\n driver.highlight(\"div.appBannerContent\")\n driver.highlight(\"h1\")\n driver.assert_text(\"Skype for Mobile\", \"h2\")\n driver.highlight(\"h2\")\n driver.highlight(\"#get-skype-0\")\n driver.highlight_click(\"span[data-dropdown-icon]\")\n driver.highlight(\"#get-skype-0_android-download\")\n driver.highlight('[data-bi-id*=\"ios\"]')\nfinally:\n driver.quit()\n
"}, {"location": "help_docs/mysql_installation/", "title": "\ud83d\uddc4\ufe0f MySQL Instructions", "text": ""}, {"location": "help_docs/mysql_installation/#mysql-installation-instructions", "title": "MySQL Installation Instructions", "text": ""}, {"location": "help_docs/mysql_installation/#mysql-optional", "title": "MySQL (OPTIONAL)", "text": "
(NOTE: If you don't plan on using the SeleniumBase MySQL DB feature, then you can skip this section.)
"}, {"location": "help_docs/mysql_installation/#github-actions-ubuntu-linux-mysql-setup", "title": "GitHub Actions Ubuntu Linux MySQL Setup", "text": "sudo /etc/init.d/mysql start\nmysql -e 'CREATE DATABASE IF NOT EXISTS test_db;' -uroot -proot\nwget https://raw.githubusercontent.com/seleniumbase/SeleniumBase/master/seleniumbase/core/create_db_tables.sql\nsudo mysql -h 127.0.0.1 -uroot -proot test_db < create_db_tables.sql\nsudo mysql -e 'ALTER USER \"root\"@\"localhost\" IDENTIFIED BY \"test\";' -uroot -proot\nsudo service mysql restart\n
Have SeleniumBase tests write to the MySQL DB:
pytest --with-db_reporting\n
Query MySQL DB Results:
mysql -e 'select test_address,browser,state,start_time,runtime from test_db.test_run_data;' -uroot -ptest\n
"}, {"location": "help_docs/mysql_installation/#standard-ubuntu-linux-mysql-setup", "title": "Standard Ubuntu Linux MySQL Setup", "text": "sudo apt update\nsudo apt install mysql-server\nsudo mysql_secure_installation\nsudo mysql -e 'CREATE DATABASE IF NOT EXISTS test_db;'\nsudo mysql -h 127.0.0.1 -u root test_db < seleniumbase/core/create_db_tables.sql\nsudo service mysql restart\n
To change the password from root
to test
:
mysqladmin -u root -p'root' password 'test'\nsudo service mysql restart\n
"}, {"location": "help_docs/mysql_installation/#macos-mysql-setup", "title": "MacOS MySQL Setup", "text": "brew install mysql\n
Then start the MySQL service:
brew services start mysql\n
(Continue with additional steps below to set up your DB.)
"}, {"location": "help_docs/mysql_installation/#windows-mysql-setup", "title": "Windows MySQL Setup", "text": "Download MySQL here Follow the steps from the MySQL Downloads page.
(Continue with additional steps below to set up your DB.)
"}, {"location": "help_docs/mysql_installation/#access-your-mysql-db", "title": "Access your MySQL DB", "text": "If you want a visual tool to help make your MySQL life easier, try MySQL Workbench.
"}, {"location": "help_docs/mysql_installation/#prepare-your-mysql-db", "title": "Prepare your MySQL DB", "text": "Use the create_db_tables.sql file to create the necessary tables for storing test data.
"}, {"location": "help_docs/mysql_installation/#configure-your-mysql-db-for-seleniumbase", "title": "Configure your MySQL DB for SeleniumBase", "text": "Update your settings.py file with your MySQL DB credentials so that tests can write to the database when they run.
"}, {"location": "help_docs/mysql_installation/#have-seleniumbase-tests-write-to-your-mysql-db", "title": "Have SeleniumBase tests write to your MySQL DB", "text": "Add the --with-db_reporting
argument on the command-line when you want tests to write to your MySQL database. Example:
pytest --with-db_reporting\n
"}, {"location": "help_docs/recorder_mode/", "title": "\ud83d\udd34 Recorder Mode", "text": ""}, {"location": "help_docs/recorder_mode/#recorder-mode", "title": "Recorder Mode \ud83d\udd34/\u23fa\ufe0f", "text": "\ud83d\udd34 SeleniumBase Recorder Mode lets you record & export browser actions into test automation scripts.
\u23fa\ufe0f Recorder Mode can be activated from the command-line interface or the Recorder Desktop App.
\u23fa\ufe0f To make a new recording from the command-line interface, use sbase mkrec
, sbase codegen
, or sbase record
:
sbase mkrec TEST_NAME.py --url=URL\n
If the file already exists, you'll get an error. If no URL is provided, you'll start on a blank page and will need to navigate somewhere for the Recorder to activate. (The Recorder captures events on URLs that start with https
, http
, or file
.) The command above runs an empty test that stops at a breakpoint so that you can perform manual browser actions for the Recorder. When you have finished recording, type \"c
\" on the command-line and press [ENTER]
to continue from the breakpoint. The test will complete and a file called TEST_NAME_rec.py
will be automatically created in the ./recordings
folder. That file will get copied back to the original folder with the name you gave it. (You can run with Edge instead of Chrome by adding --edge
to the command above. For headed Linux machines, add --gui
to prevent the default headless mode on Linux.)
Example:
sbase mkrec new_test.py --url=wikipedia.org\n\n* RECORDING initialized: new_test.py\n\npytest new_test.py --rec -q -s --url=wikipedia.org\n\n>>>>>>>>>>>>>>>>>> PDB set_trace >>>>>>>>>>>>>>>>>\n\n> PATH_TO_YOUR_CURRENT_DIRECTORY/new_test.py(9)\n .\n 5 def test_recording(self):\n 6 if self.recorder_ext:\n 7 # When done recording actions,\n 8 # type \"c\", and press [Enter].\n 9 -> import pdb; pdb.set_trace()\n return None\n(Pdb+) c\n\n>>>>>>>>>>>>>>>>>> PDB continue >>>>>>>>>>>>>>>>>>\n\n>>> RECORDING SAVED as: recordings/new_test_rec.py\n**************************************************\n\n*** RECORDING COPIED to: new_test.py\n
\ud83d\udd34 You can also activate Recorder Mode from the Recorder Desktop App:
sbase recorder\n* Starting the SeleniumBase Recorder Desktop App...\n
\u23fa\ufe0f While a recording is in progress, you can press the [ESC]
key to pause the Recorder. To resume the recording, you can hit the [~`]
key, which is located directly below the [ESC]
key on most keyboards.
\u23fa\ufe0f From within Recorder Mode there are two additional modes: \"Assert Element Mode\" and \"Assert Text Mode\". To switch into \"Assert Element Mode\", press the [^]-key (SHIFT+6)
: The border will become purple, and you'll be able to click on elements to assert from your test. To switch into \"Assert Text Mode\", press the [&]-key (SHIFT+7)
: The border will become teal, and you'll be able to click on elements for asserting text from your test.
\u23fa\ufe0f While using either of the two special Assertion Modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without navigating away from the page, etc. To add an assertion for buttons without triggering default \"click\" behavior, mouse-down on the button and then mouse-up somewhere else. (This prevents a detected click while still recording the assert.) To return back to the original Recorder Mode, press any key other than [SHIFT]
or [BACKSPACE]
(Eg: Press [CONTROL]
, etc.). Press [ESC]
once to leave the Assertion Modes, but it'll stop the Recorder if you press it again.
\u23fa\ufe0f For extra flexibility, the sbase mkrec
command can be split into four separate commands:
sbase mkfile TEST_NAME.py --rec\n\npytest TEST_NAME.py --rec -q -s\n\nsbase print ./recordings/TEST_NAME_rec.py -n\n\ncp ./recordings/TEST_NAME_rec.py ./TEST_NAME.py\n
The first command creates a boilerplate test with a breakpoint; the second command runs the test with the Recorder activated; the third command prints the completed test to the console; and the fourth command replaces the initial boilerplate with the completed test. If you're just experimenting with the Recorder, you can run the second command as many times as you want, and it'll override previous recordings saved to ./recordings/TEST_NAME_rec.py
. (Note that -s
is needed to allow breakpoints, unless you already have a pytest.ini
file present with addopts = --capture=no
in it. The -q
is optional, which shortens pytest
console output.)
\u23fa\ufe0f You can also use the Recorder to add code to an existing test. To do that, you'll first need to create a breakpoint in your code to insert manual browser actions:
import pdb; pdb.set_trace()\n
Now you'll be able to run your test with pytest
, and it will stop at the breakpoint for you to add in actions: (Press c
and ENTER
on the command-line to continue from the breakpoint.)
pytest TEST_NAME.py --rec -s\n
\u23fa\ufe0f You can also set a breakpoint at the start of your test by adding --trace
as a pytest
command-line option: (This is useful when running Recorder Mode without any pdb
breakpoints.)
pytest TEST_NAME.py --trace --rec -s\n
\u23fa\ufe0f After the test completes, a file called TEST_NAME_rec.py
will be automatically created in the ./recordings
folder, which will include the actions performed by the test, and the manual actions that you added in.
\u23fa\ufe0f Here's a command-line notification for a completed recording:
>>> RECORDING SAVED as: recordings/TEST_NAME_rec.py\n***************************************************\n
\u23fa\ufe0f When running additional tests from the same Python module, Recordings will get added to the file that was created from the first test:
>>> RECORDING ADDED to: recordings/TEST_NAME_rec.py\n***************************************************\n
\u23fa\ufe0f Recorder Mode works by saving your recorded actions into the browser's sessionStorage. SeleniumBase then reads from the browser's sessionStorage to take the raw data and generate a full test from it. Keep in mind that sessionStorage is only present while the browser tab remains in the same domain/origin. (The sessionStorage of that tab goes away if you leave that domain/origin.) To compensate, links to web pages of different domain/origin will automatically open a new tab for you in Recorder Mode.
\u23fa\ufe0f Additionally, the SeleniumBase self.open(URL)
method will also open a new tab for you in Recorder Mode if the domain/origin is different from the current URL. If you need to navigate to a different domain/origin from within the same tab, call self.save_recorded_actions()
first, which saves the recorded data for later. When a recorded test completes, SeleniumBase scans the sessionStorage data of all open browser tabs for generating the completed script.
\u23fa\ufe0f As an alternative to activating Recorder Mode with the --rec
command-line arg, you can also call self.activate_recorder()
from your tests. Using the Recorder this way is only useful for tests that stay on the same URL. This is because the standard Recorder Mode functions as a Chrome extension and persists wherever the browser goes. (This version only stays on the page where called.)
\u23fa\ufe0f (Note that same domain/origin is not the same as same URL. Example: https://xkcd.com/353 and https://xkcd.com/1537 are two different URLs with the same domain/origin. That means both URLs share the same sessionStorage, and that changes persist to different URLs of the same domain/origin. If you want to find out a website's origin during a test, just call: self.get_origin()
, which returns the value of window.location.origin
from the browser's console.)
\u23fa\ufe0f Inside recorded tests, you might find the self.open_if_not_url(URL)
method, which opens the URL given if the browser is not currently on that page. SeleniumBase uses this method in recorded scripts when the Recorder detects that a browser action changed the current URL. This method prevents an unnecessary page load and shows what page the test visited after a browser action.
\u23fa\ufe0f By launching the Recorder App with sbase recorder --ee
, you can end the recording by pressing {SHIFT
+ESC
} instead of the usual way of ending the recording by typing c
from a breakpoint()
and pressing Enter
. Those buttons don't need to be pressed at the same time, but SHIFT
must be pressed directly before ESC
.
All the code is on GitHub:
"}, {"location": "help_docs/shadow_dom/", "title": "\ud83d\udc64 Shadow DOM Support", "text": ""}, {"location": "help_docs/shadow_dom/#shadow-dom-support-shadow-root-interaction", "title": "Shadow DOM support / Shadow-root interaction", "text": "
\ud83d\udd35 SeleniumBase lets you pierce through open Shadow DOM selectors (to interact with elements inside) by adding ::shadow
to CSS fragments that include a shadow-root element. For multi-layered shadow-roots, you must individually pierce through each shadow-root element that you want to get through.
\ud83d\udd35 Here are some examples of Shadow DOM selectors:
css_1 = \"downloads-manager::shadow #no-downloads\"\n\ncss_2 = \"downloads-manager::shadow #downloadsList downloads-item::shadow #file-link\"\n\ncss_3 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow cr-icon-button\"\n\ncss_4 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow #searchInput\"\n\ncss_5 = \"downloads-manager::shadow downloads-toolbar::shadow cr-toolbar::shadow cr-toolbar-search-field::shadow #clearSearch\"\n
\ud83d\udd35 The shadow-root (::shadow
) elements are transitional, and therefore cannot be the final part of your CSS selectors. Complete your CSS selectors by including an element that's inside a shadow-root.
\ud83d\udd35 NOTE: ::shadow
selectors only exist within SeleniumBase. (They are not part of standard CSS.)
\ud83d\udd35 Here are some examples of tests that interact with Shadow DOM elements: * examples/shadow_root_test.py * examples/test_shadow_dom.py * examples/old_wordle_script.py
"}, {"location": "help_docs/syntax_formats/", "title": "\ud83d\udd21 Syntax Formats", "text": "The 23 Syntax Formats / Design Patterns \ud83d\udd21 SeleniumBase supports multiple ways of structuring tests:In this format, (which is used by most of the tests in the SeleniumBase examples folder), BaseCase
is imported at the top of a Python file, followed by a Python class inheriting BaseCase
. Then, any test method defined in that class automatically gains access to SeleniumBase methods, including the setUp()
and tearDown()
methods that are automatically called for opening and closing web browsers at the start and end of tests.
To run a test of this format, use pytest
or pynose
. Adding BaseCase.main(__name__, __file__)
enables python
to run pytest
on your file indirectly. Here's an example:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass MyTestClass(BaseCase):\n def test_demo_site(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n self.type(\"#myTextInput\", \"This is Automated\")\n self.click(\"#myButton\")\n self.assert_element(\"tbody#tbodyId\")\n self.assert_text(\"Automation Practice\", \"h3\")\n self.click_link(\"SeleniumBase Demo Page\")\n self.assert_exact_text(\"Demo Page\", \"h1\")\n self.assert_no_js_errors()\n
(See examples/test_demo_site.py for the full test.)
Using BaseCase
inheritance is a great starting point for anyone learning SeleniumBase, and it follows good object-oriented programming principles.
There are situations where you may want to customize the setUp
and tearDown
of your tests. Maybe you want to have all your tests login to a specific web site first, or maybe you want to have your tests report results through an API call depending on whether a test passed or failed. This can be done by creating a subclass of BaseCase
and then carefully creating custom setUp()
and tearDown()
methods that don't overwrite the critical functionality of the default SeleniumBase setUp()
and tearDown()
methods. Afterwards, your test classes will inherit the subclass of BaseCase
with the added functionality, rather than directly inheriting BaseCase
itself. Here's an example of that:
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass BaseTestCase(BaseCase):\n def setUp(self):\n super().setUp()\n # <<< Run custom setUp() code for tests AFTER the super().setUp() >>>\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n if self.has_exception():\n # <<< Run custom code if the test failed. >>>\n pass\n else:\n # <<< Run custom code if the test passed. >>>\n pass\n # (Wrap unreliable tearDown() code in a try/except block.)\n # <<< Run custom tearDown() code BEFORE the super().tearDown() >>>\n super().tearDown()\n\n def login(self):\n # <<< Placeholder. Add your code here. >>>\n # Reduce duplicate code in tests by having reusable methods like this.\n # If the UI changes, the fix can be applied in one place.\n pass\n\n def example_method(self):\n # <<< Placeholder. Add your code here. >>>\n pass\n\nclass MyTests(BaseTestCase):\n def test_example(self):\n self.login()\n self.example_method()\n self.type(\"input\", \"Name\")\n self.click(\"form button\")\n # ...\n
(See examples/boilerplates/base_test_case.py for more info.)
3. The \"sb\" pytest fixture (no class)The pytest framework comes with a unique system called fixtures, which replaces import statements at the top of Python files by importing libraries directly into test definitions. More than just being an import, a pytest fixture can also automatically call predefined setUp()
and tearDown()
methods at the beginning and end of test methods. To work, sb
is added as an argument to each test method definition that needs SeleniumBase functionality. This means you no longer need import statements in your Python files to use SeleniumBase. If using other pytest fixtures in your tests, you may need to use the SeleniumBase fixture (instead of BaseCase
class inheritance) for compatibility reasons. Here's an example of the sb
fixture in a test that does not use Python classes:
def test_sb_fixture_with_no_class(sb):\n sb.open(\"seleniumbase.io/help_docs/install/\")\n sb.type('input[aria-label=\"Search\"]', \"GUI Commander\")\n sb.click('mark:contains(\"Commander\")')\n sb.assert_title_contains(\"GUI / Commander\")\n
(See the top of examples/test_sb_fixture.py for the test.)
4. The \"sb\" pytest fixture (in class)The sb
pytest fixture can also be used inside of a class. There is a slight change to the syntax because that means test methods must also include self
in their argument definitions when test methods are defined. (The self
argument represents the class object, and is used in every test method that lives inside of a class.) Once again, no import statements are needed in your Python files for this to work. Here's an example of using the sb
fixture in a test method that lives inside of a Python class:
class Test_SB_Fixture:\n def test_sb_fixture_inside_class(self, sb):\n sb.open(\"seleniumbase.io/help_docs/install/\")\n sb.type('input[aria-label=\"Search\"]', \"GUI Commander\")\n sb.click('mark:contains(\"Commander\")')\n sb.assert_title_contains(\"GUI / Commander\")\n
(See the bottom of examples/test_sb_fixture.py for the test.)
5. Page Object Model with BaseCaseWith SeleniumBase, you can use Page Objects to break out code from tests, but remember, the self
variable (from test methods that inherit BaseCase
) contains the driver and all other framework-specific variable definitions. Therefore, that self
must be passed as an arg into any outside class method in order to call SeleniumBase methods from there. In the example below, the self
variable from the test method is passed into the sb
arg of the Page Object class method because the self
arg of the Page Object class method is already being used for its own class. Every Python class method definition must include the self
as the first arg.
from seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass LoginPage:\n def login_to_swag_labs(self, sb, username):\n sb.open(\"https://www.saucedemo.com\")\n sb.type(\"#user-name\", username)\n sb.type(\"#password\", \"secret_sauce\")\n sb.click('input[type=\"submit\"]')\n\nclass MyTests(BaseCase):\n def test_swag_labs_login(self):\n LoginPage().login_to_swag_labs(self, \"standard_user\")\n self.assert_element(\"div.inventory_list\")\n self.assert_element('div:contains(\"Sauce Labs Backpack\")')\n
(See examples/boilerplates/samples/swag_labs_test.py for the full test.)
6. Page Object Model with the \"sb\" fixtureThis is similar to the classic Page Object Model with BaseCase
inheritance, except that this time we pass the sb
pytest fixture from the test into the sb
arg of the page object class method, (instead of passing self
). Now that you're using sb
as a pytest fixture, you no longer need to import BaseCase
anywhere in your code. See the example below:
class LoginPage:\n def login_to_swag_labs(self, sb, username):\n sb.open(\"https://www.saucedemo.com\")\n sb.type(\"#user-name\", username)\n sb.type(\"#password\", \"secret_sauce\")\n sb.click('input[type=\"submit\"]')\n\nclass MyTests:\n def test_swag_labs_login(self, sb):\n LoginPage().login_to_swag_labs(sb, \"standard_user\")\n sb.assert_element(\"div.inventory_list\")\n sb.assert_element('div:contains(\"Sauce Labs Backpack\")')\n
(See examples/boilerplates/samples/sb_swag_test.py for the full test.)
7. Using \"request\" to get \"sb\" (no class)The pytest request
fixture can be used to retrieve other pytest fixtures from within tests, such as the sb
fixture. This allows you to have more control over when fixtures get initialized because the fixture no longer needs to be loaded at the very beginning of test methods. This is done by calling request.getfixturevalue('sb')
from the test. Here's an example of using the pytest request
fixture to load the sb
fixture in a test method that does not use Python classes:
def test_request_sb_fixture(request):\n sb = request.getfixturevalue('sb')\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.assert_text(\"SeleniumBase\", \"#myForm h2\")\n sb.assert_element(\"input#myTextInput\")\n sb.type(\"#myTextarea\", \"This is me\")\n sb.click(\"#myButton\")\n sb.tearDown()\n
(See the top of examples/test_request_sb_fixture.py for the test.)
8. Using \"request\" to get \"sb\" (in class)The pytest request
fixture can also be used to get the sb
fixture from inside a Python class. Here's an example of that:
class Test_Request_Fixture:\n def test_request_sb_fixture_in_class(self, request):\n sb = request.getfixturevalue('sb')\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.assert_element(\"input#myTextInput\")\n sb.type(\"#myTextarea\", \"Automated\")\n sb.assert_text(\"This Text is Green\", \"#pText\")\n sb.click(\"#myButton\")\n sb.assert_text(\"This Text is Purple\", \"#pText\")\n sb.tearDown()\n
(See the bottom of examples/test_request_sb_fixture.py for the test.)
9. Overriding the driver via BaseCaseWhen you want to use SeleniumBase methods via BaseCase
, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough. Here's an example of that:
from selenium import webdriver\nfrom seleniumbase import BaseCase\nBaseCase.main(__name__, __file__)\n\nclass OverrideDriverTest(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n \"\"\"This method overrides get_new_driver() from BaseCase.\"\"\"\n options = webdriver.ChromeOptions()\n options.add_argument(\"--disable-3d-apis\")\n options.add_argument(\"--disable-notifications\")\n if self.headless:\n options.add_argument(\"--headless=new\")\n options.add_argument(\"--disable-gpu\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\", \"enable-logging\"],\n )\n prefs = {\n \"credentials_enable_service\": False,\n \"profile.password_manager_enabled\": False,\n }\n options.add_experimental_option(\"prefs\", prefs)\n return webdriver.Chrome(options=options)\n\n def test_simple(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n self.assert_text(\"Demo Page\", \"h1\")\n
(From examples/test_override_driver.py)
The above format lets you customize selenium-wire for intercepting and inspecting requests and responses during SeleniumBase tests. Here's how a selenium-wire
integration may look:
from seleniumbase import BaseCase\nfrom seleniumwire import webdriver # Requires \"pip install selenium-wire\"\nBaseCase.main(__name__, __file__)\n\n\nclass WireTestCase(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n options = webdriver.ChromeOptions()\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"]\n )\n options.add_experimental_option(\"useAutomationExtension\", False)\n return webdriver.Chrome(options=options)\n\n def test_simple(self):\n self.open(\"https://seleniumbase.io/demo_page\")\n for request in self.driver.requests:\n print(request.url)\n
(NOTE: The selenium-wire
integration is now included with seleniumbase
: Add --wire
as a pytest
command-line option to activate.)
When you want to use SeleniumBase methods via the sb
pytest fixture, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough.
\"\"\"Overriding the \"sb\" fixture to override the driver.\"\"\"\nimport pytest\n\n@pytest.fixture()\ndef sb(request):\n from selenium import webdriver\n from seleniumbase import BaseCase\n from seleniumbase import config as sb_config\n from seleniumbase.core import session_helper\n\n class BaseClass(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n \"\"\"This method overrides get_new_driver() from BaseCase.\"\"\"\n options = webdriver.ChromeOptions()\n if self.headless:\n options.add_argument(\"--headless=new\")\n options.add_argument(\"--disable-gpu\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"],\n )\n return webdriver.Chrome(options=options)\n\n def setUp(self):\n super().setUp()\n\n def base_method(self):\n pass\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n super().tearDown()\n\n if request.cls:\n if sb_config.reuse_class_session:\n the_class = str(request.cls).split(\".\")[-1].split(\"'\")[0]\n if the_class != sb_config._sb_class:\n session_helper.end_reused_class_session_as_needed()\n sb_config._sb_class = the_class\n request.cls.sb = BaseClass(\"base_method\")\n request.cls.sb.setUp()\n request.cls.sb._needs_tearDown = True\n request.cls.sb._using_sb_fixture = True\n request.cls.sb._using_sb_fixture_class = True\n sb_config._sb_node[request.node.nodeid] = request.cls.sb\n yield request.cls.sb\n if request.cls.sb._needs_tearDown:\n request.cls.sb.tearDown()\n request.cls.sb._needs_tearDown = False\n else:\n sb = BaseClass(\"base_method\")\n sb.setUp()\n sb._needs_tearDown = True\n sb._using_sb_fixture = True\n sb._using_sb_fixture_no_class = True\n sb_config._sb_node[request.node.nodeid] = sb\n yield sb\n if sb._needs_tearDown:\n sb.tearDown()\n sb._needs_tearDown = False\n\ndef test_override_fixture_no_class(sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n\nclass TestOverride:\n def test_override_fixture_inside_class(self, sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n
(From examples/test_override_sb_fixture.py)
Here's how the selenium-wire integration may look when overriding the sb
pytest fixture to override the driver:
import pytest\n\n@pytest.fixture()\ndef sb(request):\n import sys\n from seleniumbase import BaseCase\n from seleniumbase import config as sb_config\n from seleniumwire import webdriver # Requires \"pip install selenium-wire\"\n\n class BaseClass(BaseCase):\n def get_new_driver(self, *args, **kwargs):\n options = webdriver.ChromeOptions()\n if \"linux\" in sys.platform:\n options.add_argument(\"--headless=new\")\n options.add_experimental_option(\n \"excludeSwitches\", [\"enable-automation\"],\n )\n return webdriver.Chrome(options=options)\n\n def setUp(self):\n super().setUp()\n\n def tearDown(self):\n self.save_teardown_screenshot() # On failure or \"--screenshot\"\n super().tearDown()\n\n def base_method(self):\n pass\n\n if request.cls:\n request.cls.sb = BaseClass(\"base_method\")\n request.cls.sb.setUp()\n request.cls.sb._needs_tearDown = True\n request.cls.sb._using_sb_fixture = True\n request.cls.sb._using_sb_fixture_class = True\n sb_config._sb_node[request.node.nodeid] = request.cls.sb\n yield request.cls.sb\n if request.cls.sb._needs_tearDown:\n request.cls.sb.tearDown()\n request.cls.sb._needs_tearDown = False\n else:\n sb = BaseClass(\"base_method\")\n sb.setUp()\n sb._needs_tearDown = True\n sb._using_sb_fixture = True\n sb._using_sb_fixture_no_class = True\n sb_config._sb_node[request.node.nodeid] = sb\n yield sb\n if sb._needs_tearDown:\n sb.tearDown()\n sb._needs_tearDown = False\n\ndef test_wire_with_no_class(sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n for request in sb.driver.requests:\n print(request.url)\n\nclass TestWire:\n def test_wire_inside_class(self, sb):\n sb.open(\"https://seleniumbase.io/demo_page\")\n for request in sb.driver.requests:\n print(request.url)\n
(NOTE: The selenium-wire
integration is now included with seleniumbase
: Add --wire
as a pytest
command-line option to activate. If you need both --wire
with --undetected
modes together, you'll still need to override get_new_driver()
.)
This format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Chinese. Here's an example of that:
from seleniumbase.translate.chinese import \u7852\u6d4b\u8bd5\u7528\u4f8b\n\u7852\u6d4b\u8bd5\u7528\u4f8b.main(__name__, __file__)\n\n\nclass \u6211\u7684\u6d4b\u8bd5\u7c7b(\u7852\u6d4b\u8bd5\u7528\u4f8b):\n def test_\u4f8b\u5b501(self):\n self.\u5f00\u542f(\"https://zh.wikipedia.org/wiki/\")\n self.\u65ad\u8a00\u6807\u9898(\"\u7ef4\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u4e66\")\n self.\u65ad\u8a00\u5143\u7d20('a[title=\"Wikipedia:\u5173\u4e8e\"]')\n self.\u5982\u679c\u53ef\u89c1\u8bf7\u5355\u51fb('button[aria-label=\"\u5173\u95ed\"]')\n self.\u5982\u679c\u53ef\u89c1\u8bf7\u5355\u51fb('button[aria-label=\"\u95dc\u9589\"]')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u521b\u5efa\u8d26\u53f7\")')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u767b\u5f55\")')\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u821e\u9f8d\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u821e\u9f8d\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Chinese_draak.jpg\"]')\n self.\u56de\u53bb()\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u9ebb\u5a46\u8c46\u8150\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u9ebb\u5a46\u8c46\u8150\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('figure:contains(\"\u4e00\u5bb6\u4e2d\u9910\u9928\u7684\u9ebb\u5a46\u8c46\u8150\")')\n self.\u56de\u53bb()\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u7cbe\u6b66\u82f1\u96c4\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Fist_of_legend.jpg\"]')\n self.\u65ad\u8a00\u6587\u672c(\"\u674e\u8fde\u6770\", 'li a[title=\"\u674e\u8fde\u6770\"]')\n
(See examples/translations/chinese_test_1.py for the Chinese test.)
12. BaseCase with Dutch translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Dutch. Here's an example of that:
from seleniumbase.translate.dutch import Testgeval\nTestgeval.main(__name__, __file__)\n\n\nclass MijnTestklasse(Testgeval):\n def test_voorbeeld_1(self):\n self.openen(\"https://nl.wikipedia.org/wiki/Hoofdpagina\")\n self.controleren_element('a[title*=\"Welkom voor nieuwkomers\"]')\n self.controleren_tekst(\"Welkom op Wikipedia\", \"td.hp-welkom\")\n self.typ(\"#searchform input\", \"Stroopwafel\")\n self.klik(\"#searchform button\")\n self.controleren_tekst(\"Stroopwafel\", \"#firstHeading\")\n self.controleren_element('img[src*=\"Stroopwafels\"]')\n self.typ(\"#searchform input\", \"Rijksmuseum Amsterdam\")\n self.klik(\"#searchform button\")\n self.controleren_tekst(\"Rijksmuseum\", \"#firstHeading\")\n self.controleren_element('img[src*=\"Rijksmuseum\"]')\n self.terug()\n self.controleren_url_bevat(\"Stroopwafel\")\n self.vooruit()\n self.controleren_url_bevat(\"Rijksmuseum\")\n
(See examples/translations/dutch_test_1.py for the Dutch test.)
13. BaseCase with French translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into French. Here's an example of that:
from seleniumbase.translate.french import CasDeBase\nCasDeBase.main(__name__, __file__)\n\n\nclass MaClasseDeTest(CasDeBase):\n def test_exemple_1(self):\n self.ouvrir(\"https://fr.wikipedia.org/wiki/\")\n self.v\u00e9rifier_texte(\"Wikip\u00e9dia\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('[alt=\"Wikip\u00e9dia\"]')\n self.cliquer_si_affich\u00e9('button[aria-label=\"Close\"]')\n self.js_taper(\"#searchform input\", \"Cr\u00e8me br\u00fbl\u00e9e\")\n self.cliquer(\"#searchform button\")\n self.v\u00e9rifier_texte(\"Cr\u00e8me br\u00fbl\u00e9e\", \"#firstHeading\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('img[alt*=\"Cr\u00e8me br\u00fbl\u00e9e\"]')\n self.js_taper(\"#searchform input\", \"Jardin des Tuileries\")\n self.cliquer(\"#searchform button\")\n self.v\u00e9rifier_texte(\"Jardin des Tuileries\", \"#firstHeading\")\n self.v\u00e9rifier_\u00e9l\u00e9ment('img[alt*=\"Jardin des Tuileries\"]')\n self.retour()\n self.v\u00e9rifier_url_contient(\"br\u00fbl\u00e9e\")\n self.en_avant()\n self.v\u00e9rifier_url_contient(\"Jardin\")\n
(See examples/translations/french_test_1.py for the French test.)
14. BaseCase with Italian translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Italian. Here's an example of that:
from seleniumbase.translate.italian import CasoDiProva\nCasoDiProva.main(__name__, __file__)\n\n\nclass MiaClasseDiTest(CasoDiProva):\n def test_esempio_1(self):\n self.apri(\"https://it.wikipedia.org/wiki/\")\n self.verificare_testo(\"Wikipedia\")\n self.verificare_elemento('a[title=\"Lingua italiana\"]')\n self.digitare(\"#searchInput\", \"Pizza\")\n self.fare_clic(\"#searchButton\")\n self.verificare_testo(\"Pizza\", \"#firstHeading\")\n self.verificare_elemento('figure img[src*=\"pizza\"]')\n self.digitare(\"#searchInput\", \"Colosseo\")\n self.fare_clic(\"#searchButton\")\n self.verificare_testo(\"Colosseo\", \"#firstHeading\")\n self.verificare_elemento('figure img[src*=\"Colosseo\"]')\n self.indietro()\n self.verificare_url_contiene(\"Pizza\")\n self.avanti()\n self.verificare_url_contiene(\"Colosseo\")\n
(See examples/translations/italian_test_1.py for the Italian test.)
15. BaseCase with Japanese translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Japanese. Here's an example of that:
from seleniumbase.translate.japanese import \u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\n\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9.main(__name__, __file__)\n\n\nclass \u79c1\u306e\u30c6\u30b9\u30c8\u30af\u30e9\u30b9(\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9):\n def test_\u4f8b1(self):\n self.\u3092\u958b\u304f(\"https://ja.wikipedia.org/wiki/\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('[title*=\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\u3078\u3088\u3046\u3053\u305d\"]')\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u30a2\u30cb\u30e1\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a2\u30cb\u30e1\", \"#firstHeading\")\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u5bff\u53f8\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u5bff\u53f8\", \"#firstHeading\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"Various_sushi\"]')\n self.JS\u5165\u529b(\"#searchInput\", \"\u30ec\u30b4\u30e9\u30f3\u30c9\u30fb\u30b8\u30e3\u30d1\u30f3\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"LEGOLAND_JAPAN\"]')\n self.\u30ea\u30f3\u30af\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u540d\u53e4\u5c4b\u57ce\")\n self.\u30ea\u30f3\u30af\u30c6\u30ad\u30b9\u30c8\u3092\u30af\u30ea\u30c3\u30af\u3057\u307e\u3059(\"\u30c6\u30fc\u30de\u30d1\u30fc\u30af\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30c6\u30fc\u30de\u30d1\u30fc\u30af\", \"#firstHeading\")\n
(See examples/translations/japanese_test_1.py for the Japanese test.)
16. BaseCase with Korean translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Korean. Here's an example of that:
from seleniumbase.translate.korean import \uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4\n\uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4.main(__name__, __file__)\n\n\nclass \ud14c\uc2a4\ud2b8_\ud074\ub798\uc2a4(\uc140\ub808\ub284_\ud14c\uc2a4\ud2b8_\ucf00\uc774\uc2a4):\n def test_\uc2e4\uc2dc\uc608_1(self):\n self.\uc5f4\uae30(\"https://ko.wikipedia.org/wiki/\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\uc704\ud0a4\ubc31\uacfc\")\n self.\uc694\uc18c_\ud655\uc778('[title=\"\uc704\ud0a4\ubc31\uacfc:\uc18c\uac1c\"]')\n self.JS_\uc785\ub825(\"#searchform input\", \"\uae40\uce58\")\n self.\ud074\ub9ad(\"#searchform button\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\uae40\uce58\", \"#firstHeading\")\n self.\uc694\uc18c_\ud655\uc778('img[src*=\"Various_kimchi.jpg\"]')\n self.\ub9c1\ud06c_\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ud55c\uad6d \uc694\ub9ac\")\n self.JS_\uc785\ub825(\"#searchform input\", \"\ube44\ube54\ubc25\")\n self.\ud074\ub9ad(\"#searchform button\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ube44\ube54\ubc25\", \"#firstHeading\")\n self.\uc694\uc18c_\ud655\uc778('img[src*=\"Dolsot-bibimbap.jpg\"]')\n self.\ub9c1\ud06c_\ud14d\uc2a4\ud2b8\ub97c_\ud074\ub9ad\ud569\ub2c8\ub2e4(\"\ub3cc\uc1a5\ube44\ube54\ubc25\")\n self.\ud14d\uc2a4\ud2b8_\ud655\uc778(\"\ub3cc\uc1a5\ube44\ube54\ubc25\", \"#firstHeading\")\n
(See examples/translations/korean_test_1.py for the Korean test.)
17. BaseCase with Portuguese translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Portuguese. Here's an example of that:
from seleniumbase.translate.portuguese import CasoDeTeste\nCasoDeTeste.main(__name__, __file__)\n\n\nclass MinhaClasseDeTeste(CasoDeTeste):\n def test_exemplo_1(self):\n self.abrir(\"https://pt.wikipedia.org/wiki/\")\n self.verificar_texto(\"Wikip\u00e9dia\")\n self.verificar_elemento('[title=\"L\u00edngua portuguesa\"]')\n self.digitar(\"#searchform input\", \"Jo\u00e3o Pessoa\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Jo\u00e3o Pessoa\", \"#firstHeading\")\n self.verificar_elemento('img[alt*=\"Jo\u00e3o Pessoa\"]')\n self.digitar(\"#searchform input\", \"Florian\u00f3polis\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Florian\u00f3polis\", \"h1#firstHeading\")\n self.verificar_elemento('td:contains(\"Avenida Beira-Mar\")')\n self.voltar()\n self.verificar_url_cont\u00e9m(\"Jo\u00e3o_Pessoa\")\n self.atualizar_a_p\u00e1gina()\n self.js_digitar(\"#searchform input\", \"Teatro Amazonas\")\n self.clique(\"#searchform button\")\n self.verificar_texto(\"Teatro Amazonas\", \"#firstHeading\")\n self.verificar_texto_do_link(\"Festival Amazonas de \u00d3pera\")\n
(See examples/translations/portuguese_test_1.py for the Portuguese test.)
18. BaseCase with Russian translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Russian. Here's an example of that:
from seleniumbase.translate.russian import \u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d\n\u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d.main(__name__, __file__)\n\n\nclass \u041c\u043e\u0439\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439\u041a\u043b\u0430\u0441\u0441(\u0422\u0435\u0441\u0442\u041d\u0430\u0421\u0435\u043b\u0435\u043d):\n def test_\u043f\u0440\u0438\u043c\u0435\u0440_1(self):\n self.\u043e\u0442\u043a\u0440\u044b\u0442\u044c(\"https://ru.wikipedia.org/wiki/\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('[title=\"\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a\"]')\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u0412\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u044f\", \"div.main-wikimedia-header\")\n self.\u0432\u0432\u0435\u0434\u0438\u0442\u0435(\"#searchInput\", \"\u041c\u0413\u0423\")\n self.\u043d\u0430\u0436\u043c\u0438\u0442\u0435(\"#searchButton\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\", \"#firstHeading\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('img[alt*=\"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0437\u0434\u0430\u043d\u0438\u0435 \u041c\u0413\u0423\"]')\n self.\u0432\u0432\u0435\u0434\u0438\u0442\u0435(\"#searchInput\", \"\u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0428\u0443\u0440\u0438\u043a\u0430\")\n self.\u043d\u0430\u0436\u043c\u0438\u0442\u0435(\"#searchButton\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u0442\u0435\u043a\u0441\u0442(\"\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u00ab\u042b\u00bb \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0428\u0443\u0440\u0438\u043a\u0430\")\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_\u044d\u043b\u0435\u043c\u0435\u043d\u0442('img[alt=\"\u041f\u043e\u0441\u0442\u0435\u0440 \u0444\u0438\u043b\u044c\u043c\u0430\"]')\n self.\u043d\u0430\u0437\u0430\u0434()\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_URL_\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442(\"\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\")\n self.\u0432\u043f\u0435\u0440\u0435\u0434()\n self.\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c_URL_\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442(\"\u0428\u0443\u0440\u0438\u043a\u0430\")\n
(See examples/translations/russian_test_1.py for the Russian test.)
19. BaseCase with Spanish translationsThis format is similar to the English version with BaseCase
inheritance, but there's a different import statement, and method names have been translated into Spanish. Here's an example of that:
from seleniumbase.translate.spanish import CasoDePrueba\nCasoDePrueba.main(__name__, __file__)\n\n\nclass MiClaseDePrueba(CasoDePrueba):\n def test_ejemplo_1(self):\n self.abrir(\"https://es.wikipedia.org/wiki/\")\n self.verificar_texto(\"Wikipedia\")\n self.verificar_elemento('[title=\"Wikipedia:Bienvenidos\"]')\n self.escriba('[name=\"search\"]', \"Parque de Atracciones Tibidabo\")\n self.haga_clic('button:contains(\"Buscar\")')\n self.verificar_texto(\"Tibidabo\", \"#firstHeading\")\n self.verificar_elemento('img[src*=\"Tibidabo\"]')\n self.escriba('input[name=\"search\"]', \"Palma de Mallorca\")\n self.haga_clic('button:contains(\"Buscar\")')\n self.verificar_texto(\"Palma de Mallorca\", \"#firstHeading\")\n self.verificar_elemento('img[src*=\"Palma\"]')\n self.volver()\n self.verificar_url_contiene(\"Tibidabo\")\n self.adelante()\n self.verificar_url_contiene(\"Mallorca\")\n
(See examples/translations/spanish_test_1.py for the Spanish test.)
20. Gherkin syntax with \"behave\" BDD runnerWith Behave's BDD Gherkin format, you can use natural language to write tests that work with SeleniumBase methods. Behave tests are run by calling behave
on the command-line. This requires some special files in a specific directory structure. Here's an example of that structure:
features/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 behave.ini\n\u251c\u2500\u2500 environment.py\n\u251c\u2500\u2500 feature_file.feature\n\u2514\u2500\u2500 steps/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 imported.py\n \u2514\u2500\u2500 step_file.py\n
A *.feature
file might look like this:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert exact text \"Welcome!\" in \"h1\"\n And Highlight \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n When Click link \"Sign out\"\n Then Assert element 'a:contains(\"Sign in\")'\n And Assert text \"You have been signed out!\"\n
(From examples/behave_bdd/features/realworld.feature)
You'll need the environment.py
file for tests to work. Here it is:
from seleniumbase import BaseCase\nfrom seleniumbase.behave import behave_sb\nbehave_sb.set_base_class(BaseCase) # Accepts a BaseCase subclass\nfrom seleniumbase.behave.behave_sb import before_all # noqa\nfrom seleniumbase.behave.behave_sb import before_feature # noqa\nfrom seleniumbase.behave.behave_sb import before_scenario # noqa\nfrom seleniumbase.behave.behave_sb import before_step # noqa\nfrom seleniumbase.behave.behave_sb import after_step # noqa\nfrom seleniumbase.behave.behave_sb import after_scenario # noqa\nfrom seleniumbase.behave.behave_sb import after_feature # noqa\nfrom seleniumbase.behave.behave_sb import after_all # noqa\n
(From examples/behave_bdd/features/environment.py)
Inside that file, you can use BaseCase
(or a subclass) for the inherited class.
For your behave
tests to have access to SeleniumBase Behave steps, you can create an imported.py
file with the following line:
from seleniumbase.behave import steps # noqa\n
That will allow you to use lines like this in your *.feature
files:
Feature: SeleniumBase scenarios for the RealWorld App\n\n Scenario: Verify RealWorld App (log in / sign out)\n Given Open \"seleniumbase.io/realworld/login\"\n And Clear Session Storage\n When Type \"demo_user\" into \"#username\"\n And Type \"secret_pass\" into \"#password\"\n And Do MFA \"GAXG2MTEOR3DMMDG\" into \"#totpcode\"\n Then Assert exact text \"Welcome!\" in \"h1\"\n And Highlight \"img#image1\"\n And Click 'a:contains(\"This Page\")'\n And Save screenshot to logs\n
You can also create your own step files (Eg. step_file.py
):
from behave import step\n\n@step(\"Open the Swag Labs Login Page\")\ndef go_to_swag_labs(context):\n sb = context.sb\n sb.open(\"https://www.saucedemo.com\")\n sb.clear_local_storage()\n\n@step(\"Login to Swag Labs with {user}\")\ndef login_to_swag_labs(context, user):\n sb = context.sb\n sb.type(\"#user-name\", user)\n sb.type(\"#password\", \"secret_sauce\\n\")\n
(For more information, see the SeleniumBase Behave BDD ReadMe.)
21. SeleniumBase SB (Python context manager)This format provides a pure Python way of using SeleniumBase without a test runner. Options can be passed via method instantiation or from the command-line. When setting the test
option to True
(or calling python --test
), then standard test logging will occur, such as screenshots and reports for failing tests. All the usual SeleniumBase options are available, such as customizing the browser settings, etc. Here are some examples:
from seleniumbase import SB\n\nwith SB() as sb:\n sb.open(\"seleniumbase.io/simple/login\")\n sb.type(\"#username\", \"demo_user\")\n sb.type(\"#password\", \"secret_pass\")\n sb.click('a:contains(\"Sign in\")')\n sb.assert_exact_text(\"Welcome!\", \"h1\")\n sb.assert_element(\"img#image1\")\n sb.highlight(\"#image1\")\n sb.click_link(\"Sign out\")\n sb.assert_text(\"signed out\", \"#top_message\")\n
(See examples/raw_sb.py for the test.)
Here's another example, which uses test
mode:
from seleniumbase import SB\n\nwith SB(test=True) as sb:\n sb.open(\"https://google.com/ncr\")\n sb.type('[name=\"q\"]', \"SeleniumBase on GitHub\\n\")\n sb.click('a[href*=\"github.com/seleniumbase\"]')\n sb.highlight(\"div.Layout-main\")\n sb.highlight(\"div.Layout-sidebar\")\n sb.sleep(0.5)\n\nwith SB(test=True, rtf=True, demo=True) as sb:\n sb.open(\"seleniumbase.github.io/demo_page\")\n sb.type(\"#myTextInput\", \"This is Automated\")\n sb.assert_text(\"This is Automated\", \"#myTextInput\")\n sb.assert_text(\"This Text is Green\", \"#pText\")\n sb.click('button:contains(\"Click Me\")')\n sb.assert_text(\"This Text is Purple\", \"#pText\")\n sb.click(\"#checkBox1\")\n sb.assert_element_not_visible(\"div#drop2 img#logo\")\n sb.drag_and_drop(\"img#logo\", \"div#drop2\")\n sb.assert_element(\"div#drop2 img#logo\")\n
(See examples/raw_test_scripts.py for the test.)
22. The driver manager (via context manager)This pure Python format gives you a raw webdriver
instance in a with
block. The SeleniumBase Driver Manager will automatically make sure that your driver is compatible with your browser version. It gives you full access to customize driver options via method args or via the command-line. The driver will automatically call quit()
after the code leaves the with
block. Here are some examples:
\"\"\"DriverContext() example. (Runs with \"python\").\"\"\"\nfrom seleniumbase import DriverContext\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/\")\n driver.highlight('img[alt=\"SeleniumBase\"]', loops=6)\n\nwith DriverContext(browser=\"chrome\", incognito=True) as driver:\n driver.open(\"seleniumbase.io/apps/calculator\")\n driver.click('[id=\"4\"]')\n driver.click('[id=\"2\"]')\n driver.assert_text(\"42\", \"#output\")\n driver.highlight(\"#output\", loops=6)\n\nwith DriverContext() as driver:\n driver.open(\"seleniumbase.io/demo_page\")\n driver.highlight(\"h2\")\n driver.type(\"#myTextInput\", \"Automation\")\n driver.click(\"#checkBox1\")\n driver.highlight(\"img\", loops=6)\n
(See examples/raw_driver_context.py for an example.)
23. The driver manager (via direct import)Another way of running Selenium tests with pure python
(as opposed to using pytest
or pynose
) is by using this format, which bypasses BaseCase methods while still giving you a flexible driver with a manager. SeleniumBase includes helper files such as page_actions.py, which may help you get around some of the limitations of bypassing BaseCase
. Here's an example:
\"\"\"Driver() example. (Runs with \"python\").\"\"\"\nfrom seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/demo_page\")\n driver.highlight(\"h2\")\n driver.type(\"#myTextInput\", \"Automation\")\n driver.click(\"#checkBox1\")\n driver.highlight(\"img\", loops=6)\nfinally:\n driver.quit()\n\ndriver = Driver(browser=\"chrome\", headless=False)\ntry:\n driver.open(\"seleniumbase.io/apps/calculator\")\n driver.click('[id=\"4\"]')\n driver.click('[id=\"2\"]')\n driver.assert_text(\"42\", \"#output\")\n driver.highlight(\"#output\", loops=6)\nfinally:\n driver.quit()\n
(From examples/raw_driver_manager.py)
Here's how the selenium-wire integration may look when using the Driver()
format:
from seleniumbase import Driver\n\ndriver = Driver(wire=True, headless=True)\ntry:\n driver.get(\"https://wikipedia.org\")\n for request in driver.requests:\n print(request.url)\nfinally:\n driver.quit()\n
Here's another selenium-wire
example with the Driver()
format:
from seleniumbase import Driver\n\ndef intercept_response(request, response):\n print(request.headers)\n\ndriver = Driver(wire=True)\ntry:\n driver.response_interceptor = intercept_response\n driver.get(\"https://wikipedia.org\")\nfinally:\n driver.quit()\n
Here's an example of basic login with the Driver()
format:
from seleniumbase import Driver\n\ndriver = Driver()\ntry:\n driver.open(\"seleniumbase.io/simple/login\")\n driver.type(\"#username\", \"demo_user\")\n driver.type(\"#password\", \"secret_pass\")\n driver.click('a:contains(\"Sign in\")')\n driver.assert_exact_text(\"Welcome!\", \"h1\")\n driver.assert_element(\"img#image1\")\n driver.highlight(\"#image1\")\n driver.click_link(\"Sign out\")\n driver.assert_text(\"signed out\", \"#top_message\")\nfinally:\n driver.quit()\n
(From examples/raw_login_driver.py)
The Driver()
manager format can be used as a drop-in replacement for virtually every Python/selenium framework, as it uses the raw driver
instance for handling commands. The Driver()
method simplifies the work of managing drivers with optimal settings, and it can be configured with multiple args. The Driver()
also accepts command-line options (such as python --headless
) so that you don't need to modify your tests directly to use different settings. These command-line options only take effect if the associated method args remain unset (or set to None
) for the specified options.
When using the Driver()
format, you may need to activate a Virtual Display on your own if you want to run headed tests in a headless Linux environment. (See https://github.com/mdmintz/sbVirtualDisplay for details.) One such example of this is using an authenticated proxy, which is configured via a Chrome extension that is generated at runtime. (Note that regular headless mode in Chrome doesn't support extensions.)
SeleniumBase Playlist on YouTube:
SeleniumBase GitHub Repo Link:
SeleniumBase Gitter Chat Link:
Other Social Media Links:
"}, {"location": "help_docs/translations/", "title": "\ud83c\udf0f Translations", "text": ""}, {"location": "help_docs/translations/#translated-tests", "title": "\ud83c\udf0f Translated Tests \ud83c\ude3a Translation API \ud83c\ude3a", "text": "SeleniumBase supports the following 10 languages: English, Chinese, Dutch, French, Italian, Japanese, Korean, Portuguese, Russian, and Spanish. (Examples can be found in SeleniumBase/examples/translations)
Multi-language tests run with pytest like other tests. Test methods have a one-to-one mapping to supported languages. Here's an example of a translated test:
# Chinese Translation\nfrom seleniumbase.translate.chinese import \u7852\u6d4b\u8bd5\u7528\u4f8b\n\nclass \u6211\u7684\u6d4b\u8bd5\u7c7b(\u7852\u6d4b\u8bd5\u7528\u4f8b):\n def test_\u4f8b\u5b501(self):\n self.\u5f00\u542f(\"https://zh.wikipedia.org/wiki/\")\n self.\u65ad\u8a00\u6807\u9898(\"\u7ef4\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u4e66\")\n self.\u65ad\u8a00\u5143\u7d20('a[title=\"Wikipedia:\u5173\u4e8e\"]')\n self.\u5982\u679c\u53ef\u89c1\u8bf7\u5355\u51fb('button[aria-label=\"\u5173\u95ed\"]')\n self.\u5982\u679c\u53ef\u89c1\u8bf7\u5355\u51fb('button[aria-label=\"\u95dc\u9589\"]')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u521b\u5efa\u8d26\u53f7\")')\n self.\u65ad\u8a00\u5143\u7d20('span:contains(\"\u767b\u5f55\")')\n self.\u8f93\u5165\u6587\u672c('input[name=\"search\"]', \"\u821e\u9f8d\")\n self.\u5355\u51fb('button:contains(\"\u641c\u7d22\")')\n self.\u65ad\u8a00\u6587\u672c(\"\u821e\u9f8d\", \"#firstHeading\")\n self.\u65ad\u8a00\u5143\u7d20('img[src*=\"Chinese_draak.jpg\"]')\n
Here's another example:
# Japanese Translation\nfrom seleniumbase.translate.japanese import \u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\n\nclass \u79c1\u306e\u30c6\u30b9\u30c8\u30af\u30e9\u30b9(\u30bb\u30ec\u30cb\u30a6\u30e0\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9):\n def test_\u4f8b1(self):\n self.\u3092\u958b\u304f(\"https://ja.wikipedia.org/wiki/\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('[title*=\"\u30a6\u30a3\u30ad\u30da\u30c7\u30a3\u30a2\u3078\u3088\u3046\u3053\u305d\"]')\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u30a2\u30cb\u30e1\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u30a2\u30cb\u30e1\", \"#firstHeading\")\n self.JS\u5165\u529b('input[name=\"search\"]', \"\u5bff\u53f8\")\n self.\u30af\u30ea\u30c3\u30af\u3057\u3066(\"#searchform button\")\n self.\u30c6\u30ad\u30b9\u30c8\u3092\u78ba\u8a8d\u3059\u308b(\"\u5bff\u53f8\", \"#firstHeading\")\n self.\u8981\u7d20\u3092\u78ba\u8a8d\u3059\u308b('img[src*=\"Various_sushi\"]')\n
You can use SeleniumBase to selectively translate the method names of any test from one language to another with the console scripts interface. Additionally, the import
line at the top of the Python file will change to import the new BaseCase
. Example: BaseCase
becomes CasoDeTeste
when a test is translated into Portuguese.
seleniumbase translate\n
* Usage:\nseleniumbase translate [SB_FILE.py] [LANGUAGE] [ACTION]\n\n* Languages:\n``--en`` / ``--English`` | ``--zh`` / ``--Chinese``\n``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``\n``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``\n``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``\n``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``\n\n* Actions:\n``-p`` / ``--print`` (Print translation output to the screen)\n``-o`` / ``--overwrite`` (Overwrite the file being translated)\n``-c`` / ``--copy`` (Copy the translation to a new ``.py`` file)\n\n* Options:\n``-n`` (include line Numbers when using the Print action)\n\n* Examples:\nTranslate test_1.py into Chinese and only print the output:\n>>> seleniumbase translate test_1.py --zh -p\nTranslate test_2.py into Portuguese and overwrite the file:\n>>> seleniumbase translate test_2.py --pt -o\nTranslate test_3.py into Dutch and make a copy of the file:\n>>> seleniumbase translate test_3.py --nl -c\n\n* Output:\nTranslates a SeleniumBase Python file into the language\nspecified. Method calls and ``import`` lines get swapped.\nBoth a language and an action must be specified.\nThe ``-p`` action can be paired with one other action.\nWhen running with ``-c`` (or ``--copy``) the new file name\nwill be the original name appended with an underscore\nplus the 2-letter language code of the new language.\n(Example: Translating ``test_1.py`` into Japanese with\n``-c`` will create a new file called ``test_1_ja.py``.)\n
"}, {"location": "help_docs/uc_mode/", "title": "\ud83d\udc64 UC Mode", "text": ""}, {"location": "help_docs/uc_mode/#uc-mode", "title": "UC Mode \ud83d\udc64", "text": "\ud83d\udc64 SeleniumBase UC Mode (Undetected-Chromedriver Mode) allows bots to appear human, which lets them evade detection from anti-bot services that try to block them or trigger CAPTCHAs on various websites.
(Watch the 1st UC Mode tutorial on YouTube! \u25b6\ufe0f)
(Watch the 2nd UC Mode tutorial on YouTube! \u25b6\ufe0f)
\ud83d\udc64 UC Mode is based on undetected-chromedriver, but includes multiple updates, fixes, and improvements, such as:
uc_*()
methods.\ud83d\udc64 Here's a simple example with the Driver
manager:
from seleniumbase import Driver\n\ndriver = Driver(uc=True)\nurl = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, 4)\ndriver.quit()\n
\ud83d\udc64 Here's an example with the SB
manager (which has more methods and functionality than the Driver
format):
from seleniumbase import SB\n\nwith SB(uc=True) as sb:\n url = \"https://gitlab.com/users/sign_in\"\n sb.uc_open_with_reconnect(url, 4)\n
\ud83d\udc64 Here's a longer example, which includes a special click if the CAPTCHA isn't bypassed on the initial page load:
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://gitlab.com/users/sign_in\"\n sb.uc_open_with_reconnect(url, 4)\n sb.uc_gui_click_captcha()\n sb.assert_text(\"Username\", '[for=\"user_login\"]', timeout=3)\n sb.assert_element('label[for=\"user_login\"]')\n sb.highlight('button:contains(\"Sign in\")')\n sb.highlight('h1:contains(\"GitLab.com\")')\n sb.post_message(\"SeleniumBase wasn't detected\", duration=4)\n
\ud83d\udc64 Here's an example where clicking the checkbox is required, even for humans:(Commonly seen on forms that are CAPTCHA-protected.)
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://seleniumbase.io/apps/turnstile\"\n sb.uc_open_with_reconnect(url, reconnect_time=2)\n sb.uc_gui_handle_cf()\n sb.assert_element(\"img#captcha-success\", timeout=3)\n sb.set_messenger_theme(location=\"top_left\")\n sb.post_message(\"SeleniumBase wasn't detected\", duration=3)\n
If running on a Linux server, uc_gui_handle_cf()
might not be good enough. Switch to uc_gui_click_cf()
to be more stealthy. You can also use uc_gui_click_captcha()
as a generic CAPTCHA-clicker, which auto-detects between CF Turnstile and Google reCAPTCHA.
\ud83d\udc64 Here's an example where the CAPTCHA appears after submitting a form:
from seleniumbase import SB\n\nwith SB(uc=True, test=True, incognito=True, locale_code=\"en\") as sb:\n url = \"https://ahrefs.com/website-authority-checker\"\n input_field = 'input[placeholder=\"Enter domain\"]'\n submit_button = 'span:contains(\"Check Authority\")'\n sb.uc_open_with_reconnect(url, 2) # The bot-check is later\n sb.type(input_field, \"github.com/seleniumbase/SeleniumBase\")\n sb.reconnect(0.1)\n sb.uc_click(submit_button, reconnect_time=4)\n sb.uc_gui_click_captcha()\n sb.wait_for_text_not_visible(\"Checking\", timeout=10)\n sb.highlight('p:contains(\"github.com/seleniumbase/SeleniumBase\")')\n sb.highlight('a:contains(\"Top 100 backlinks\")')\n sb.set_messenger_theme(location=\"bottom_center\")\n sb.post_message(\"SeleniumBase wasn't detected!\")\n
\ud83d\udc64 Here, the CAPTCHA appears after clicking to go to the sign-in screen:
from seleniumbase import SB\n\nwith SB(uc=True, test=True, ad_block=True) as sb:\n url = \"https://www.thaiticketmajor.com/concert/\"\n sb.uc_open_with_reconnect(url, 6.111)\n sb.uc_click(\"button.btn-signin\", 4.1)\n sb.uc_gui_click_captcha()\n
\ud83d\udc64 On Linux, use sb.uc_gui_click_cf()
to handle Cloudflare Turnstiles:
from seleniumbase import SB\n\nwith SB(uc=True, test=True) as sb:\n url = \"https://www.virtualmanager.com/en/login\"\n sb.uc_open_with_reconnect(url, 4)\n print(sb.get_page_title())\n sb.uc_gui_click_cf() # Ready if needed!\n print(sb.get_page_title())\n sb.assert_element('input[name*=\"email\"]')\n sb.assert_element('input[name*=\"login\"]')\n sb.set_messenger_theme(location=\"bottom_center\")\n sb.post_message(\"SeleniumBase wasn't detected!\")\n
The 2nd print()
should output \"Virtual Manager\", which means that the automation successfully passed the Turnstile.
\ud83d\udc64 In UC Mode, driver.get(url)
has been modified from its original version: If anti-bot services are detected from a requests.get(url)
call that's made before navigating to the website, then driver.uc_open_with_reconnect(url)
will be used instead. To open a URL normally in UC Mode, use driver.default_get(url)
.
driver
-specific methods added by SeleniumBase for UC Mode: --uc
/ uc=True
", "text": "driver.uc_open(url)\n\ndriver.uc_open_with_tab(url)\n\ndriver.uc_open_with_reconnect(url, reconnect_time=None)\n\ndriver.uc_open_with_disconnect(url, timeout=None)\n\ndriver.reconnect(timeout)\n\ndriver.disconnect()\n\ndriver.connect()\n\ndriver.uc_click(\n selector, by=\"css selector\",\n timeout=settings.SMALL_TIMEOUT, reconnect_time=None)\n\ndriver.uc_gui_press_key(key)\n\ndriver.uc_gui_press_keys(keys)\n\ndriver.uc_gui_write(text)\n\ndriver.uc_gui_click_x_y(x, y, timeframe=0.25)\n\ndriver.uc_gui_click_captcha(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False)\n\ndriver.uc_gui_handle_cf(frame=\"iframe\")\n\ndriver.uc_switch_to_frame(frame, reconnect_time=None)\n
(Note that the reconnect_time
is used to specify how long the driver should be disconnected from Chrome to prevent detection before reconnecting again.)
\ud83d\udc64 Since driver.get(url)
is slower in UC Mode for bypassing detection, use driver.default_get(url)
for a standard page load instead:
driver.default_get(url) # Faster, but Selenium can be detected\n
\ud83d\udc64 Here are some examples of using those special UC Mode methods: (Use self.driver
for BaseCase
formats. Use sb.driver
for SB()
formats):
url = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, reconnect_time=3)\ndriver.uc_open_with_reconnect(url, 3)\n\ndriver.reconnect(5)\ndriver.reconnect(timeout=5)\n
\ud83d\udc64 You can also set the reconnect_time
/ timeout
to \"breakpoint\"
as a valid option. This allows the user to perform manual actions (until typing c
and pressing ENTER
to continue from the breakpoint):
url = \"https://gitlab.com/users/sign_in\"\ndriver.uc_open_with_reconnect(url, reconnect_time=\"breakpoint\")\ndriver.uc_open_with_reconnect(url, \"breakpoint\")\n\ndriver.reconnect(timeout=\"breakpoint\")\ndriver.reconnect(\"breakpoint\")\n
(Note that while the special UC Mode
breakpoint is active, you can't use Selenium
commands in the browser, and the browser can't detect Selenium
.)
\ud83d\udc64 On Linux, you may need to use driver.uc_gui_click_cf()
to successfully bypass a Cloudflare CAPTCHA. If there's more than one Cloudflare iframe on that website, then put the CSS Selector of an element that's above the iframe as the first arg to driver.uc_gui_click_cf()
. This method uses pyautogui
. In order for pyautogui
to focus on the correct element, use xvfb=True
/ --xvfb
to activate a special virtual display on Linux.
\ud83d\udc64 driver.uc_gui_click_cf(frame=\"iframe\", retry=False, blind=False)
has three args. (All optional). The first one, frame
, lets you specify the iframe in case the CAPTCHA is not located in the first iframe on the page. The second one, retry
, lets you retry the click after reloading the page if the first one didn't work (and a CAPTCHA is still present after the page reload). The third arg, blind
, will retry after a page reload (if the first click failed) by clicking at the last known coordinates of the CAPTCHA checkbox without confirming first with Selenium that a CAPTCHA is still on the page.
\ud83d\udc64 driver.uc_gui_click_rc(frame=\"iframe\", retry=False, blind=False)
is for reCAPTCHA. This may only work a few times before not working anymore... not because Selenium was detected, but because reCAPTCHA uses advanced AI to detect unusual activity, unlike the CF Turnstile, which only uses basic detection.
\ud83d\udc64 driver.uc_gui_click_captcha()
auto-detects the CAPTCHA type before trying to click it. This is a generic method for both CF Turnstile and Google reCAPTCHA. It will use the code from uc_gui_click_cf()
and uc_gui_click_rc()
as needed.
\ud83d\udc64 To find out if UC Mode will work at all on a specific site (before adjusting for timing), load your site with the following script:
from seleniumbase import SB\n\nwith SB(uc=True) as sb:\n sb.driver.uc_open_with_reconnect(URL, reconnect_time=\"breakpoint\")\n
(If you remain undetected while loading the page and performing manual actions, then you know you can create a working script once you swap the breakpoint with a time and add special methods like driver.uc_click
as needed.)
\ud83d\udc64 Multithreaded UC Mode:
If you're using pytest
for multithreaded UC Mode (which requires using one of the pytest
syntax formats), then all you have to do is set the number of threads when your script runs. (-n NUM
) Eg:
pytest --uc -n 4\n
(Then pytest-xdist
is automatically used to spin up and process the threads.)
If you don't want to use pytest
for multithreading, then you'll need to do a little more work. That involves using a different multithreading library, (eg. concurrent.futures
), and making sure that thread-locking is done correctly for processes that share resources. To handle that thread-locking, include sys.argv.append(\"-n\")
in your SeleniumBase file.
Here's a sample script that uses concurrent.futures
for spinning up multiple processes:
import sys\nfrom concurrent.futures import ThreadPoolExecutor\nfrom seleniumbase import Driver\nsys.argv.append(\"-n\") # Tell SeleniumBase to do thread-locking as needed\n\ndef launch_driver(url):\n driver = Driver(uc=True)\n try:\n driver.get(url=url)\n driver.sleep(2)\n finally:\n driver.quit()\n\nurls = ['https://seleniumbase.io/demo_page' for i in range(3)]\nwith ThreadPoolExecutor(max_workers=len(urls)) as executor:\n for url in urls:\n executor.submit(launch_driver, url)\n
\ud83d\udc64 What makes UC Mode work?
Here are the 3 primary things that UC Mode does to make bots appear human:
chromedriver
to rename Chrome DevTools Console variables.chromedriver
to them.chromedriver
from Chrome during stealthy actions.For example, if the Chrome DevTools Console variables aren't renamed, you can expect to find them easily when using selenium
for browser automation:
(If those variables are still there, then websites can easily detect your bots.)
If you launch Chrome using chromedriver
, then there will be settings that make your browser look like a bot. (Instead, UC Mode connects chromedriver
to Chrome after the browser is launched, which makes Chrome look like a normal, human-controlled web browser.)
While chromedriver
is connected to Chrome, website services can detect it. Thankfully, raw selenium
already includes driver.service.stop()
for stopping the chromedriver
service, driver.service.start()
for starting the chromedriver
service, and driver.start_session(capabilities)
for reviving the active browser session with the given capabilities. (SeleniumBase
UC Mode methods automatically use those raw selenium
methods as needed.)
Links to those raw Selenium method definitions have been provided for reference (but you don't need to call those methods directly):
driver.service.stop()
driver.service.start()
driver.start_session(capabilities)
Also note that chromedriver
isn't detectable in a browser tab if it never touches that tab. Here's a JS command that lets you open a URL in a new tab (from your current tab):
window.open(\"URL\");
--> (Info: W3Schools)The above JS method is used within SeleniumBase
UC Mode methods for opening URLs in a stealthy way. Since some websites try to detect if your browser is a bot on the initial page load, this allows you to bypass detection in those situations. After a few seconds (customizable), UC Mode tells chromedriver
to connect to that tab so that automated commands can now be issued. At that point, chromedriver
could be detected if websites are looking for it (but generally websites only look for it during specific events, such as page loads, form submissions, and button clicks).
Avoiding detection while clicking is easy if you schedule your clicks to happen at a future point when the chromedriver
service has been stopped. Here's a JS command that lets you schedule events (such as clicks) to happen in the future:
window.setTimeout(function() { SCRIPT }, MS);
--> (Info: W3Schools)The above JS method is used within the SeleniumBase
UC Mode method: driver.uc_click(selector)
so that clicking can be done in a stealthy way. UC Mode schedules your click, disconnects chromedriver
from Chrome, waits a little (customizable), and reconnects.
\ud83d\udee0\ufe0f Troubleshooting UC Mode
On Windows, the uc_gui_click_cf()
and uc_gui_click_captcha()
methods require \"Scaling\" to be set at \"100%\". (Note that \"100%\" may be different from the system's \"Recommended\" percent, which can be higher depending on your screen resolution and monitor size.)
As an alternative to using the uc_gui_click_cf()
or uc_gui_click_captcha()
methods on Windows, you can use sb.uc_gui_handle_cf()
, which does not require \"Scaling\" to be set to a specific value. Instead of using the mouse to click a CAPTCHA, sb.uc_gui_handle_cf()
uses a combination of the TAB
key and the SPACEBAR
.
\ud83c\udfc6 Choosing the right CAPTCHA service for your business / website:
As an ethical hacker / cybersecurity researcher who builds bots that bypass CAPTCHAs for sport, the CAPTCHA service that I personally recommend for keeping bots out is Google's reCAPTCHA:
Since Google makes Chrome, Google's own reCAPTCHA service has access to more data than other CAPTCHA services (eg. hCaptcha, CloudFlare, DataDome, etc.), and can therefore use that data to make better decisions about whether or not web activity is coming from real humans or automated bots.
\u2696\ufe0f Legal implications of web-scraping:
Based on the following article, https://nubela.co/blog/meta-lost-the-scraping-legal-battle-to-bright-data/, (which outlines a court case where social-networking company: Meta lost the legal battle to data-scraping company: Bright Data), it was determined that web scraping is 100% legal in the eyes of the courts as long as: 1. The scraping is only done with public data and not private data. 2. The scraping isn\u2019t done while logged in on the site being scraped.
If the above criteria are met, then scrape away! (According to the article)
(Note: I'm not a lawyer, so I can't officially offer legal advice, but I can direct people to existing articles online where people can find their own answers.)
"}, {"location": "help_docs/useful_grep_commands/", "title": "\ud83d\udcdc Useful grep commands", "text": ""}, {"location": "help_docs/useful_grep_commands/#useful-grep-commands", "title": "Useful grep commands", "text": "There are several useful grep commands for helping you find and/or replace text in multiple files. Examples:
"}, {"location": "help_docs/useful_grep_commands/#list-all-files-containing-selfget_new_driver-ignoring-pyc-files-from-the-current-directory", "title": "List all files containingself.get_new_driver(
, ignoring \".pyc\" files, from the current directory", "text": "grep -rl \"self.get_new_driver(\" * --exclude=\\*.pyc
OR grep -rl * -e \"self.get_new_driver(\" --exclude=\\*.pyc
To only search .py
files, use --include=\\*.py
:
grep -rl \"self.get_new_driver(\" * --include=\\*.py
sed -i 's/foo_abc/bar_xyz/g' *.py
sed -i '' 's/foo_abc/bar_xyz/g' *.py
ps
with grep
):", "text": "ps -ef |grep chromedriver
(NOTE: Safari's WebDriver requires macOS 10.13 \"High Sierra\" or later.)
You can find the official Apple documentation regarding \"Testing with WebDriver in Safari\" on the following page: https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari
Run safaridriver --enable
once in a terminal to enable Safari's WebDriver. (If you\u2019re upgrading from a previous macOS release, you may need to prefix the command with sudo
.)
Now you can use --safari
to run your SeleniumBase tests on Safari.
There are multiple ways of creating a Python virtual environment. This tutorial covers two of those:
venv
command (included with Python 3+).mkvirtualenv
command.venv
creates virtual environments in the location where run (generally with Python projects).
mkvirtualenv
creates virtual environments in one place (generally in your home directory).
(The Python Software Foundation recommends venv
for creating virtual environments.)
macOS/Linux terminal (python3 -m venv ENV
)
python3 -m venv sbase_env\nsource sbase_env/bin/activate\n
Windows CMD prompt (py -m venv ENV
):
py -m venv sbase_env\ncall sbase_env\\\\Scripts\\\\activate\n
To exit a virtual env, type deactivate
.
macOS/Linux terminal:
python3 -m pip install virtualenvwrapper --force-reinstall\nexport WORKON_HOME=$HOME/.virtualenvs\nsource `which virtualenvwrapper.sh`\n
(Shortcut: Run source virtualenv_install.sh
from the top-level SeleniumBase folder to perform the above steps.)
(If you add source `which virtualenvwrapper.sh`
to your local bash file (~/.bash_profile
on macOS, or ~/.bashrc
on Linux), virtualenvwrapper commands such as mkvirtualenv
will be available whenever you open a new command prompt.)
Windows CMD prompt:
py -m pip install virtualenvwrapper-win --force-reinstall --user\n
(Shortcut: Run win_virtualenv.bat
from the top-level SeleniumBase folder to perform the above step.)
mkvirtualenv ENV
:mkvirtualenv sbase_env\n
(If you have multiple versions of Python installed on your machine, and you want your virtual environment to use a specific Python version, add --python=PATH_TO_PYTHON_EXE
to your mkvirtualenv
command with the Python executable to use.)
Creating a virtual environment:
mkvirtualenv sbase_env\n
Leaving your virtual environment:
deactivate\n
Returning to a virtual environment:
workon sbase_env\n
Listing all virtual environments:
workon\n
Deleting a virtual environment:
rmvirtualenv sbase_env\n
If the python
and python3
versions don't match (while in a virtualenv on macOS or Linux), the following command will sync the versions:
alias python=python3\n
(To remove an alias, use: unalias NAME
)
To verify the python
version, use:
python --version\n
To see the PATH of your python
(macOS/Linux), use:
which python\n
python-guide.org/en/latest/dev/virtualenvs has more information about Python virtual environments. For specific details about VirtualEnv and VirtualEnvWrapper, see http://virtualenv.readthedocs.org/en/latest/ and http://virtualenvwrapper.readthedocs.org/en/latest/.
"}, {"location": "integrations/azure/azure_pipelines/ReadMe/", "title": "\ud83e\udd16 Azure Pipelines", "text": ""}, {"location": "integrations/azure/azure_pipelines/ReadMe/#running-browser-based-test-automation-with-azure-pipelines-by-using-seleniumbase", "title": "Running browser-based test automation with Azure Pipelines by using SeleniumBase", "text": ""}, {"location": "integrations/azure/azure_pipelines/ReadMe/#step-0-fork-the-seleniumbase-repo-on-github-to-get-started-quickly", "title": "Step 0. Fork the SeleniumBase repo on GitHub to get started quickly.", "text": "Navigate to https://azure.microsoft.com/en-us/services/devops/?nav=min
Follow the steps...
https://dev.azure.com/seleniumbase/seleniumbase/_build/results?buildId=234
"}, {"location": "integrations/azure/azure_pipelines/ReadMe/#every-time-you-create-a-pull-request-now-azure-pipelines-will-run-your-tests-automatically", "title": "Every time you create a pull request now, Azure Pipelines will run your tests automatically.", "text": "To learn more, study SeleniumBase and see how the azure-pipelines.yml file works.
"}, {"location": "integrations/azure/jenkins/ReadMe/", "title": "\ud83e\udd16 Jenkins on Azure", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#building-a-browser-based-test-automation-server-with-jenkins-on-azure-by-using-seleniumbase", "title": "Building a browser-based test automation server with Jenkins on Azure by using SeleniumBase", "text": "(2022 NOTE: Steps from this 2019 tutorial from Boston Code Camp are now out-of-date. For installing Jenkins from the Azure Marketplace, you can try using Bitnami Jenkins. Or, for the newer official Microsoft tutorial, see Get Started: Install Jenkins on an Azure Linux VM, and then continue with Step 4 below to resume SeleniumBase setup after you've created your Jenkins instance.)
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-0-fork-the-seleniumbase-repo-on-github-to-get-started-quickly", "title": "Step 0. Fork the SeleniumBase repo on GitHub to get started quickly.", "text": "Jenkins (Publisher: Microsoft)
result to get to the Jenkins Start page.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-2-launch-a-jenkins-instance", "title": "Step 2. Launch a Jenkins instance", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#click-create-and-follow-the-steps", "title": "Click \"Create\" and follow the steps...", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#continue-to-additional-settings-when-youre-done-with-basics", "title": "Continue to \"Additional Settings\" when you're done with \"Basics\".", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#on-the-additional-settings-section-set-the-size-to-b2s", "title": "On the \"Additional Settings\" section, set the Size to \"B2s\":", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-youve-reached-step-5-click-create-to-complete-the-setup", "title": "Once you've reached Step 5, click \"Create\" to complete the setup.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-3-inspect-your-new-jenkins-instance-to-ssh-into-the-new-machine", "title": "Step 3. Inspect your new Jenkins instance to SSH into the new machine", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-your-new-jenkins-instance-has-finished-launching-you-should-be-able-to-see-the-main-page", "title": "Once your new Jenkins instance has finished launching, you should be able to see the main page", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#on-the-main-page-you-should-be-able-to-find-the-public-ip-address", "title": "On the main page, you should be able to find the Public IP Address.", "text": "ssh USERNAME@IP_ADDRESS\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-4-clone-the-seleniumbase-repository-from-the-root-directory", "title": "Step 4. Clone the SeleniumBase repository from the root (\"/\") directory.", "text": "cd /\nsudo git clone https://github.com/seleniumbase/SeleniumBase.git\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-5-enter-the-linux-folder", "title": "Step 5. Enter the \"linux\" folder", "text": "cd SeleniumBase/integrations/linux/\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-6-give-the-jenkins-user-sudo-access-see-jenkins_permissionssh-for-details", "title": "Step 6. Give the \"jenkins\" user sudo access (See jenkins_permissions.sh for details)", "text": "./jenkins_permissions.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-7-become-the-jenkins-user-and-enter-a-bash-shell", "title": "Step 7. Become the \"jenkins\" user and enter a \"bash\" shell", "text": "sudo su jenkins\nbash\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-8-install-dependencies-see-linuxfilesh-for-details", "title": "Step 8. Install dependencies (See Linuxfile.sh for details)", "text": "./Linuxfile.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-9-start-up-the-headless-browser-display-mechanism-xvfb-see-xvfb_launchersh-for-details", "title": "Step 9. Start up the headless browser display mechanism: Xvfb (See Xvfb_launcher.sh for details)", "text": "./Xvfb_launcher.sh\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-10-go-to-the-seleniumbase-directory", "title": "Step 10. Go to the SeleniumBase directory", "text": "cd /SeleniumBase\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-11-install-the-requirements-for-seleniumbase", "title": "Step 11. Install the requirements for SeleniumBase", "text": "sudo pip install -r requirements.txt --upgrade\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-12-install-seleniumbase-make-sure-you-already-installed-the-requirements-above", "title": "Step 12. Install SeleniumBase (Make sure you already installed the requirements above)", "text": "sudo python setup.py develop\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-13-install-chromedriver", "title": "Step 13. Install chromedriver", "text": "sudo seleniumbase install chromedriver\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-14-run-an-example-test-in-chrome-to-verify-installation-may-take-up-to-10-seconds", "title": "Step 14. Run an example test in Chrome to verify installation (May take up to 10 seconds)", "text": "pytest examples/my_first_test.py --headless --browser=chrome\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-15-secure-your-jenkins-machine", "title": "Step 15. Secure your Jenkins machine", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#navigate-to-httpjenkins_ip_addressjenkins-on-azure", "title": "Navigate to http://JENKINS_IP_ADDRESS/jenkins-on-azure/", "text": "(Depending on your version of Jenkins, you may see the following screen, or nothing at all.)
"}, {"location": "integrations/azure/jenkins/ReadMe/#initially-jenkins-uses-only-http-which-makes-it-less-secure", "title": "Initially, Jenkins uses onlyhttp
, which makes it less secure.", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#youll-need-to-set-up-ssh-port-forwarding-in-order-to-secure-it", "title": "You'll need to set up SSH Port Forwarding in order to secure it.", "text": "ssh -L 127.0.0.1:8080:localhost:8080 USERNAME@DNS_NAME
http://127.0.0.1:8080/
", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#youll-need-to-get-the-password-from-the-ssh-terminal-on-the-linux-machine-to-log-in", "title": "You'll need to get the password from the SSH terminal on the Linux machine to log in", "text": "sudo cat /var/lib/jenkins/secrets/initialAdminPassword\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#step-17-customize-jenkins", "title": "Step 17. Customize Jenkins", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-18-create-an-admin-user", "title": "Step 18. Create an Admin user", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#once-jenkins-has-finished-loading-the-top-left-of-the-page-should-look-like-this", "title": "Once Jenkins has finished loading, the top left of the page should look like this", "text": ""}, {"location": "integrations/azure/jenkins/ReadMe/#step-19-create-a-new-jenkins-job", "title": "Step 19. Create a new Jenkins job", "text": "https://github.com/seleniumbase/SeleniumBase.git
. (You'll eventually be using your own clone of the repository here.)cd examples\npytest my_first_test.py --headless\n
"}, {"location": "integrations/azure/jenkins/ReadMe/#click-save-when-youre-done", "title": "Click \"Save\" when you're done.", "text": "If you have a web application that you want to test, you'll be able to create SeleniumBase tests and add them to Jenkins as you saw here. You may want to create a Deploy job, which downloads the latest version of your repository, and then kicks off all tests to run after that. You could then tell that Deploy job to auto-run whenever a change is pushed to your repository by using: \"Poll SCM\". All your tests would then be able to run by using: \"Build after other projects are built\".
"}, {"location": "integrations/azure/jenkins/ReadMe/#congratulations-youre-now-well-on-your-way-to-becoming-a-build-release-automation-engineer", "title": "Congratulations! You're now well on your way to becoming a build & release / automation engineer!", "text": ""}, {"location": "integrations/docker/ReadMe/", "title": "\ud83d\udc33 Docker Start Guide", "text": ""}, {"location": "integrations/docker/ReadMe/#docker-setup-instructions-for-seleniumbase", "title": "Docker setup instructions for SeleniumBase", "text": ""}, {"location": "integrations/docker/ReadMe/#1-install-the-docker-desktop", "title": "1. Install the Docker Desktop", "text": "You can get that from here: https://www.docker.com/products/docker-desktop/
You might also want to install the Docker Engine: https://docs.docker.com/engine/install/
"}, {"location": "integrations/docker/ReadMe/#2-go-to-the-seleniumbase-home-directory-on-the-command-line-which-is-where-dockerfile-is-located-this-assumes-youve-already-cloned-the-seleniumbase-repo", "title": "2. Go to the SeleniumBase home directory on the command line, which is where Dockerfile is located. (This assumes you've already cloned the SeleniumBase repo.)", "text": ""}, {"location": "integrations/docker/ReadMe/#3-create-your-docker-image-from-your-dockerfile-get-ready-to-wait-awhile", "title": "3. Create your Docker image from your Dockerfile: (Get ready to wait awhile)", "text": "docker build -t seleniumbase .\n
If running on an Apple M1/M2 Mac, use this instead:
docker build --platform linux/amd64 -t seleniumbase .\n
M1/M2 Mac users should also see StackOverflow.com/a/76586216/7058266 to Enable Rosetta in Docker Desktop. (Otherwise you will encounter errors like this when Chrome tries to launch: \"Chrome failed to start: crashed.\"
)
docker run seleniumbase ./run_docker_test_in_chrome.sh\n
"}, {"location": "integrations/docker/ReadMe/#5-you-can-also-enter-docker-and-stay-inside-the-shell", "title": "5. You can also enter Docker and stay inside the shell", "text": "docker run -i -t seleniumbase\n
"}, {"location": "integrations/docker/ReadMe/#6-now-you-can-run-the-example-test-from-inside-the-docker-shell", "title": "6. Now you can run the example test from inside the Docker shell", "text": "./run_docker_test_in_chrome.sh\n
"}, {"location": "integrations/docker/ReadMe/#7-when-youre-satisfied-you-may-exit-the-docker-shell", "title": "7. When you're satisfied, you may exit the Docker shell", "text": "exit\n
"}, {"location": "integrations/docker/ReadMe/#8-optional-since-docker-images-and-containers-take-up-a-lot-of-space-you-may-want-to-clean-up-your-machine-from-time-to-time-when-theyre-not-being-used", "title": "8. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they\u2019re not being used", "text": "Details on that can be found here: http://stackoverflow.com/questions/17236796/how-to-remove-old-docker-containers
Here are a few of those cleanup commands:
docker container prune\ndocker system prune\ndocker images | grep \"<none>\" | awk '{print $3}' | xargs docker rmi\ndocker rm 'docker ps --no-trunc -aq'\n
If you want to completely remove all of your Docker containers and images, use these commands: (If there's nothing to delete, those commands will return an error.)
docker rm -f $(docker ps -a -q)\ndocker rmi -f $(docker images -q)\n
For more cleanup commands, check out: https://codefresh.io/blog/everyday-hacks-docker/
"}, {"location": "integrations/docker/ReadMe/#9-optional-more-reading-on-docker-can-be-found-here", "title": "9. (Optional) More reading on Docker can be found here", "text": ".yml
script.", "text": "master
branch.", "text": "(This tutorial, from a previous Google Cloud Meetup, will teach you how to setup a Linux server for running automated browser tests. The cost of running this server is about $13.60/month on Google Cloud (enough to handle 5 parallel tests). This is less expensive than using other platforms.)
"}, {"location": "integrations/google_cloud/ReadMe/#step-1-open-the-google-cloud-platform-cloud-launcher", "title": "Step 1. Open the Google Cloud Platform Cloud Launcher", "text": "cd /\nsudo git clone https://github.com/seleniumbase/SeleniumBase.git\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-5-enter-the-linux-folder", "title": "Step 5. Enter the \"linux\" folder", "text": "cd SeleniumBase/integrations/linux/\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-6-give-jenkins-aka-tomcat-user-sudo-access-see-tomcat_permissionssh-for-details", "title": "Step 6. Give Jenkins (aka \"tomcat\" user) sudo access (See tomcat_permissions.sh for details)", "text": "./tomcat_permissions.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-7-become-tomcat-the-jenkins-user-and-enter-a-bash-shell", "title": "Step 7. Become \"tomcat\" (the Jenkins user) and enter a \"bash\" shell", "text": "sudo su tomcat\nbash\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-8-install-dependencies-see-linuxfilesh-for-details", "title": "Step 8. Install dependencies (See Linuxfile.sh for details)", "text": "./Linuxfile.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-9-start-up-the-headless-browser-display-mechanism-xvfb-see-xvfb_launchersh-for-details", "title": "Step 9. Start up the headless browser display mechanism: Xvfb (See Xvfb_launcher.sh for details)", "text": "./Xvfb_launcher.sh\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-10-go-to-the-seleniumbase-directory", "title": "Step 10. Go to the SeleniumBase directory", "text": "cd /SeleniumBase\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-11-install-the-requirements-for-seleniumbase", "title": "Step 11. Install the requirements for SeleniumBase", "text": "sudo pip install -r requirements.txt --upgrade\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-12-install-seleniumbase", "title": "Step 12. Install SeleniumBase", "text": "sudo python setup.py develop\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-13-run-an-example-test-on-chrome-to-verify-installation-may-take-up-to-10-seconds", "title": "Step 13. Run an example test on Chrome to verify installation (May take up to 10 seconds)", "text": "pytest examples/my_first_test.py --headless\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-14-if-you-prefer-using-nosetests-that-works-too", "title": "Step 14. If you prefer using nosetests, that works too", "text": "nosetests examples/my_first_test.py --headless\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-15-you-can-also-verify-that-the-example-test-runs-on-firefox", "title": "Step 15. You can also verify that the example test runs on Firefox", "text": "pytest examples/my_first_test.py --headless --browser=firefox\n
"}, {"location": "integrations/google_cloud/ReadMe/#step-16-login-to-jenkins", "title": "Step 16. Login to Jenkins", "text": "https://github.com/seleniumbase/SeleniumBase.git
. (You'll eventually be using your own clone of the repository here.)pytest examples/my_first_test.py --headless\n
If you have a web application that you want to test, you'll be able to create SeleniumBase tests and add them to Jenkins as you saw here. You may want to create a Deploy job, which downloads the latest version of your repository, and then kicks off all tests to run after that. You could then tell that Deploy job to auto-run whenever a change is pushed to your repository by using: \"Poll SCM\". All your tests would then be able to run by using: \"Build after other projects are built\". You can also use MySQL to save test results in the DB so that you can query the data at any time.
"}, {"location": "integrations/google_cloud/ReadMe/#congratulations-youre-now-well-on-your-way-to-becoming-a-build-release-automation-engineer", "title": "Congratulations! You're now well on your way to becoming a build & release / automation engineer!", "text": ""}, {"location": "integrations/google_cloud/ReadMe/#mysql-db-setup-instructions", "title": "MySQL DB setup instructions", "text": ""}, {"location": "integrations/google_cloud/ReadMe/#step-21-return-to-the-google-cloud-launcher-and-launch-a-mysql-instance", "title": "Step 21. Return to the Google Cloud Launcher and launch a MySQL Instance", "text": "test_db
.pytest examples/test_suite.py --headless --with-db_reporting\n
@print_runtime(description=None, limit=None)
@runtime_limit(limit, description=None)
@retry_on_exception(tries=6, delay=1, backoff=2, max_delay=32)
@rate_limited(max_per_second)
Example demonstrating a rate-limited printing functionality:
import unittest\nfrom seleniumbase import decorators\n\nclass MyTestClass(unittest.TestCase):\n\n @decorators.rate_limited(3.5) # The arg is max calls per second\n def print_item(self, item):\n print(item)\n\n def test_rate_limited_printing(self):\n print(\"\\nRunning rate-limited print test:\")\n for item in range(1, 11):\n self.print_item(item)\n
"}, {"location": "seleniumbase/common/ReadMe/#part-2-stringpassword-obfuscation-encryption-and-decryption", "title": "Part 2: String/Password Obfuscation, Encryption, and Decryption", "text": ""}, {"location": "seleniumbase/common/ReadMe/#intro", "title": "Intro", "text": "Often in your tests, you may need to login to a website to perform testing. This generally means storing passwords in plaintext formats. For security reasons, that may not be an optimal solution. For this reason, encryption/obfuscation tools have been built here to help you mask your passwords in your tests. It's not a bulletproof solution, but it can keep anyone looking over your shoulder during test creation from getting your login passwords if they don't have your encryption key, which is stored in a separate file.
"}, {"location": "seleniumbase/common/ReadMe/#usage", "title": "Usage", "text": "First, set your custom encryption/decryption key in your local clone of settings.py. (If you modify the key later, you'll need to encrypt all your passwords again.)
Next, use obfuscate.py to obfuscate/encrypt passwords into coded strings:
python obfuscate.py\n\nEnter password to obfuscate: (CTRL+C to exit)\nPassword: *********\nVerify password:\nPassword: *********\n\nHere is the obfuscated password:\n$^*ENCRYPT=RXlYMSJWTz8HSwM=?&#$\n
(You can also use unobfuscate.py to encrypt passwords without having them masked while typing them. Or you can use it to decrypt an obfuscated password.)
from seleniumbase import encryption\n...\npassword = encryption.decrypt('$^*ENCRYPT=RXlYMSJWTz8HSwM=?&#$')\n
(You'll notice that encrypted strings have a common start token and end token. This is to help tell them apart from non-encrypted strings. You can customize these tokens in settings.py. The current default setting is $^*ENCRYPT=
for the start token and ?&#$
for the end token.)
See decryption_test.py for an example of decrypting encrypted passwords in tests.
"}, {"location": "seleniumbase/console_scripts/ReadMe/", "title": "\ud83c\udf20 Console Scripts", "text": ""}, {"location": "seleniumbase/console_scripts/ReadMe/#console-scripts", "title": "Console Scripts \ud83c\udf20", "text": "\ud83c\udf1f SeleniumBase console scripts can do many things, such as downloading web drivers, creating test directories with config files, activating the SeleniumBase Recorder, launching the SeleniumBase Commander, translating tests into other languages, running a Selenium Grid, and more.
Usage: seleniumbase [COMMAND] [PARAMETERS]
(simplified): sbase [COMMAND] [PARAMETERS]
To list all commands: seleniumbase --help
(For running tests, use pytest with SeleniumBase.)
COMMANDS:\n get / install [DRIVER] [OPTIONS]\n methods (List common Python methods)\n options (List common pytest options)\n behave-options (List common behave options)\n gui / commander [OPTIONAL PATH or TEST FILE]\n behave-gui (SBase Commander for Behave)\n caseplans [OPTIONAL PATH or TEST FILE]\n mkdir [DIRECTORY] [OPTIONS]\n mkfile [FILE.py] [OPTIONS]\n mkrec / codegen [FILE.py] [OPTIONS]\n recorder (Open Recorder Desktop App.)\n record (If args: mkrec. Else: App.)\n mkpres [FILE.py] [LANG]\n mkchart [FILE.py] [LANG]\n print [FILE] [OPTIONS]\n translate [SB_FILE.py] [LANG] [ACTION]\n convert [WEBDRIVER_UNITTEST_FILE.py]\n extract-objects [SB_FILE.py]\n inject-objects [SB_FILE.py] [OPTIONS]\n objectify [SB_FILE.py] [OPTIONS]\n revert-objects [SB_FILE.py] [OPTIONS]\n encrypt / obfuscate\n decrypt / unobfuscate\n proxy (Start a basic proxy server)\n download server (Get Selenium Grid JAR file)\n grid-hub [start|stop] [OPTIONS]\n grid-node [start|stop] --hub=[HOST/IP]\n * (EXAMPLE: \"sbase get chromedriver\") *\n\n Type \"sbase help [COMMAND]\" for specific command info.\n For info on all commands, type: \"seleniumbase --help\".\n Use \"pytest\" for running tests.\n
get / install sbase get [DRIVER] [OPTIONS]\nsbase install [DRIVER] [OPTIONS]\n
sbase get chromedriver\nsbase get geckodriver\nsbase get edgedriver\nsbase get chromedriver 114\nsbase get chromedriver 114.0.5735.90\nsbase get chromedriver stable\nsbase get chromedriver beta\nsbase get chromedriver -p\n
(Drivers: chromedriver
, geckodriver
, edgedriver
, iedriver
, uc_driver
)
(Options: A specific driver version or major version integer. If not set, the driver version matches the browser. -p
/ --path
: Also copy to \"/usr/local/bin\".)
Downloads the webdriver to seleniumbase/drivers/
(chromedriver
is required for Chrome automation) (geckodriver
is required for Firefox automation) (edgedriver
is required for MS__Edge automation)
sbase methods\n
Displays common SeleniumBase Python methods.
optionssbase options\n
Displays common pytest command-line options that are available when using SeleniumBase.
--browser=BROWSER (The web browser to use. Default is \"chrome\")\n--edge / --firefox / --safari (Shortcut for browser selection.)\n--headless (Run tests headlessly. Default mode on Linux OS.)\n--demo (Slow down and visually see test actions as they occur.)\n--slow (Slow down the automation. Faster than using Demo Mode.)\n--rs / --reuse-session (Reuse browser session between tests.)\n--crumbs (Clear all cookies between tests reusing a session.)\n--maximize (Start tests with the web browser window maximized.)\n--dashboard (Enable SeleniumBase\\'s Dashboard at dashboard.html)\n--incognito (Enable Chromium\\'s Incognito mode.)\n--guest (Enable Chromium\\'s Guest Mode.)\n--dark (Enable Chromium\\'s Dark Mode.)\n--uc (Use undetected-chromedriver to evade detection.)\n-m=MARKER (Run tests with the specified pytest marker.)\n-n=NUM (Multithread the tests using that many threads.)\n-v (Verbose mode. Print the full names of each test run.)\n--html=report.html (Create a detailed pytest-html report.)\n--collect-only / --co (Only show discovered tests. No run.)\n--co -q (Only show full names of discovered tests. No run.)\n-x (Stop running tests after the first failure is reached.)\n--pdb (Enter the Post Mortem Debug Mode after any test fails.)\n--trace (Enter Debug Mode immediately after starting any test.)\n | Debug Mode Commands >>> help / h: List all commands. |\n | n: Next line of method. s: Step through. c: Continue. |\n | return / r: Run until method returns. j: Jump to line. |\n | where / w: Show stack spot. u: Up stack. d: Down stack. |\n | longlist / ll: See code. dir(): List namespace objects. |\n--help / -h (Display list of all available pytest options.)\n--final-debug (Enter Final Debug Mode after each test ends.)\n--recorder / --rec (Save browser actions as Python scripts.)\n--rec-behave / --rec-gherkin (Save actions as Gherkin code.)\n--rec-print (Display recorded scripts when they are created.)\n--save-screenshot (Save a screenshot at the end of each test.)\n--archive-logs (Archive old log files instead of deleting them.)\n--check-js (Check for JavaScript errors after page loads.)\n--start-page=URL (The browser start page when tests begin.)\n--agent=STRING (Modify the web browser\\'s User-Agent string.)\n--mobile (Use Chromium\\'s mobile device emulator during tests.)\n--metrics=STRING (Set mobile \"CSSWidth,CSSHeight,PixelRatio\".)\n--ad-block (Block some types of display ads after page loads.)\n--settings-file=FILE (Override default SeleniumBase settings.)\n--env=ENV (Set the test env. Access with \"self.env\" in tests.)\n--data=DATA (Extra test data. Access with \"self.data\" in tests.)\n--disable-csp (Disable the Content Security Policy of websites.)\n--remote-debug (Sync to Ch-R-Debugger chrome://inspect/#devices)\n--server=SERVER (The Selenium Grid server/IP used for tests.)\n--port=PORT (The Selenium Grid port used by the test server.)\n--proxy=SERVER:PORT (Connect to a proxy server:port for tests.)\n--proxy=USER:PASS@SERVER:PORT (Use authenticated proxy server.)\n\nFor the full list of command-line options, type: \"pytest --help\".\n
behave-options sbase behave-options\n
Displays common Behave command-line options that are available when using SeleniumBase.
-D browser=BROWSER (The web browser to use. Default is \"chrome\")\n-D headless (Run tests headlessly. Default mode on Linux OS.)\n-D demo (Slow down and visually see test actions as they occur.)\n-D slow (Slow down the automation. Faster than using Demo Mode.)\n-D reuse-session / -D rs (Reuse browser session between tests.)\n-D crumbs (Clear all cookies between tests reusing a session.)\n-D maximize (Start tests with the web browser window maximized.)\n-D dashboard (Enable SeleniumBase\\'s Dashboard at dashboard.html)\n-D incognito (Enable Chromium\\'s Incognito Mode.)\n-D guest (Enable Chromium\\'s Guest Mode.)\n-D dark (Enable Chromium\\'s Dark Mode.)\n-D uc (Use undetected-chromedriver to evade detection.)\n--no-snippets / -q (Quiet mode. Don\\'t print snippets.)\n--dry-run / -d (Dry run. Only show discovered tests.)\n--stop (Stop running tests after the first failure is reached.)\n-D pdb (Enter the Post Mortem Debug Mode after any test fails.)\n | Debug Mode Commands >>> help / h: List all commands. |\n | n: Next line of method. s: Step through. c: Continue. |\n | return / r: Run until method returns. j: Jump to line. |\n | where / w: Show stack spot. u: Up stack. d: Down stack. |\n | longlist / ll: See code. dir(): List namespace objects. |\n-D recorder (Record browser actions to generate test scripts.)\n-D rec-print (Display recorded scripts when they are created.)\n-D save-screenshot (Save a screenshot at the end of each test.)\n-D archive-logs (Archive old log files instead of deleting them.)\n-D check-js (Check for JavaScript errors after page loads.)\n-D start-page=URL (The browser start page when tests begin.)\n-D agent=STRING (Modify the web browser\\'s User-Agent string.)\n-D mobile (Use Chromium\\'s mobile device emulator during tests.)\n-D metrics=STRING (Set mobile \"CSSWidth,CSSHeight,PixelRatio\".)\n-D ad-block (Block some types of display ads after page loads.)\n-D settings-file=FILE (Override default SeleniumBase settings.)\n-D env=ENV (Set the test env. Access with \"self.env\" in tests.)\n-D data=DATA (Extra test data. Access with \"self.data\" in tests.)\n-D disable-csp (Disable the Content Security Policy of websites.)\n-D remote-debug (Sync to Ch-R-Debugger chrome://inspect/#devices)\n-D server=SERVER (The Selenium Grid server/IP used for tests.)\n-D port=PORT (The Selenium Grid port used by the test server.)\n-D proxy=SERVER:PORT (Connect to a proxy server:port for tests.)\n-D proxy=USER:PASS@SERVER:PORT (Use authenticated proxy server.)\n\nFor the full list of command-line options, type: \"behave --help\".\n
gui / commander sbase gui [OPTIONAL PATH or TEST FILE]\nsbase commander [OPTIONAL PATH or TEST FILE]\n
behave-gui sbase behave-gui [OPTIONAL PATH or TEST FILE]\nsbase gui-behave [OPTIONAL PATH or TEST FILE]\n
sbase behave-gui\nsbase behave-gui -i=calculator\nsbase behave-gui features/\nsbase behave-gui features/calculator.feature\n
Launches SeleniumBase Commander / GUI for Behave.
caseplanssbase caseplans [OPTIONAL PATH or TEST FILE]\n
sbase caseplans\nsbase caseplans -k agent\nsbase caseplans -m marker2\nsbase caseplans test_suite.py\nsbase caseplans offline_examples/\n
Launches the SeleniumBase Case Plans Generator.
mkdirsbase mkdir [DIRECTORY] [OPTIONS]\n
sbase mkdir ui_tests\n
-b
/ --basic
(Only config files. No tests added.)
Creates a new folder for running SBase scripts. The new folder contains default config files, sample tests for helping new users get started, and Python boilerplates for setting up customized test frameworks.
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 my_first_test.py\n\u251c\u2500\u2500 parameterized_test.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 test_demo_site.py\n\u2514\u2500\u2500 boilerplates/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 base_test_case.py\n \u251c\u2500\u2500 boilerplate_test.py\n \u251c\u2500\u2500 classic_obj_test.py\n \u251c\u2500\u2500 page_objects.py\n \u251c\u2500\u2500 sb_fixture_test.py\n \u2514\u2500\u2500 samples/\n \u251c\u2500\u2500 __init__.py\n \u251c\u2500\u2500 google_objects.py\n \u251c\u2500\u2500 google_test.py\n \u251c\u2500\u2500 sb_swag_test.py\n \u2514\u2500\u2500 swag_labs_test.py\n
If running with the -b
or --basic
option:
ui_tests/\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 pytest.ini\n\u251c\u2500\u2500 requirements.txt\n\u2514\u2500\u2500 setup.cfg\n
mkfile sbase mkfile [FILE.py] [OPTIONS]\n
sbase mkfile new_test.py\n
-b
/ --basic
(Basic boilerplate / single-line test) -r
/ --rec
(adds Pdb+ breakpoint for Recorder Mode) --url=URL
(makes the test start on a specific page)
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
--bc
/ --basecase
(BaseCase class inheritance) --pf
/ --pytest-fixture
(sb pytest fixture) --cf
/ --class-fixture
(class + sb pytest fixture) --cm
/ --context-manager
(SB context manager) --dc
/ --driver-context
(DriverContext manager) --dm
/ --driver-manager
(Driver manager)
Creates a new SBase test file with boilerplate code. If the file already exists, an error is raised. By default, uses English with BaseCase inheritance, and creates a boilerplate with common SeleniumBase methods: \"open\", \"type\", \"click\", \"assert_element\", and \"assert_text\". If using the basic boilerplate option, only the \"open\" method is included. Only the BaseCase format supports Languages or Recorder Mode.
mkrec / record / codegensbase mkrec [FILE.py] [OPTIONS]\nsbase codegen [FILE.py] [OPTIONS]\n
sbase mkrec new_test.py\nsbase mkrec new_test.py --url=seleniumbase.io\nsbase codegen new_test.py\nsbase codegen new_test.py --url=wikipedia.org\n
--url=URL
(Sets the initial start page URL.) --edge
(Use Edge browser instead of Chrome.) --gui
/ --headed
(Use headed mode on Linux.) --uc
/ --undetected
(Use undetectable mode.) --ee
(Use SHIFT + ESC to end the recording.) --overwrite
(Overwrite file when it exists.) --behave
(Also output Behave/Gherkin files.)
Creates a new SeleniumBase test using the Recorder. If the filename already exists, an error is raised.
recordersbase recorder [OPTIONS]\n
--uc
/ --undetected
(Use undetectable mode.) --behave
(Also output Behave/Gherkin files.)
Launches the SeleniumBase Recorder Desktop App.
mkpressbase mkpres [FILE.py] [LANG]\n
sbase mkpres new_presentation.py --en\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
Creates a new presentation with 3 example slides. If the file already exists, an error is raised. By default, the slides are written in English, and use \"serif\" theme with \"slide\" transition. The slides can be used as a basic boilerplate.
mkchartsbase mkchart [FILE.py] [LANG]\n
sbase mkchart new_chart.py --en\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
Creates a new SeleniumBase chart presentation. If the file already exists, an error is raised. By default, the slides are written in English, and use a \"sky\" theme with \"slide\" transition. The chart can be used as a basic boilerplate.
printsbase print [FILE] [OPTIONS]\n
-n
(Add line Numbers to the rows)
Prints the code/text of any file with syntax-highlighting.
translatesbase translate [SB_FILE.py] [LANGUAGE] [ACTION]\n
--en
/ --English
| --zh
/ --Chinese
--nl
/ --Dutch
| --fr
/ --French
--it
/ --Italian
| --ja
/ --Japanese
--ko
/ --Korean
| --pt
/ --Portuguese
--ru
/ --Russian
| --es
/ --Spanish
-p
/ --print
(Print translation output to the screen) -o
/ --overwrite
(Overwrite the file being translated) -c
/ --copy
(Copy the translation to a new .py
file)
-n
(include line Numbers when using the Print action)
Translates a SeleniumBase Python file into the language specified. Method calls and \"import\" lines get swapped. Both a language and an action must be specified. The -p
action can be paired with one other action. When running with -c
(or --copy
), the new file name will be the original name appended with an underscore plus the 2-letter language code of the new language. (Example: Translating \"test_1.py\" into Japanese with -c
will create a new file called \"test_1_ja.py\".)
sbase extract-objects [SB_FILE.py]\n
Creates page objects based on selectors found in a seleniumbase Python file and saves those objects to the \"page_objects.py\" file in the same folder as the tests.
inject-objectssbase inject-objects [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Add object selectors to the comments.)
Takes the page objects found in the \"page_objects.py\" file and uses those to replace matching selectors in the selected seleniumbase Python file.
objectifysbase objectify [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Add object selectors to the comments.)
A modified version of the file where the selectors have been replaced with variable names defined in \"page_objects.py\", supporting the Page Object Pattern. (This has the same outcome as combining extract-objects
with inject-objects
)
sbase revert-objects [SB_FILE.py] [OPTIONS]\n
-c
, --comments
(Keep existing comments for the lines.)
Reverts the changes made by seleniumbase objectify ...
or seleniumbase inject-objects ...
when run against a seleniumbase Python file. Objects will get replaced by selectors stored in the \"page_objects.py\" file.
sbase convert [WEBDRIVER_UNITTEST_FILE.py]\n
Converts a Selenium IDE exported WebDriver unittest file into a SeleniumBase file. Adds _SB
to the new filename while keeping the original file intact. Works on both Selenium IDE & Katalon Recorder scripts.
sbase encrypt
OR sbase obfuscate
Runs the password encryption/obfuscation tool. (Where you can enter a password to encrypt/obfuscate.)
decrypt / unobfuscatesbase decrypt
OR sbase unobfuscate
Runs the password decryption/unobfuscation tool. (Where you can enter an encrypted password to decrypt.)
proxysbase proxy [OPTIONS]\n
--hostname=HOSTNAME
(Set hostname
) (Default: 127.0.0.1
) --port=PORT
(Set port
) (Default: 8899
) --help
/ -h
(Display list of all available proxy
options.)
Launch a basic proxy server on the current machine. (Uses 127.0.0.1:8899
as the default address.)
sbase download server\n
Downloads the Selenium Server JAR file for Grid usage. (That JAR file is required when using a Selenium Grid)
grid-hubsbase grid-hub {start|stop|restart} [OPTIONS]\n
-v
, --verbose
(Increases verbosity of logging output.) --timeout=TIMEOUT
(Close idle browser windows after TIMEOUT seconds.)
Controls the Selenium Grid Hub server, which allows for running tests on multiple machines in parallel to speed up test runs and reduce the total time of test suite execution. You can start, restart, or stop the Grid Hub server.
grid-nodesbase grid-node {start|stop|restart} [OPTIONS]\n
--hub=HUB_IP
(The Grid Hub IP Address to connect to.) (Default: 127.0.0.1
) -v
, --verbose
(Increases verbosity of logging output.)
Controls the Selenium Grid node, which serves as a worker machine for your Selenium Grid Hub server. You can start, restart, or stop the Grid node.
"}, {"location": "seleniumbase/utilities/selenium_grid/ReadMe/", "title": "\ud83c\udf10 Selenium Grid", "text": "The Selenium Grid Hub:The Selenium Grid Hub lets you distribute tests to run in parallel across multiple node machines. Each node machine can then run its own allocation of tests. This allows you to run a large suite of tests very quickly.
Running the Selenium Grid Hub:The following commands will work once you've installed seleniumbase.
Downloading the Selenium Server JAR file:seleniumbase download server\n
seleniumbase grid-hub {start|stop|restart} [OPTIONS]\n
Options:
seleniumbase grid-node {start|stop|restart} --hub=[HUB_IP] [OPTIONS]\n
Options:
When the Grid Hub Console is up and running, you'll be able to find it here: http://127.0.0.1:4444/grid/console
Now you can run your tests on the Selenium Grid:
pytest test_demo_site.py --server=IP_ADDRESS --port=4444\n
You can also run your tests on someone else's Selenium Grid to avoid managing your own. Here are some Selenium Grids that you can use (and the run command format):
pytest test_demo_site.py --server=USERNAME:KEY@hub.browserstack.com --port=80\n
pytest test_demo_site.py --server=USERNAME:KEY@ondemand.us-east-1.saucelabs.com --port=443 --protocol=https\n
pytest test_demo_site.py --server=USERNAME:KEY@hub.crossbrowsertesting.com --port=80\n
To use a server on the https
protocol, add --protocol=https
: (SeleniumBase 1.65.2 and newer uses https
automatically for --port=443
.)
pytest test_demo_site.py --protocol=https --server=IP_ADDRESS --port=PORT\n
(For setting browser desired capabilities while running Selenium remotely, see the desired capabilities documentation and the sample files located in SeleniumBase/examples/capabilities)
More info about the Selenium Grid Hub can be found here: