diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 7cddd0d8515b8..530fd4d8d19f7 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -321,7 +321,6 @@ py_library( "test/selenium/webdriver/__init__.py", "test/selenium/webdriver/chrome/__init__.py", "test/selenium/webdriver/common/__init__.py", - "test/selenium/webdriver/common/conftest.py", "test/selenium/webdriver/common/network.py", "test/selenium/webdriver/common/webserver.py", "test/selenium/webdriver/firefox/__init__.py", @@ -330,7 +329,6 @@ py_library( "test/selenium/webdriver/marionette/conftest.py", "test/selenium/webdriver/safari/conftest.py", "test/selenium/webdriver/support/__init__.py", - "test/selenium/webdriver/support/conftest.py", ], data = [ "pyproject.toml", @@ -547,6 +545,7 @@ py_test_suite( srcs = glob( [ "test/selenium/webdriver/common/**/*.py", + "test/selenium/webdriver/remote/**/*.py", "test/selenium/webdriver/support/**/*.py", ], exclude = BIDI_TESTS, diff --git a/py/conftest.py b/py/conftest.py index 71d7103bbb045..b076e18313e71 100644 --- a/py/conftest.py +++ b/py/conftest.py @@ -96,6 +96,11 @@ def pytest_ignore_collect(path, config): return len([d for d in _drivers if d.lower() in parts]) > 0 +def pytest_generate_tests(metafunc): + if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: + metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) + + def get_driver_class(driver_option): """Generate the driver class name from the lowercase driver option.""" if driver_option == "webkitgtk": @@ -113,9 +118,16 @@ def get_driver_class(driver_option): @pytest.fixture(scope="function") def driver(request): kwargs = {} + driver_option = getattr(request, "param", "Chrome") + # browser can be changed with `--driver=firefox` as an argument or to addopts in pytest.ini - driver_class = get_driver_class(getattr(request, "param", "Chrome")) - # skip tests if not available on the platform + driver_class = get_driver_class(driver_option) + + # skip tests in the 'remote' directory if run with a local driver + if request.node.path.parts[-2] == "remote" and driver_class != "Remote": + pytest.skip(f"Remote tests can't be run with driver '{driver_option}'") + + # skip tests that can't run on certain platforms _platform = platform.system() if driver_class == "Safari" and _platform != "Darwin": pytest.skip("Safari tests can only run on an Apple OS") @@ -123,10 +135,12 @@ def driver(request): pytest.skip("IE and EdgeHTML Tests can only run on Windows") if "WebKit" in driver_class and _platform == "Windows": pytest.skip("WebKit tests cannot be run on Windows") + # skip tests for drivers that don't support BiDi when --bidi is enabled if request.config.option.bidi: if driver_class in ("Ie", "Safari", "WebKitGTK", "WPEWebKit"): pytest.skip(f"{driver_class} does not support BiDi") + # conditionally mark tests as expected to fail based on driver marker = request.node.get_closest_marker(f"xfail_{driver_class.lower()}") @@ -177,6 +191,7 @@ def fin(): kwargs["options"] = options driver_instance = getattr(webdriver, driver_class)(**kwargs) + yield driver_instance # Close the browser after BiDi tests. Those make event subscriptions # and doesn't seems to be stable enough, causing the flakiness of the @@ -217,7 +232,6 @@ def get_options(driver_class, config): if headless: if not options: options = getattr(webdriver, f"{driver_class}Options")() - if driver_class == "Chrome" or driver_class == "Edge": options.add_argument("--headless=new") if driver_class == "Firefox": @@ -226,7 +240,6 @@ def get_options(driver_class, config): if bidi: if not options: options = getattr(webdriver, f"{driver_class}Options")() - options.web_socket_url = True options.unhandled_prompt_behavior = "ignore" @@ -382,3 +395,11 @@ def clean_driver(request): if request.node.get_closest_marker("no_driver_after_test"): driver_reference = None + + +@pytest.fixture +def firefox_options(request): + options = webdriver.FirefoxOptions() + if request.config.option.headless: + options.add_argument("-headless") + return options diff --git a/py/test/selenium/webdriver/chrome/conftest.py b/py/test/selenium/webdriver/chrome/conftest.py deleted file mode 100644 index 043b7df7e146f..0000000000000 --- a/py/test/selenium/webdriver/chrome/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - - -def pytest_generate_tests(metafunc): - if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: - metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) diff --git a/py/test/selenium/webdriver/common/conftest.py b/py/test/selenium/webdriver/common/conftest.py deleted file mode 100644 index 043b7df7e146f..0000000000000 --- a/py/test/selenium/webdriver/common/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - - -def pytest_generate_tests(metafunc): - if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: - metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) diff --git a/py/test/selenium/webdriver/edge/conftest.py b/py/test/selenium/webdriver/edge/conftest.py deleted file mode 100644 index 043b7df7e146f..0000000000000 --- a/py/test/selenium/webdriver/edge/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - - -def pytest_generate_tests(metafunc): - if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: - metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) diff --git a/py/test/selenium/webdriver/firefox/firefox_sizing_tests.py b/py/test/selenium/webdriver/firefox/firefox_sizing_tests.py index fa417a3d782d7..ce157bd7edfb2 100644 --- a/py/test/selenium/webdriver/firefox/firefox_sizing_tests.py +++ b/py/test/selenium/webdriver/firefox/firefox_sizing_tests.py @@ -22,7 +22,6 @@ import pytest from selenium import webdriver -from selenium.webdriver.firefox.options import Options def is_running_wayland(): @@ -30,33 +29,20 @@ def is_running_wayland(): @pytest.mark.skipif(not is_running_wayland(), reason="This test only runs on Linux under Wayland") -def test_firefox_opens_large_when_running_xwayland(request): # noqa: F821 - options = Options() - if request.config.getoption("--headless"): - options.add_argument("-headless") +def test_firefox_opens_large_when_running_xwayland(firefox_options): # setting environment variable `MOZ_ENABLE_WAYLAND=0` forces Firefox # to run under XWayland on Wayland based systems with patch.dict("os.environ", {"MOZ_ENABLE_WAYLAND": "0"}): - try: - driver = webdriver.Firefox(options=options) + with webdriver.Firefox(options=firefox_options) as driver: size = driver.get_window_size() assert size["height"] > 500 assert size["width"] > 500 - finally: - driver.quit() @pytest.mark.skipif(not is_running_wayland(), reason="This test only runs on Linux under Wayland") @pytest.mark.xfail(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1959040") -# Firefox opens in a small window when running on Linux/Wayland -def test_firefox_opens_large_when_running_wayland(request): # noqa: F821 - options = Options() - if request.config.getoption("--headless"): - options.add_argument("-headless") - try: - driver = webdriver.Firefox(options=options) +def test_firefox_opens_large_when_running_wayland(firefox_options): + with webdriver.Firefox(options=firefox_options) as driver: size = driver.get_window_size() assert size["height"] > 500 assert size["width"] > 500 - finally: - driver.quit() diff --git a/py/test/selenium/webdriver/remote/remote_connection_tests.py b/py/test/selenium/webdriver/remote/remote_connection_tests.py index e4046aff719a4..438bc26cb0c42 100644 --- a/py/test/selenium/webdriver/remote/remote_connection_tests.py +++ b/py/test/selenium/webdriver/remote/remote_connection_tests.py @@ -14,12 +14,14 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + import base64 import filetype def test_browser_specific_method(driver, pages): + """This only works on Firefox""" pages.load("simpleTest.html") screenshot = driver.execute("FULL_PAGE_SCREENSHOT")["value"] result = base64.b64decode(screenshot) diff --git a/py/test/selenium/webdriver/remote/custom_element_tests.py b/py/test/selenium/webdriver/remote/remote_custom_element_tests.py similarity index 78% rename from py/test/selenium/webdriver/remote/custom_element_tests.py rename to py/test/selenium/webdriver/remote/remote_custom_element_tests.py index 3fccb52ad3119..12a82e16fd79c 100644 --- a/py/test/selenium/webdriver/remote/custom_element_tests.py +++ b/py/test/selenium/webdriver/remote/remote_custom_element_tests.py @@ -14,6 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +import pytest + from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @@ -24,20 +27,27 @@ def custom_method(self): return "Custom element method" -def test_find_element_with_custom_class(driver, pages): +@pytest.fixture() +def custom_element_driver(driver): + try: + driver._web_element_cls = MyCustomElement + yield driver + finally: + driver._web_element_cls = WebElement + + +def test_find_element_with_custom_class(custom_element_driver, pages): """Test to ensure custom element class is used for a single element.""" - driver._web_element_cls = MyCustomElement pages.load("simpleTest.html") - element = driver.find_element(By.TAG_NAME, "body") + element = custom_element_driver.find_element(By.TAG_NAME, "body") assert isinstance(element, MyCustomElement) assert element.custom_method() == "Custom element method" -def test_find_elements_with_custom_class(driver, pages): +def test_find_elements_with_custom_class(custom_element_driver, pages): """Test to ensure custom element class is used for multiple elements.""" - driver._web_element_cls = MyCustomElement pages.load("simpleTest.html") - elements = driver.find_elements(By.TAG_NAME, "div") + elements = custom_element_driver.find_elements(By.TAG_NAME, "div") assert all(isinstance(el, MyCustomElement) for el in elements) assert all(el.custom_method() == "Custom element method" for el in elements) diff --git a/py/test/selenium/webdriver/remote/remote_custom_locator_tests.py b/py/test/selenium/webdriver/remote/remote_custom_locator_tests.py index e235f2ee2e999..efa0463148856 100644 --- a/py/test/selenium/webdriver/remote/remote_custom_locator_tests.py +++ b/py/test/selenium/webdriver/remote/remote_custom_locator_tests.py @@ -14,6 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +import pytest + +from selenium import webdriver from selenium.webdriver.remote.locator_converter import LocatorConverter @@ -25,16 +29,25 @@ def convert(self, by, value): return super().convert(by, value) -def test_find_element_with_custom_locator(driver): - driver.get("data:text/html,
Test
") - element = driver.find_element("custom", "example") +@pytest.fixture() +def custom_locator_driver(firefox_options): + driver = webdriver.Remote(options=firefox_options, locator_converter=CustomLocatorConverter()) + yield driver + driver.quit() + + +def test_find_element_with_custom_locator(custom_locator_driver): + custom_locator_driver.get("data:text/html,
Test
") + element = custom_locator_driver.find_element("custom", "example") assert element is not None assert element.text == "Test" -def test_find_elements_with_custom_locator(driver): - driver.get("data:text/html,
Test1
Test2
") - elements = driver.find_elements("custom", "example") +def test_find_elements_with_custom_locator(custom_locator_driver): + custom_locator_driver.get( + "data:text/html,
Test1
Test2
" + ) + elements = custom_locator_driver.find_elements("custom", "example") assert len(elements) == 2 assert elements[0].text == "Test1" assert elements[1].text == "Test2" diff --git a/py/test/selenium/webdriver/remote/remote_downloads_tests.py b/py/test/selenium/webdriver/remote/remote_downloads_tests.py index faa7fd996ecd8..5a8ed7f1fcbd4 100644 --- a/py/test/selenium/webdriver/remote/remote_downloads_tests.py +++ b/py/test/selenium/webdriver/remote/remote_downloads_tests.py @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + import os import tempfile diff --git a/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py b/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py index 6d5c1d0cb54df..70b1d49b59be9 100644 --- a/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py +++ b/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py @@ -15,26 +15,13 @@ # specific language governing permissions and limitations # under the License. -import pytest - from selenium import webdriver +from selenium.webdriver.firefox.firefox_profile import FirefoxProfile -@pytest.fixture -def driver(options): - with pytest.warns(None) as record: - driver = webdriver.Remote(options=options) - assert len(record) == 0 - yield driver - driver.quit() - - -@pytest.fixture -def options(): - options = webdriver.FirefoxOptions() - options.set_preference("browser.startup.homepage", "about:") - return options - - -def test_profile_is_used(driver): - assert "about:blank" == driver.current_url or "about:" == driver.current_url +def test_profile_is_used(firefox_options): + ff_profile = FirefoxProfile() + ff_profile.set_preference("browser.startup.page", "1") + firefox_options.profile = ff_profile + with webdriver.Remote(options=firefox_options) as driver: + assert "browser/content/blanktab.html" in driver.current_url diff --git a/py/test/selenium/webdriver/remote/remote_hub_connection.py b/py/test/selenium/webdriver/remote/remote_hub_connection.py index 2a70fe0bad826..5540444b941fa 100644 --- a/py/test/selenium/webdriver/remote/remote_hub_connection.py +++ b/py/test/selenium/webdriver/remote/remote_hub_connection.py @@ -19,10 +19,14 @@ import urllib3 from selenium import webdriver +from selenium.webdriver.firefox.options import Options def test_command_executor_ssl_certificate_is_verified(): + options = Options() + site = "wrong.host.badssl.com" with pytest.raises(urllib3.exceptions.MaxRetryError) as excinfo: - webdriver.Remote(command_executor="https://wrong.host.badssl.com/") + webdriver.Remote(command_executor="https://wrong.host.badssl.com/", options=options) assert isinstance(excinfo.value.reason, urllib3.exceptions.SSLError) - assert "doesn't match" in str(excinfo.value) + assert site in str(excinfo.value) + assert "certificate is not valid" in str(excinfo.value).lower() diff --git a/py/test/selenium/webdriver/support/conftest.py b/py/test/selenium/webdriver/support/conftest.py deleted file mode 100644 index 043b7df7e146f..0000000000000 --- a/py/test/selenium/webdriver/support/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - - -def pytest_generate_tests(metafunc): - if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: - metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True)