From 19a8a67a5c3fea5f134cf39b1452be0e9568aea4 Mon Sep 17 00:00:00 2001 From: Titus Fortner Date: Fri, 5 Jun 2026 17:24:21 -0500 Subject: [PATCH 1/2] [py] add Selenium Manager integration tests --- .github/workflows/ci-python.yml | 16 +++ py/BUILD.bazel | 34 +++++- .../webdriver/common/driver_finder_tests.py | 103 ++++++++++++++++++ 3 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 py/test/selenium/webdriver/common/driver_finder_tests.py diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 507bcd335c5be..1940e479e52f9 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -85,3 +85,19 @@ jobs: rerun-with-debug: true run: | bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:test-${{ matrix.browser }} + + selenium-manager-tests: + name: Selenium Manager Tests + needs: build + uses: ./.github/workflows/bazel.yml + strategy: + fail-fast: false + matrix: + os: [ubuntu, windows, macos] + with: + name: Integration Tests Selenium Manager (${{ matrix.os }}) + needs-display: true + os: ${{ matrix.os }} + rerun-with-debug: true + run: | + bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=false --build_tests_only --test_tag_filters=se-manager //py/... diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 6835e30127bbf..ce7d32d944824 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -818,6 +818,8 @@ ACTIONS_TESTS = [ "test/selenium/webdriver/support/event_firing_webdriver_tests.py", ] +DRIVER_FINDER_TESTS = ["test/selenium/webdriver/common/driver_finder_tests.py"] + # Browser-specific test configuration BROWSER_TESTS = { "chrome": { @@ -905,7 +907,7 @@ DEFAULT_BROWSER_TESTS = [b for b in BROWSER_TESTS if b != "ie"] "test/selenium/webdriver/common/**/*.py", "test/selenium/webdriver/support/**/*.py", ] + BROWSER_TESTS[browser]["browser_srcs"], - exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + + exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + BROWSER_TESTS[browser].get("extra_excludes", []), ), args = [ @@ -989,6 +991,28 @@ FEATURE_SUITE_DEFS = { ] + [":test-%s-%s" % (browser, f) for f in FEATURE_SUITE_DEFS], ) for browser in DEFAULT_BROWSER_TESTS] +[ + py_test_suite( + name = "test-%s-driver-finder" % browser, + size = "large", + srcs = DRIVER_FINDER_TESTS, + args = [ + "--instafail", + ] + BROWSERS[browser]["args"], + data = BROWSERS[browser]["data"], + env_inherit = ["DISPLAY"], + flaky = True, + tags = BROWSERS[browser]["tags"] + ["se-manager"], + target_compatible_with = BROWSERS[browser]["target_compatible_with"], + test_suffix = browser, + deps = [ + ":init-tree", + ":webserver", + ] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS, + ) + for browser in DEFAULT_BROWSER_TESTS +] + # Generate test--bidi-common targets [ py_test_suite( @@ -999,7 +1023,7 @@ FEATURE_SUITE_DEFS = { "test/selenium/webdriver/common/**/*.py", "test/selenium/webdriver/support/**/*.py", ] + BROWSER_TESTS[browser]["browser_srcs"], - exclude = ACTIONS_TESTS + FEATURE_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + + exclude = ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + BROWSER_TESTS[browser].get("extra_excludes", []), ), args = [ @@ -1091,7 +1115,7 @@ FEATURE_SUITE_DEFS = { "test/selenium/webdriver/remote/**/*.py", "test/selenium/webdriver/support/**/*.py", ] + BROWSER_TESTS[browser]["browser_srcs"], - exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + + exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS + ["test/selenium/webdriver/common/print_pdf_tests.py"] + BROWSER_TESTS[browser].get("extra_excludes", []), ), args = [ @@ -1227,7 +1251,7 @@ py_test_suite( "test/selenium/webdriver/common/**/*.py", "test/selenium/webdriver/support/**/*.py", ], - exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS, + exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS, ), args = [ "--instafail", @@ -1319,7 +1343,7 @@ py_test_suite( "test/selenium/webdriver/common/**/*.py", "test/selenium/webdriver/support/**/*.py", ], - exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS, + exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS, ), args = [ "--instafail", diff --git a/py/test/selenium/webdriver/common/driver_finder_tests.py b/py/test/selenium/webdriver/common/driver_finder_tests.py new file mode 100644 index 0000000000000..b75aef5c7dc33 --- /dev/null +++ b/py/test/selenium/webdriver/common/driver_finder_tests.py @@ -0,0 +1,103 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import os +import sys + +import pytest + +from selenium import webdriver +from selenium.webdriver.common.driver_finder import DriverFinder + +from conftest import _resolve_bazel_path + + +@pytest.fixture +def browser_name(request): + drivers = request.config.option.drivers + if not drivers: + pytest.skip("Selenium Manager tests require a single --driver/--browser") + return drivers[0].lower() + + +@pytest.fixture +def pinned(request): + return bool(request.config.option.executable) + + +@pytest.fixture +def driver_finder(browser_name, request): + module = getattr(webdriver, browser_name) + + options = module.options.Options() + if request.config.option.binary: + options.binary_location = _resolve_bazel_path(request.config.option.binary).strip("'") + + executable = request.config.option.executable + service = module.service.Service(executable_path=_resolve_bazel_path(executable) if executable else None) + + return DriverFinder(service, options) + + +def test_resolves_an_executable_driver_path(driver_finder): + path = driver_finder.get_driver_path() + assert os.path.isfile(path), f"driver path is not a file: {path}" + assert os.access(path, os.X_OK), f"driver path is not executable: {path}" + + +def test_resolves_an_executable_browser_path(driver_finder, pinned): + if pinned: + pytest.skip("Pinned runs supply the browser via options; Selenium Manager is not consulted") + path = driver_finder.get_browser_path() + assert os.path.isfile(path), f"browser path is not a file: {path}" + assert os.access(path, os.X_OK), f"browser path is not executable: {path}" + + +def test_downloads_the_driver_into_the_selenium_cache(driver_finder, browser_name, pinned, tmp_path, monkeypatch): + if pinned: + pytest.skip("Pinned runs do not use Selenium Manager") + if browser_name == "safari": + pytest.skip("Safari driver ships with the OS") + monkeypatch.setenv("SE_CACHE_PATH", str(tmp_path)) + monkeypatch.setenv("SE_SKIP_DRIVER_IN_PATH", "true") + # Match by basename so 8.3 short names on Windows don't fail the comparison. + assert tmp_path.name in driver_finder.get_driver_path() + + +def test_downloads_the_browser_into_the_selenium_cache(driver_finder, browser_name, pinned, tmp_path, monkeypatch): + if pinned: + pytest.skip("Pinned runs do not use Selenium Manager") + if browser_name == "safari": + pytest.skip("Safari ships with the OS") + if browser_name == "edge" and sys.platform == "win32": + pytest.skip("Edge MSI installer always writes to the system path") + monkeypatch.setenv("SE_CACHE_PATH", str(tmp_path)) + monkeypatch.setenv("SE_FORCE_BROWSER_DOWNLOAD", "true") + assert tmp_path.name in driver_finder.get_browser_path() + + +def test_resolves_the_browser_to_its_system_install_location( + driver_finder, browser_name, pinned, tmp_path, monkeypatch +): + if pinned: + pytest.skip("Pinned runs do not use Selenium Manager") + system_only = browser_name == "safari" or (browser_name == "edge" and sys.platform == "win32") + if not system_only: + pytest.skip("Only Safari and Windows Edge resolve to a system install location") + monkeypatch.setenv("SE_CACHE_PATH", str(tmp_path)) + monkeypatch.setenv("SE_FORCE_BROWSER_DOWNLOAD", "true") + assert tmp_path.name not in driver_finder.get_browser_path() From b28e3cffe29555861796bdfaf60633a9c626293b Mon Sep 17 00:00:00 2001 From: Titus Fortner Date: Sat, 6 Jun 2026 08:12:29 -0500 Subject: [PATCH 2/2] [py] strip quotes from pinned driver path in selenium manager test --- py/test/selenium/webdriver/common/driver_finder_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/test/selenium/webdriver/common/driver_finder_tests.py b/py/test/selenium/webdriver/common/driver_finder_tests.py index b75aef5c7dc33..2f44d7def5768 100644 --- a/py/test/selenium/webdriver/common/driver_finder_tests.py +++ b/py/test/selenium/webdriver/common/driver_finder_tests.py @@ -48,7 +48,7 @@ def driver_finder(browser_name, request): options.binary_location = _resolve_bazel_path(request.config.option.binary).strip("'") executable = request.config.option.executable - service = module.service.Service(executable_path=_resolve_bazel_path(executable) if executable else None) + service = module.service.Service(executable_path=_resolve_bazel_path(executable).strip("'") if executable else None) return DriverFinder(service, options)