This guide helps contributors write tests in the Selenium Python codebase.
common/src/web/.pages fixture loads test pages via pages.load("pageName.html").assert statements.import pytest from selenium.webdriver.common.by import By def test_element_is_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(By.ID, "displayed") assert element.is_displayed() is True @pytest.mark.xfail_safari(reason="Safari doesn't support this") def test_something_safari_fails(driver, pages): # Expected to fail on Safari pass
Bazel creates test targets for each browser. Tests run in parallel by default.
bazel test //py/... # All tests bazel test //py:unit # Unit tests (no browser) bazel test //py:test-chrome # Chrome browser tests bazel test //py:test-firefox # Firefox browser tests bazel test //py:test-chrome-common # Common (cross-browser) tests with Chrome # A single test file with Chrome (target = test/<path>/<file>-<browser>[-variant]). # Discover exact names with: bazel query //py:all | grep window_tests bazel test //py:test/selenium/webdriver/common/window_tests-chrome # With BiDi protocol bazel test //py:test-chrome-bidi # Test filters bazel test //py/... --test_tag_filters=chrome # Additional arguments bazel test //py/... --flaky_test_attempts=3 bazel test //py/... --test_output=all bazel test //py/... --test_output=streamed # Live output for debugging bazel test //py:test-chrome --headless # Run a specific test in a test file bazel test //py:test/selenium/webdriver/common/bidi_browsing_context_tests-chrome-bidi \ --test_arg=-k \ --test_arg=test_get_tree_with_child \ # View all targets bazel query //py/...
You can run tests directly with pytest after setting up the development environment.
First, install the required dependencies:
pip install -r py/requirements_lock.txt
Then build the generated files and copy them into your local source tree:
./go py:local_dev
# Run all tests in a directory pytest py/test/selenium/webdriver/chrome/ --driver chrome # Run a specific test file pytest py/test/selenium/webdriver/common/window_tests.py # Run a specific test function pytest py/test/selenium/webdriver/common/window_tests.py::test_should_get_the_size_of_the_current_window # With pytest options pytest py/test/selenium/webdriver/chrome/ --driver chrome --headless -v
Note: For running BiDi tests, use the
--bidiflag.
Skips use pytest markers; each accepts optional reason and run parameters (run=False skips the test entirely instead of expecting a failure).
| Marker | When to Use |
|---|---|
@pytest.mark.xfail_chrome | Test expected to fail on Chrome |
@pytest.mark.xfail_firefox | Test expected to fail on Firefox |
@pytest.mark.xfail_safari | Test expected to fail on Safari |
@pytest.mark.xfail_edge | Test expected to fail on Edge |
@pytest.mark.xfail_ie | Test expected to fail on IE |
@pytest.mark.xfail_remote | Test expected to fail with Remote WebDriver |
@pytest.mark.xfail_chrome(reason="Not implemented yet") @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/123") def test_something(driver, pages): pass @pytest.mark.xfail_safari(run=False) # Skip entirely instead of xfail def test_skip_safari(driver, pages): pass
| Marker | When to Use |
|---|---|
@pytest.mark.no_driver_after_test | Teardown driver after test |
@pytest.mark.needs_fresh_driver | Restart driver for test isolation |
We make use of pytest fixtures to simplify test setup/teardown. There are several built-in pytest fixtures, and many of our own internal fixtures. If a fixture is specific to a module, you will find it defined within the test file that uses it. If it is shared among several modules, you will find the main fixtures in conftest.py:
| Fixture | Description |
|---|---|
driver | WebDriver instance, auto-parametrized by browser |
pages | Load test pages: pages.load("page.html") or pages.url("page.html") |
webserver | Test HTTP server reference |
clean_driver | Fresh driver without parametrization |
clean_options | Fresh browser options instance |
py/test/
├── unit/ # Unit tests (no browser)
│ └── selenium/webdriver/
└── selenium/webdriver/ # Integration tests
├── common/ # Cross-browser tests
├── chrome/
├── firefox/
├── safari/
└── remote/
Test files end in _tests.py (e.g., visibility_tests.py).
*_tests.py are picked up automatically.py_test_suite targets.