From db5ed89b63f39c12eb389a1b65dbc54aaee10aa1 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Tue, 30 Sep 2025 20:31:15 -0400 Subject: [PATCH 01/14] [build] Python CI - add unit tests and chrome/windows to integration tests --- .github/workflows/ci-python.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 173cf2fa64613..fc27ed92c8fc3 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -54,6 +54,22 @@ jobs: env: TOXENV: mypy + unit-tests: + name: Unit Tests + needs: build + uses: ./.github/workflows/bazel.yml + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu + - os: windows + with: + name: Unit Tests (${{ matrix.os }}) + os: ${{ matrix.os }} + cache-key: python-unit-test-${{ matrix.os }}} + run: bazel test //py:unit + remote-tests: name: Remote Tests needs: build @@ -79,6 +95,8 @@ jobs: include: - browser: chrome os: ubuntu + - browser: chrome + os: windows - browser: edge os: ubuntu - browser: firefox From be85745908fb8ed6ed0e3026113b7e3d69b04703 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Tue, 30 Sep 2025 21:19:04 -0400 Subject: [PATCH 02/14] [py] Fix cache key --- .github/workflows/ci-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index fc27ed92c8fc3..426685d68411a 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -67,7 +67,7 @@ jobs: with: name: Unit Tests (${{ matrix.os }}) os: ${{ matrix.os }} - cache-key: python-unit-test-${{ matrix.os }}} + cache-key: python-unit-test-${{ matrix.os }} run: bazel test //py:unit remote-tests: From 3f62eda7c02cf5e47ceb4b19598673bd89a38f01 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Fri, 3 Oct 2025 08:58:16 -0400 Subject: [PATCH 03/14] [py] Add newline --- py/selenium/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/py/selenium/types.py b/py/selenium/types.py index fdec985bd16ab..08ea194c49a8c 100644 --- a/py/selenium/types.py +++ b/py/selenium/types.py @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + """Selenium type definitions.""" from collections.abc import Iterable From e5325f84247dfe99d3fd3ba8e37bb680f5356857 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Fri, 3 Oct 2025 09:22:31 -0400 Subject: [PATCH 04/14] [py] Add more tests to CI --- .github/workflows/ci-python.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 426685d68411a..bbda5d4a4be5f 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -95,12 +95,16 @@ jobs: include: - browser: chrome os: ubuntu - - browser: chrome - os: windows - browser: edge os: ubuntu - browser: firefox os: ubuntu + - browser: chrome + os: windows + - browser: edge + os: windows + - browser: firefox + os: windows with: name: Integration Tests (${{ matrix.browser }}, ${{ matrix.os }}) browser: ${{ matrix.browser }} @@ -126,4 +130,5 @@ jobs: os: ${{ matrix.os }} cache-key: py-browser-${{ matrix.browser }} run: | + bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:common-${{ matrix.browser }} bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:test-${{ matrix.browser }} From 88cf6fd22c77bc1eeeaf7d98f9ce59c580bcbaea Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:45:43 -0400 Subject: [PATCH 05/14] [py] Fix broken unit test assertion on Windows --- .../unit/selenium/webdriver/remote/remote_connection_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py b/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py index e2efccde7221f..eb68796f3172c 100644 --- a/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py +++ b/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py @@ -65,7 +65,7 @@ def test_get_remote_connection_headers_defaults(): assert headers.get("Accept") == "application/json" assert headers.get("Content-Type") == "application/json;charset=UTF-8" assert headers.get("User-Agent").startswith(f"selenium/{__version__} (python ") - assert headers.get("User-Agent").split(" ")[-1] in {"windows)", "mac)", "linux)", "mac", "windows", "linux"} + assert headers.get("User-Agent").split(" ")[-1].rstrip(")") in ("win32", "windows", "mac", "linux") def test_get_remote_connection_headers_adds_auth_header_if_pass(recwarn): From c3e5ca72e1954f30da818cf0adc7cdca74b9efe4 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:04:08 -0400 Subject: [PATCH 06/14] [py] Skip tests on Windows that fail --- py/test/selenium/webdriver/chrome/chrome_service_tests.py | 5 +++++ py/test/selenium/webdriver/edge/edge_service_tests.py | 4 ++++ .../virtual_authenticator_options_tests.py | 3 +++ 3 files changed, 12 insertions(+) diff --git a/py/test/selenium/webdriver/chrome/chrome_service_tests.py b/py/test/selenium/webdriver/chrome/chrome_service_tests.py index fc110921cfd1d..c592d22a82626 100644 --- a/py/test/selenium/webdriver/chrome/chrome_service_tests.py +++ b/py/test/selenium/webdriver/chrome/chrome_service_tests.py @@ -17,6 +17,7 @@ import os import subprocess +import sys import time from unittest.mock import patch @@ -107,6 +108,10 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() +@pytest.mark.skipif( + sys.platform == "win32", + reason="chromedriver doesn't return an error on windows if you use an invalid profile path", +) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index af449b3ddfbb7..ba1d661c5fddc 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -107,6 +107,10 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() +@pytest.mark.skipif( + sys.platform == "win32", + reason="edgedriver doesn't return an error on windows if you use an invalid profile path", +) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, clean_service, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") diff --git a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py index 30b93b559aeef..4a3bcbfca2080 100644 --- a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py +++ b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +import sys + import pytest from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions @@ -43,6 +45,7 @@ def test_bespoke_options_for_virtual_authenticator(): } +@pytest.mark.skipif(sys.platform == "win32", reason="Fails when run with Bazel on GH runners") def test_to_dict_with_defaults(options): default_options = options.to_dict() assert default_options["transport"] == VirtualAuthenticatorOptions.Transport.USB.value From 4fdf2059e69177ccf5accfce11a31f835738b0ff Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:25:53 -0400 Subject: [PATCH 07/14] [py] Add missing import --- py/test/selenium/webdriver/edge/edge_service_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index ba1d661c5fddc..55c8fd3bca7a2 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -17,6 +17,7 @@ import os import subprocess +import sys import time from unittest.mock import patch From 62413d053d4557d17a46640dcaf0a91bf61bf4e4 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sat, 4 Oct 2025 09:42:38 -0400 Subject: [PATCH 08/14] [py] Skip additional test on Windows --- .../virtual_authenticator_options_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py index 4a3bcbfca2080..25cc6c4782c23 100644 --- a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py +++ b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py @@ -27,6 +27,7 @@ def options(): return VirtualAuthenticatorOptions() +@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windoiws when run with Bazel on GHA runners") def test_bespoke_options_for_virtual_authenticator(): assert VirtualAuthenticatorOptions( protocol="ctap1/u2f", @@ -45,7 +46,7 @@ def test_bespoke_options_for_virtual_authenticator(): } -@pytest.mark.skipif(sys.platform == "win32", reason="Fails when run with Bazel on GH runners") +@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windoiws when run with Bazel on GHA runners") def test_to_dict_with_defaults(options): default_options = options.to_dict() assert default_options["transport"] == VirtualAuthenticatorOptions.Transport.USB.value From 70cdad8929b3455bf696257b985f29fcb2b5b68c Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sat, 4 Oct 2025 09:46:27 -0400 Subject: [PATCH 09/14] [py] Update test os matrix --- .github/workflows/ci-python.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index bbda5d4a4be5f..69b8a308ef312 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -64,6 +64,7 @@ jobs: include: - os: ubuntu - os: windows + - os: macos with: name: Unit Tests (${{ matrix.os }}) os: ${{ matrix.os }} @@ -103,8 +104,6 @@ jobs: os: windows - browser: edge os: windows - - browser: firefox - os: windows with: name: Integration Tests (${{ matrix.browser }}, ${{ matrix.os }}) browser: ${{ matrix.browser }} From c60ecd6d51f6170540048510a1ef01cfdcbc97d4 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sat, 4 Oct 2025 18:23:52 -0400 Subject: [PATCH 10/14] [py] Remove skip markers --- .../virtual_authenticator_options_tests.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py index 25cc6c4782c23..d7ebe23d11312 100644 --- a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py +++ b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py @@ -27,7 +27,6 @@ def options(): return VirtualAuthenticatorOptions() -@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windoiws when run with Bazel on GHA runners") def test_bespoke_options_for_virtual_authenticator(): assert VirtualAuthenticatorOptions( protocol="ctap1/u2f", @@ -46,7 +45,6 @@ def test_bespoke_options_for_virtual_authenticator(): } -@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windoiws when run with Bazel on GHA runners") def test_to_dict_with_defaults(options): default_options = options.to_dict() assert default_options["transport"] == VirtualAuthenticatorOptions.Transport.USB.value From f28290d2e41c8278f2c204b584637de3b71e43f0 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sat, 4 Oct 2025 18:31:03 -0400 Subject: [PATCH 11/14] [py] Remove Windows unit tests from CI again --- .github/workflows/ci-python.yml | 1 - py/test/selenium/webdriver/chrome/chrome_service_tests.py | 4 ---- py/test/selenium/webdriver/edge/edge_service_tests.py | 4 ---- 3 files changed, 9 deletions(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 69b8a308ef312..96c5182b71740 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -63,7 +63,6 @@ jobs: matrix: include: - os: ubuntu - - os: windows - os: macos with: name: Unit Tests (${{ matrix.os }}) diff --git a/py/test/selenium/webdriver/chrome/chrome_service_tests.py b/py/test/selenium/webdriver/chrome/chrome_service_tests.py index c592d22a82626..85562c91bb299 100644 --- a/py/test/selenium/webdriver/chrome/chrome_service_tests.py +++ b/py/test/selenium/webdriver/chrome/chrome_service_tests.py @@ -108,10 +108,6 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() -@pytest.mark.skipif( - sys.platform == "win32", - reason="chromedriver doesn't return an error on windows if you use an invalid profile path", -) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index 55c8fd3bca7a2..42770edb90179 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -108,10 +108,6 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() -@pytest.mark.skipif( - sys.platform == "win32", - reason="edgedriver doesn't return an error on windows if you use an invalid profile path", -) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, clean_service, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") From 3f6d4b52f42934af17ce19a62a81e18386fef936 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sun, 5 Oct 2025 07:32:51 -0400 Subject: [PATCH 12/14] [py] Remove unused import --- py/test/selenium/webdriver/chrome/chrome_service_tests.py | 1 - py/test/selenium/webdriver/edge/edge_service_tests.py | 1 - .../virtual_authenticator/virtual_authenticator_options_tests.py | 1 - 3 files changed, 3 deletions(-) diff --git a/py/test/selenium/webdriver/chrome/chrome_service_tests.py b/py/test/selenium/webdriver/chrome/chrome_service_tests.py index 85562c91bb299..fc110921cfd1d 100644 --- a/py/test/selenium/webdriver/chrome/chrome_service_tests.py +++ b/py/test/selenium/webdriver/chrome/chrome_service_tests.py @@ -17,7 +17,6 @@ import os import subprocess -import sys import time from unittest.mock import patch diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index 42770edb90179..af449b3ddfbb7 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -17,7 +17,6 @@ import os import subprocess -import sys import time from unittest.mock import patch diff --git a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py index d7ebe23d11312..dacb9587b4880 100644 --- a/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py +++ b/py/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. -import sys import pytest From e9a1595350e2d723f81b9ba8092b57a7a4695efe Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sun, 5 Oct 2025 08:03:44 -0400 Subject: [PATCH 13/14] [py] Add xfail marker --- py/test/selenium/webdriver/chrome/chrome_service_tests.py | 2 ++ py/test/selenium/webdriver/edge/edge_service_tests.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/py/test/selenium/webdriver/chrome/chrome_service_tests.py b/py/test/selenium/webdriver/chrome/chrome_service_tests.py index fc110921cfd1d..c81e08e30cf04 100644 --- a/py/test/selenium/webdriver/chrome/chrome_service_tests.py +++ b/py/test/selenium/webdriver/chrome/chrome_service_tests.py @@ -17,6 +17,7 @@ import os import subprocess +import sys import time from unittest.mock import patch @@ -107,6 +108,7 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() +@pytest.mark.xfail(sys.platform == "win32", reason="chromedriver doesn't return an error on windows if you use an invalid profile path") @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index af449b3ddfbb7..0bebda17afd11 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -17,6 +17,7 @@ import os import subprocess +import sys import time from unittest.mock import patch @@ -107,6 +108,7 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() +@pytest.mark.xfail(sys.platform == "win32", reason="edgedriver doesn't return an error on windows if you use an invalid profile path") @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, clean_service, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") From 636b0e3f4611e2921999662996d597d3b4f0d673 Mon Sep 17 00:00:00 2001 From: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Date: Sun, 5 Oct 2025 08:06:55 -0400 Subject: [PATCH 14/14] [py] Fix formatting --- py/test/selenium/webdriver/chrome/chrome_service_tests.py | 4 +++- py/test/selenium/webdriver/edge/edge_service_tests.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/py/test/selenium/webdriver/chrome/chrome_service_tests.py b/py/test/selenium/webdriver/chrome/chrome_service_tests.py index c81e08e30cf04..53d4241f9fd1b 100644 --- a/py/test/selenium/webdriver/chrome/chrome_service_tests.py +++ b/py/test/selenium/webdriver/chrome/chrome_service_tests.py @@ -108,7 +108,9 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() -@pytest.mark.xfail(sys.platform == "win32", reason="chromedriver doesn't return an error on windows if you use an invalid profile path") +@pytest.mark.xfail( + sys.platform == "win32", reason="chromedriver doesn't return an error on windows if you use an invalid profile path" +) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location") diff --git a/py/test/selenium/webdriver/edge/edge_service_tests.py b/py/test/selenium/webdriver/edge/edge_service_tests.py index 0bebda17afd11..37f4da68c453f 100644 --- a/py/test/selenium/webdriver/edge/edge_service_tests.py +++ b/py/test/selenium/webdriver/edge/edge_service_tests.py @@ -108,7 +108,9 @@ def test_log_output_null_default(driver, capfd) -> None: driver.quit() -@pytest.mark.xfail(sys.platform == "win32", reason="edgedriver doesn't return an error on windows if you use an invalid profile path") +@pytest.mark.xfail( + sys.platform == "win32", reason="edgedriver doesn't return an error on windows if you use an invalid profile path" +) @pytest.mark.no_driver_after_test def test_driver_is_stopped_if_browser_cant_start(clean_driver, clean_options, clean_service, driver_executable) -> None: clean_options.add_argument("--user-data-dir=/no/such/location")