From 14a154cc1a7dda933a9eb99479c77862496129af Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 18:47:55 +0530 Subject: [PATCH 1/9] implement BiDi browser module --- py/selenium/webdriver/common/bidi/browser.py | 201 +++++++++++++++++++ py/selenium/webdriver/remote/webdriver.py | 25 +++ 2 files changed, 226 insertions(+) create mode 100644 py/selenium/webdriver/common/bidi/browser.py diff --git a/py/selenium/webdriver/common/bidi/browser.py b/py/selenium/webdriver/common/bidi/browser.py new file mode 100644 index 0000000000000..fcb7c11bf2116 --- /dev/null +++ b/py/selenium/webdriver/common/bidi/browser.py @@ -0,0 +1,201 @@ +# 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. + +from typing import Dict, List + + +class ClientWindowState: + """Represents a window state.""" + FULLSCREEN = "fullscreen" + MAXIMIZED = "maximized" + MINIMIZED = "minimized" + NORMAL = "normal" + + +class ClientWindowInfo: + """Represents a client window information.""" + + def __init__( + self, + client_window: str, + state: str, + width: int, + height: int, + x: int, + y: int, + active: bool, + ): + self.client_window = client_window + self.state = state + self.width = width + self.height = height + self.x = x + self.y = y + self.active = active + + def get_state(self) -> str: + """Gets the state of the client window. + + Returns: + ------- + str: The state of the client window (one of the ClientWindowState constants). + """ + return self.state + + def get_client_window(self) -> str: + """Gets the client window identifier. + + Returns: + ------- + str: The client window identifier. + """ + return self.client_window + + def get_width(self) -> int: + """Gets the width of the client window. + + Returns: + ------- + int: The width of the client window. + """ + return self.width + + def get_height(self) -> int: + """Gets the height of the client window. + + Returns: + ------- + int: The height of the client window. + """ + return self.height + + def get_x(self) -> int: + """Gets the x coordinate of the client window. + + Returns: + ------- + int: The x coordinate of the client window. + """ + return self.x + + def get_y(self) -> int: + """Gets the y coordinate of the client window. + + Returns: + ------- + int: The y coordinate of the client window. + """ + return self.y + + def is_active(self) -> bool: + """Checks if the client window is active. + + Returns: + ------- + bool: True if the client window is active, False otherwise. + """ + return self.active + + @classmethod + def from_dict(cls, data: Dict) -> "ClientWindowInfo": + """Creates a ClientWindowInfo instance from a dictionary. + + Parameters: + ----------- + data: A dictionary containing the client window information. + + Returns: + ------- + ClientWindowInfo: A new instance of ClientWindowInfo. + """ + return cls( + client_window=data.get("clientWindow"), + state=data.get("state"), + width=data.get("width"), + height=data.get("height"), + x=data.get("x"), + y=data.get("y"), + active=data.get("active"), + ) + + +class Browser: + """ + BiDi implementation of the browser module. + """ + + def __init__(self, conn): + self.conn = conn + + def command_builder(self, method: str, params: Dict = None) -> Dict: + """Build a command iterator to send to the browser. + + Parameters: + ----------- + method: The method to execute. + params: The parameters to pass to the method. Default is None. + """ + if params is None: + params = {} + + command = {"method": method, "params": params} + cmd = yield command + return cmd + + def create_user_context(self) -> str: + """Creates a new user context. + + Returns: + ------- + str: The ID of the created user context. + """ + result = self.conn.execute(self.command_builder("browser.createUserContext", {})) + return result["userContext"] + + def get_user_contexts(self) -> List[str]: + """Gets all user contexts. + + Returns: + ------- + List[str]: A list of user context IDs. + """ + result = self.conn.execute(self.command_builder("browser.getUserContexts", {})) + return [context_info["userContext"] for context_info in result["userContexts"]] + + def remove_user_context(self, user_context_id: str) -> None: + """Removes a user context. + + Parameters: + ----------- + user_context_id: The ID of the user context to remove. + + Raises: + ------ + Exception: If the user context ID is "default" or does not exist. + """ + params = {"userContext": user_context_id} + self.conn.execute(self.command_builder("browser.removeUserContext", params)) + + def get_client_windows(self) -> List[ClientWindowInfo]: + """Gets all client windows. + + Returns: + ------- + List[ClientWindowInfo]: A list of client window information. + """ + result = self.conn.execute(self.command_builder("browser.getClientWindows", {})) + return [ClientWindowInfo.from_dict(window) for window in result["clientWindows"]] diff --git a/py/selenium/webdriver/remote/webdriver.py b/py/selenium/webdriver/remote/webdriver.py index a97952d84383f..2c192673a7089 100644 --- a/py/selenium/webdriver/remote/webdriver.py +++ b/py/selenium/webdriver/remote/webdriver.py @@ -41,6 +41,7 @@ from selenium.common.exceptions import NoSuchCookieException from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException +from selenium.webdriver.common.bidi.browser import Browser from selenium.webdriver.common.bidi.network import Network from selenium.webdriver.common.bidi.script import Script from selenium.webdriver.common.by import By @@ -254,6 +255,7 @@ def __init__( self._websocket_connection = None self._script = None self._network = None + self._browser = None def __repr__(self): return f'<{type(self).__module__}.{type(self).__name__} (session="{self.session_id}")>' @@ -1269,6 +1271,29 @@ def network(self): return self._network + @property + def browser(self): + """Returns a browser module object for BiDi browser commands. + + Returns: + -------- + Browser: an object containing access to BiDi browser commands. + + Examples: + --------- + >>> user_context = driver.browser.create_user_context() + >>> user_contexts = driver.browser.get_user_contexts() + >>> client_windows = driver.browser.get_client_windows() + >>> driver.browser.remove_user_context(user_context) + """ + if not self._websocket_connection: + self._start_bidi() + + if self._browser is None: + self._browser = Browser(self._websocket_connection) + + return self._browser + def _get_cdp_details(self): import json From 23ae0caa91001790d70da6b26ef30387fe003b09 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 18:48:14 +0530 Subject: [PATCH 2/9] add test browser tests --- .../webdriver/common/bidi_browser_tests.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 py/test/selenium/webdriver/common/bidi_browser_tests.py diff --git a/py/test/selenium/webdriver/common/bidi_browser_tests.py b/py/test/selenium/webdriver/common/bidi_browser_tests.py new file mode 100644 index 0000000000000..cf460cebcca00 --- /dev/null +++ b/py/test/selenium/webdriver/common/bidi_browser_tests.py @@ -0,0 +1,98 @@ +# 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 pytest + +from selenium.webdriver.common.bidi.browser import ClientWindowInfo, ClientWindowState + + +@pytest.mark.xfail_safari +def test_browser_initialized(driver): + """Test that the browser module is initialized properly.""" + assert driver.browser is not None + + +@pytest.mark.xfail_safari +def test_create_user_context(driver): + """Test creating a user context.""" + user_context = driver.browser.create_user_context() + assert user_context is not None + + # Clean up + driver.browser.remove_user_context(user_context) + + +@pytest.mark.xfail_safari +def test_get_user_contexts(driver): + """Test getting user contexts.""" + user_context1 = driver.browser.create_user_context() + user_context2 = driver.browser.create_user_context() + + user_contexts = driver.browser.get_user_contexts() + # it should be 3 since there is a default user context present, therefore >= 2 + assert len(user_contexts) >= 2 + + # Clean up + driver.browser.remove_user_context(user_context1) + driver.browser.remove_user_context(user_context2) + + +@pytest.mark.xfail_safari +def test_remove_user_context(driver): + """Test removing a user context.""" + user_context1 = driver.browser.create_user_context() + user_context2 = driver.browser.create_user_context() + + user_contexts = driver.browser.get_user_contexts() + assert len(user_contexts) >= 2 + + driver.browser.remove_user_context(user_context2) + + updated_user_contexts = driver.browser.get_user_contexts() + assert user_context1 in updated_user_contexts + assert user_context2 not in updated_user_contexts + + # Clean up + driver.browser.remove_user_context(user_context1) + + +@pytest.mark.xfail_safari +def test_get_client_windows(driver): + """Test getting client windows.""" + client_windows = driver.browser.get_client_windows() + + assert client_windows is not None + assert len(client_windows) > 0 + + window_info = client_windows[0] + assert isinstance(window_info, ClientWindowInfo) + assert window_info.get_client_window() is not None + assert window_info.get_state() is not None + assert isinstance(window_info.get_state(), str) + assert window_info.get_width() > 0 + assert window_info.get_height() > 0 + assert isinstance(window_info.is_active(), bool) + assert window_info.get_x() > 0 + assert window_info.get_y() > 0 + + +@pytest.mark.xfail_safari +def test_client_window_state_constants(driver): + assert ClientWindowState.FULLSCREEN == "fullscreen" + assert ClientWindowState.MAXIMIZED == "maximized" + assert ClientWindowState.MINIMIZED == "minimized" + assert ClientWindowState.NORMAL == "normal" From f37a13ee0d7bd592e3cf3fe901a74cd29346e916 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 18:49:19 +0530 Subject: [PATCH 3/9] run `format.sh` --- py/selenium/webdriver/common/bidi/browser.py | 4 +++- py/test/selenium/webdriver/common/bidi_browser_tests.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/py/selenium/webdriver/common/bidi/browser.py b/py/selenium/webdriver/common/bidi/browser.py index fcb7c11bf2116..8f4bc273a33e4 100644 --- a/py/selenium/webdriver/common/bidi/browser.py +++ b/py/selenium/webdriver/common/bidi/browser.py @@ -15,11 +15,13 @@ # specific language governing permissions and limitations # under the License. -from typing import Dict, List +from typing import Dict +from typing import List class ClientWindowState: """Represents a window state.""" + FULLSCREEN = "fullscreen" MAXIMIZED = "maximized" MINIMIZED = "minimized" diff --git a/py/test/selenium/webdriver/common/bidi_browser_tests.py b/py/test/selenium/webdriver/common/bidi_browser_tests.py index cf460cebcca00..d9174f7a707d7 100644 --- a/py/test/selenium/webdriver/common/bidi_browser_tests.py +++ b/py/test/selenium/webdriver/common/bidi_browser_tests.py @@ -17,7 +17,8 @@ import pytest -from selenium.webdriver.common.bidi.browser import ClientWindowInfo, ClientWindowState +from selenium.webdriver.common.bidi.browser import ClientWindowInfo +from selenium.webdriver.common.bidi.browser import ClientWindowState @pytest.mark.xfail_safari From 386a0dcf21ed632cbf0141f4a63902a8cff3ac29 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 19:09:47 +0530 Subject: [PATCH 4/9] move `command_builder` to `common.py` to avoid function duplication --- py/selenium/webdriver/common/bidi/browser.py | 25 +++-------- py/selenium/webdriver/common/bidi/common.py | 38 +++++++++++++++++ py/selenium/webdriver/common/bidi/network.py | 44 +++++--------------- 3 files changed, 55 insertions(+), 52 deletions(-) create mode 100644 py/selenium/webdriver/common/bidi/common.py diff --git a/py/selenium/webdriver/common/bidi/browser.py b/py/selenium/webdriver/common/bidi/browser.py index 8f4bc273a33e4..6c311ac935caf 100644 --- a/py/selenium/webdriver/common/bidi/browser.py +++ b/py/selenium/webdriver/common/bidi/browser.py @@ -18,6 +18,8 @@ from typing import Dict from typing import List +from selenium.webdriver.common.bidi.common import command_builder + class ClientWindowState: """Represents a window state.""" @@ -143,21 +145,6 @@ class Browser: def __init__(self, conn): self.conn = conn - def command_builder(self, method: str, params: Dict = None) -> Dict: - """Build a command iterator to send to the browser. - - Parameters: - ----------- - method: The method to execute. - params: The parameters to pass to the method. Default is None. - """ - if params is None: - params = {} - - command = {"method": method, "params": params} - cmd = yield command - return cmd - def create_user_context(self) -> str: """Creates a new user context. @@ -165,7 +152,7 @@ def create_user_context(self) -> str: ------- str: The ID of the created user context. """ - result = self.conn.execute(self.command_builder("browser.createUserContext", {})) + result = self.conn.execute(command_builder("browser.createUserContext", {})) return result["userContext"] def get_user_contexts(self) -> List[str]: @@ -175,7 +162,7 @@ def get_user_contexts(self) -> List[str]: ------- List[str]: A list of user context IDs. """ - result = self.conn.execute(self.command_builder("browser.getUserContexts", {})) + result = self.conn.execute(command_builder("browser.getUserContexts", {})) return [context_info["userContext"] for context_info in result["userContexts"]] def remove_user_context(self, user_context_id: str) -> None: @@ -190,7 +177,7 @@ def remove_user_context(self, user_context_id: str) -> None: Exception: If the user context ID is "default" or does not exist. """ params = {"userContext": user_context_id} - self.conn.execute(self.command_builder("browser.removeUserContext", params)) + self.conn.execute(command_builder("browser.removeUserContext", params)) def get_client_windows(self) -> List[ClientWindowInfo]: """Gets all client windows. @@ -199,5 +186,5 @@ def get_client_windows(self) -> List[ClientWindowInfo]: ------- List[ClientWindowInfo]: A list of client window information. """ - result = self.conn.execute(self.command_builder("browser.getClientWindows", {})) + result = self.conn.execute(command_builder("browser.getClientWindows", {})) return [ClientWindowInfo.from_dict(window) for window in result["clientWindows"]] diff --git a/py/selenium/webdriver/common/bidi/common.py b/py/selenium/webdriver/common/bidi/common.py new file mode 100644 index 0000000000000..38a4d7e31d3d5 --- /dev/null +++ b/py/selenium/webdriver/common/bidi/common.py @@ -0,0 +1,38 @@ +# 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. + +from typing import Dict + + +def command_builder(method: str, params: Dict = None) -> Dict: + """Build a command iterator to send to the BiDi protocol. + + Parameters: + ----------- + method: The method to execute. + params: The parameters to pass to the method. Default is None. + + Returns: + -------- + The response from the command execution. + """ + if params is None: + params = {} + + command = {"method": method, "params": params} + cmd = yield command + return cmd diff --git a/py/selenium/webdriver/common/bidi/network.py b/py/selenium/webdriver/common/bidi/network.py index 36a0f9be32677..cecdbfb80d225 100644 --- a/py/selenium/webdriver/common/bidi/network.py +++ b/py/selenium/webdriver/common/bidi/network.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +from selenium.webdriver.common.bidi.common import command_builder + class NetworkEvent: """Represents a network event.""" @@ -51,18 +53,6 @@ def __init__(self, conn): self.callbacks = {} self.subscriptions = {} - def command_builder(self, method, params): - """Build a command iterator to send to the network. - - Parameters: - ---------- - method (str): The method to execute. - params (dict): The parameters to pass to the method. - """ - command = {"method": method, "params": params} - cmd = yield command - return cmd - def _add_intercept(self, phases=[], contexts=None, url_patterns=None): """Add an intercept to the network. @@ -88,7 +78,7 @@ def _add_intercept(self, phases=[], contexts=None, url_patterns=None): params["phases"] = phases else: params["phases"] = ["beforeRequestSent"] - cmd = self.command_builder("network.addIntercept", params) + cmd = command_builder("network.addIntercept", params) result = self.conn.execute(cmd) self.intercepts.append(result["intercept"]) @@ -113,11 +103,11 @@ def _remove_intercept(self, intercept=None): if intercept is None: intercepts_to_remove = self.intercepts.copy() # create a copy before iterating for intercept_id in intercepts_to_remove: # remove all intercepts - self.conn.execute(self.command_builder("network.removeIntercept", {"intercept": intercept_id})) + self.conn.execute(command_builder("network.removeIntercept", {"intercept": intercept_id})) self.intercepts.remove(intercept_id) else: try: - self.conn.execute(self.command_builder("network.removeIntercept", {"intercept": intercept})) + self.conn.execute(command_builder("network.removeIntercept", {"intercept": intercept})) self.intercepts.remove(intercept) except Exception as e: raise Exception(f"Exception: {e}") @@ -192,7 +182,7 @@ def add_request_handler(self, event, callback, url_patterns=None, contexts=None) else: params = {} params["events"] = [event_name] - self.conn.execute(self.command_builder("session.subscribe", params)) + self.conn.execute(command_builder("session.subscribe", params)) self.subscriptions[event_name] = [callback_id] self.callbacks[callback_id] = result["intercept"] @@ -220,7 +210,7 @@ def remove_request_handler(self, event, callback_id): if len(self.subscriptions[event_name]) == 0: params = {} params["events"] = [event_name] - self.conn.execute(self.command_builder("session.unsubscribe", params)) + self.conn.execute(command_builder("session.unsubscribe", params)) del self.subscriptions[event_name] def clear_request_handlers(self): @@ -234,7 +224,7 @@ def clear_request_handlers(self): del self.callbacks[callback_id] params = {} params["events"] = [event_name] - self.conn.execute(self.command_builder("session.unsubscribe", params)) + self.conn.execute(command_builder("session.unsubscribe", params)) self.subscriptions = {} def add_auth_handler(self, username, password): @@ -294,18 +284,6 @@ def __init__( self.timings = timings self.url = url - def command_builder(self, method, params): - """Build a command iterator to send to the network. - - Parameters: - ---------- - method (str): The method to execute. - params (dict): The parameters to pass to the method. - """ - command = {"method": method, "params": params} - cmd = yield command - return cmd - def fail_request(self): """Fail this request.""" @@ -313,7 +291,7 @@ def fail_request(self): raise ValueError("Request not found.") params = {"request": self.request_id} - self.network.conn.execute(self.command_builder("network.failRequest", params)) + self.network.conn.execute(command_builder("network.failRequest", params)) def continue_request(self, body=None, method=None, headers=None, cookies=None, url=None): """Continue after intercepting this request.""" @@ -333,7 +311,7 @@ def continue_request(self, body=None, method=None, headers=None, cookies=None, u if url is not None: params["url"] = url - self.network.conn.execute(self.command_builder("network.continueRequest", params)) + self.network.conn.execute(command_builder("network.continueRequest", params)) def _continue_with_auth(self, username=None, password=None): """Continue with authentication. @@ -358,4 +336,4 @@ def _continue_with_auth(self, username=None, password=None): params["action"] = "provideCredentials" params["credentials"] = {"type": "password", "username": username, "password": password} - self.network.conn.execute(self.command_builder("network.continueWithAuth", params)) + self.network.conn.execute(command_builder("network.continueWithAuth", params)) From 75d465ffdc35cab6b9cb7aa5aeb9bc26b4c82356 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 19:17:37 +0530 Subject: [PATCH 5/9] add `init.py` --- .../selenium/webdriver/common/bidi/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 py/test/selenium/webdriver/common/bidi/__init__.py diff --git a/py/test/selenium/webdriver/common/bidi/__init__.py b/py/test/selenium/webdriver/common/bidi/__init__.py new file mode 100644 index 0000000000000..556d95e81d402 --- /dev/null +++ b/py/test/selenium/webdriver/common/bidi/__init__.py @@ -0,0 +1,17 @@ +# 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. + From 922379fac890bd721a8027c4fe72f20a40dcc1ff Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 19:43:26 +0530 Subject: [PATCH 6/9] move bidi test to `bidi/` directory --- py/test/selenium/webdriver/common/bidi/__init__.py | 1 - .../common/{bidi_browser_tests.py => bidi/browser_tests.py} | 0 .../common/{bidi_network_tests.py => bidi/network_tests.py} | 0 .../common/{bidi_script_tests.py => bidi/script_tests.py} | 0 4 files changed, 1 deletion(-) rename py/test/selenium/webdriver/common/{bidi_browser_tests.py => bidi/browser_tests.py} (100%) rename py/test/selenium/webdriver/common/{bidi_network_tests.py => bidi/network_tests.py} (100%) rename py/test/selenium/webdriver/common/{bidi_script_tests.py => bidi/script_tests.py} (100%) diff --git a/py/test/selenium/webdriver/common/bidi/__init__.py b/py/test/selenium/webdriver/common/bidi/__init__.py index 556d95e81d402..a5b1e6f85a09e 100644 --- a/py/test/selenium/webdriver/common/bidi/__init__.py +++ b/py/test/selenium/webdriver/common/bidi/__init__.py @@ -14,4 +14,3 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - diff --git a/py/test/selenium/webdriver/common/bidi_browser_tests.py b/py/test/selenium/webdriver/common/bidi/browser_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi_browser_tests.py rename to py/test/selenium/webdriver/common/bidi/browser_tests.py diff --git a/py/test/selenium/webdriver/common/bidi_network_tests.py b/py/test/selenium/webdriver/common/bidi/network_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi_network_tests.py rename to py/test/selenium/webdriver/common/bidi/network_tests.py diff --git a/py/test/selenium/webdriver/common/bidi_script_tests.py b/py/test/selenium/webdriver/common/bidi/script_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi_script_tests.py rename to py/test/selenium/webdriver/common/bidi/script_tests.py From 039ad3557db43cf64890198fdf3b1da1a5339e44 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 19:44:08 +0530 Subject: [PATCH 7/9] fix tests --- py/test/selenium/webdriver/common/bidi/browser_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/test/selenium/webdriver/common/bidi/browser_tests.py b/py/test/selenium/webdriver/common/bidi/browser_tests.py index d9174f7a707d7..de3de64191f03 100644 --- a/py/test/selenium/webdriver/common/bidi/browser_tests.py +++ b/py/test/selenium/webdriver/common/bidi/browser_tests.py @@ -87,8 +87,8 @@ def test_get_client_windows(driver): assert window_info.get_width() > 0 assert window_info.get_height() > 0 assert isinstance(window_info.is_active(), bool) - assert window_info.get_x() > 0 - assert window_info.get_y() > 0 + assert window_info.get_x() >= 0 + assert window_info.get_y() >= 0 @pytest.mark.xfail_safari From 82af77135fe54d32029d44bc31b562d749e62ac4 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 20:04:23 +0530 Subject: [PATCH 8/9] check user_context_id for default and raise exception --- py/selenium/webdriver/common/bidi/browser.py | 3 +++ py/test/selenium/webdriver/common/bidi/browser_tests.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/py/selenium/webdriver/common/bidi/browser.py b/py/selenium/webdriver/common/bidi/browser.py index 6c311ac935caf..a32c29847372d 100644 --- a/py/selenium/webdriver/common/bidi/browser.py +++ b/py/selenium/webdriver/common/bidi/browser.py @@ -176,6 +176,9 @@ def remove_user_context(self, user_context_id: str) -> None: ------ Exception: If the user context ID is "default" or does not exist. """ + if user_context_id == "default": + raise Exception("Cannot remove the default user context") + params = {"userContext": user_context_id} self.conn.execute(command_builder("browser.removeUserContext", params)) diff --git a/py/test/selenium/webdriver/common/bidi/browser_tests.py b/py/test/selenium/webdriver/common/bidi/browser_tests.py index de3de64191f03..72d288333f0b4 100644 --- a/py/test/selenium/webdriver/common/bidi/browser_tests.py +++ b/py/test/selenium/webdriver/common/bidi/browser_tests.py @@ -91,6 +91,12 @@ def test_get_client_windows(driver): assert window_info.get_y() >= 0 +@pytest.mark.xfail_safari +def test_raises_exception_when_removing_default_user_context(driver): + with pytest.raises(Exception): + driver.browser.remove_user_context("default") + + @pytest.mark.xfail_safari def test_client_window_state_constants(driver): assert ClientWindowState.FULLSCREEN == "fullscreen" From 0456d1dc1b32a841e757ed4278172ebfd148f14d Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 11 Apr 2025 20:13:51 +0530 Subject: [PATCH 9/9] revert tests relocation since CI is failing --- .../selenium/webdriver/common/bidi/__init__.py | 16 ---------------- .../browser_tests.py => bidi_browser_tests.py} | 0 .../network_tests.py => bidi_network_tests.py} | 0 .../script_tests.py => bidi_script_tests.py} | 0 4 files changed, 16 deletions(-) delete mode 100644 py/test/selenium/webdriver/common/bidi/__init__.py rename py/test/selenium/webdriver/common/{bidi/browser_tests.py => bidi_browser_tests.py} (100%) rename py/test/selenium/webdriver/common/{bidi/network_tests.py => bidi_network_tests.py} (100%) rename py/test/selenium/webdriver/common/{bidi/script_tests.py => bidi_script_tests.py} (100%) diff --git a/py/test/selenium/webdriver/common/bidi/__init__.py b/py/test/selenium/webdriver/common/bidi/__init__.py deleted file mode 100644 index a5b1e6f85a09e..0000000000000 --- a/py/test/selenium/webdriver/common/bidi/__init__.py +++ /dev/null @@ -1,16 +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. diff --git a/py/test/selenium/webdriver/common/bidi/browser_tests.py b/py/test/selenium/webdriver/common/bidi_browser_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi/browser_tests.py rename to py/test/selenium/webdriver/common/bidi_browser_tests.py diff --git a/py/test/selenium/webdriver/common/bidi/network_tests.py b/py/test/selenium/webdriver/common/bidi_network_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi/network_tests.py rename to py/test/selenium/webdriver/common/bidi_network_tests.py diff --git a/py/test/selenium/webdriver/common/bidi/script_tests.py b/py/test/selenium/webdriver/common/bidi_script_tests.py similarity index 100% rename from py/test/selenium/webdriver/common/bidi/script_tests.py rename to py/test/selenium/webdriver/common/bidi_script_tests.py