diff --git a/py/conftest.py b/py/conftest.py index fd1b28d6bebc9..c790b27a489c0 100644 --- a/py/conftest.py +++ b/py/conftest.py @@ -443,6 +443,19 @@ def clean_driver(request): except (AttributeError, TypeError): raise Exception("This test requires a --driver to be specified.") driver_reference = getattr(webdriver, driver_class) + + # conditionally mark tests as expected to fail based on driver + marker = request.node.get_closest_marker(f"xfail_{driver_class.lower()}") + if marker is not None: + if "run" in marker.kwargs: + if marker.kwargs["run"] is False: + pytest.skip() + yield + return + if "raises" in marker.kwargs: + marker.kwargs.pop("raises") + pytest.xfail(**marker.kwargs) + yield driver_reference if request.node.get_closest_marker("no_driver_after_test"): driver_reference = None diff --git a/py/selenium/webdriver/remote/webdriver.py b/py/selenium/webdriver/remote/webdriver.py index 07627a488a10e..b90ae35d703a0 100644 --- a/py/selenium/webdriver/remote/webdriver.py +++ b/py/selenium/webdriver/remote/webdriver.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - """The WebDriver implementation.""" import base64 @@ -75,7 +74,6 @@ from .websocket_connection import WebSocketConnection cdp = None -devtools = None def import_cdp(): @@ -267,6 +265,7 @@ def __init__( self._storage = None self._webextension = None self._permissions = None + self._devtools = None def __repr__(self): return f'<{type(self).__module__}.{type(self).__name__} (session="{self.session_id}")>' @@ -1182,32 +1181,28 @@ def orientation(self, value) -> None: raise WebDriverException("You can only set the orientation to 'LANDSCAPE' and 'PORTRAIT'") def start_devtools(self): - global devtools - if self._websocket_connection: - return devtools, self._websocket_connection + global cdp + import_cdp() + if self.caps.get("se:cdp"): + ws_url = self.caps.get("se:cdp") + version = self.caps.get("se:cdpVersion").split(".")[0] else: - global cdp - import_cdp() - - if not devtools: - if self.caps.get("se:cdp"): - ws_url = self.caps.get("se:cdp") - version = self.caps.get("se:cdpVersion").split(".")[0] - else: - version, ws_url = self._get_cdp_details() - - if not ws_url: - raise WebDriverException("Unable to find url to connect to from capabilities") - - devtools = cdp.import_devtools(version) - if self.caps["browserName"].lower() == "firefox": - raise RuntimeError("CDP support for Firefox has been removed. Please switch to WebDriver BiDi.") - self._websocket_connection = WebSocketConnection(ws_url) - targets = self._websocket_connection.execute(devtools.target.get_targets()) - target_id = targets[0].target_id - session = self._websocket_connection.execute(devtools.target.attach_to_target(target_id, True)) - self._websocket_connection.session_id = session - return devtools, self._websocket_connection + version, ws_url = self._get_cdp_details() + + if not ws_url: + raise WebDriverException("Unable to find url to connect to from capabilities") + + self._devtools = cdp.import_devtools(version) + if self._websocket_connection: + return self._devtools, self._websocket_connection + if self.caps["browserName"].lower() == "firefox": + raise RuntimeError("CDP support for Firefox has been removed. Please switch to WebDriver BiDi.") + self._websocket_connection = WebSocketConnection(ws_url) + targets = self._websocket_connection.execute(self._devtools.target.get_targets()) + target_id = targets[0].target_id + session = self._websocket_connection.execute(self._devtools.target.attach_to_target(target_id, True)) + self._websocket_connection.session_id = session + return self._devtools, self._websocket_connection @asynccontextmanager async def bidi_connection(self): @@ -1282,9 +1277,8 @@ def browser(self): @property def _session(self): - """ - Returns the BiDi session object for the current WebDriver session. - """ + """Returns the BiDi session object for the current WebDriver + session.""" if not self._websocket_connection: self._start_bidi() @@ -1295,7 +1289,8 @@ def _session(self): @property def browsing_context(self): - """Returns a browsing context module object for BiDi browsing context commands. + """Returns a browsing context module object for BiDi browsing context + commands. Returns: -------- diff --git a/py/test/selenium/webdriver/common/devtools_tests.py b/py/test/selenium/webdriver/common/devtools_tests.py index 8d46f3b2742af..46f35e7672d61 100644 --- a/py/test/selenium/webdriver/common/devtools_tests.py +++ b/py/test/selenium/webdriver/common/devtools_tests.py @@ -38,3 +38,16 @@ def test_check_console_messages(driver, pages, recwarn): assert console_api_calls[0].args[0].value == "I love cheese" assert console_api_calls[1].type_ == "error" assert console_api_calls[1].args[0].value == "I love bread" + + +@pytest.mark.xfail_safari +@pytest.mark.xfail_firefox +@pytest.mark.xfail_remote +def test_check_start_twice(clean_driver, clean_options): + driver1 = clean_driver(options=clean_options) + devtools1, connection1 = driver1.start_devtools() + driver1.quit() + + driver2 = clean_driver(options=clean_options) + devtools2, connection2 = driver2.start_devtools() + driver2.quit()