diff --git a/py/selenium/webdriver/common/bidi/emulation.py b/py/selenium/webdriver/common/bidi/emulation.py index 85cd48422229b..9dbc585559aed 100644 --- a/py/selenium/webdriver/common/bidi/emulation.py +++ b/py/selenium/webdriver/common/bidi/emulation.py @@ -35,8 +35,7 @@ def __init__( ): """Initialize GeolocationCoordinates. - Parameters: - ----------- + Args: latitude: Latitude coordinate (-90.0 to 90.0). longitude: Longitude coordinate (-180.0 to 180.0). accuracy: Accuracy in meters (>= 0.0), defaults to 1.0. @@ -46,7 +45,6 @@ def __init__( speed: Speed in meters per second (>= 0.0) or None, defaults to None. Raises: - ------ ValueError: If coordinates are out of valid range or if altitude_accuracy is provided without altitude. """ self.latitude = latitude @@ -180,18 +178,16 @@ def set_geolocation_override( ) -> None: """Set geolocation override for the given contexts or user contexts. - Parameters: - ----------- + Args: coordinates: Geolocation coordinates to emulate, or None. error: Geolocation error to emulate, or None. contexts: List of browsing context IDs to apply the override to. user_contexts: List of user context IDs to apply the override to. Raises: - ------ ValueError: If both coordinates and error are provided, or if both contexts - and user_contexts are provided, or if neither contexts nor - user_contexts are provided. + and user_contexts are provided, or if neither contexts nor + user_contexts are provided. """ if coordinates is not None and error is not None: raise ValueError("Cannot specify both coordinates and error") @@ -224,17 +220,15 @@ def set_timezone_override( ) -> None: """Set timezone override for the given contexts or user contexts. - Parameters: - ----------- + Args: timezone: Timezone identifier (IANA timezone name or offset string like '+01:00'), - or None to clear the override. + or None to clear the override. contexts: List of browsing context IDs to apply the override to. user_contexts: List of user context IDs to apply the override to. Raises: - ------ ValueError: If both contexts and user_contexts are provided, or if neither - contexts nor user_contexts are provided. + contexts nor user_contexts are provided. """ if contexts is not None and user_contexts is not None: raise ValueError("Cannot specify both contexts and user_contexts") @@ -259,16 +253,14 @@ def set_locale_override( ) -> None: """Set locale override for the given contexts or user contexts. - Parameters: - ----------- + Args: locale: Locale string as per BCP 47, or None to clear override. contexts: List of browsing context IDs to apply the override to. user_contexts: List of user context IDs to apply the override to. Raises: - ------ ValueError: If both contexts and user_contexts are provided, or if neither - contexts nor user_contexts are provided, or if locale is invalid. + contexts nor user_contexts are provided, or if locale is invalid. """ if contexts is not None and user_contexts is not None: raise ValueError("Cannot specify both contexts and userContexts") @@ -284,3 +276,39 @@ def set_locale_override( params["userContexts"] = user_contexts self.conn.execute(command_builder("emulation.setLocaleOverride", params)) + + def set_scripting_enabled( + self, + enabled: Union[bool, None] = False, + contexts: Optional[list[str]] = None, + user_contexts: Optional[list[str]] = None, + ) -> None: + """Set scripting enabled override for the given contexts or user contexts. + + Args: + enabled: False to disable scripting, None to clear the override. + Note: Only emulation of disabled JavaScript is supported. + contexts: List of browsing context IDs to apply the override to. + user_contexts: List of user context IDs to apply the override to. + + Raises: + ValueError: If both contexts and user_contexts are provided, or if neither + contexts nor user_contexts are provided, or if enabled is True. + """ + if enabled: + raise ValueError("Only emulation of disabled JavaScript is supported (enabled must be False or None)") + + if contexts is not None and user_contexts is not None: + raise ValueError("Cannot specify both contexts and userContexts") + + if contexts is None and user_contexts is None: + raise ValueError("Must specify either contexts or userContexts") + + params: dict[str, Any] = {"enabled": enabled} + + if contexts is not None: + params["contexts"] = contexts + elif user_contexts is not None: + params["userContexts"] = user_contexts + + self.conn.execute(command_builder("emulation.setScriptingEnabled", params)) diff --git a/py/test/selenium/webdriver/common/bidi_emulation_tests.py b/py/test/selenium/webdriver/common/bidi_emulation_tests.py index 01705b0ae3c6f..49c74ea9ec32a 100644 --- a/py/test/selenium/webdriver/common/bidi_emulation_tests.py +++ b/py/test/selenium/webdriver/common/bidi_emulation_tests.py @@ -74,13 +74,11 @@ def get_browser_locale(driver): def test_emulation_initialized(driver): - """Test that the emulation module is initialized properly.""" assert driver.emulation is not None assert isinstance(driver.emulation, Emulation) def test_set_geolocation_override_with_coordinates_in_context(driver, pages): - """Test setting geolocation override with coordinates.""" context_id = driver.current_window_handle pages.load("blank.html") coords = GeolocationCoordinates(45.5, -122.4194, accuracy=10.0) @@ -96,7 +94,6 @@ def test_set_geolocation_override_with_coordinates_in_context(driver, pages): def test_set_geolocation_override_with_coordinates_in_user_context(driver, pages): - """Test setting geolocation override with coordinates in a user context.""" # Create a user context user_context = driver.browser.create_user_context() @@ -121,7 +118,6 @@ def test_set_geolocation_override_with_coordinates_in_user_context(driver, pages def test_set_geolocation_override_all_coords(driver, pages): - """Test setting geolocation override with coordinates.""" context_id = driver.current_window_handle pages.load("blank.html") coords = GeolocationCoordinates( @@ -147,7 +143,6 @@ def test_set_geolocation_override_all_coords(driver, pages): def test_set_geolocation_override_with_multiple_contexts(driver, pages): - """Test setting geolocation override with multiple browsing contexts.""" # Create two browsing contexts context1_id = driver.browsing_context.create(type=WindowTypes.TAB) context2_id = driver.browsing_context.create(type=WindowTypes.TAB) @@ -181,7 +176,6 @@ def test_set_geolocation_override_with_multiple_contexts(driver, pages): def test_set_geolocation_override_with_multiple_user_contexts(driver, pages): - """Test setting geolocation override with multiple user contexts.""" # Create two user contexts user_context1 = driver.browser.create_user_context() user_context2 = driver.browser.create_user_context() @@ -229,7 +223,6 @@ def test_set_geolocation_override_with_multiple_user_contexts(driver, pages): @pytest.mark.xfail_firefox def test_set_geolocation_override_with_error(driver, pages): - """Test setting geolocation override with error.""" context_id = driver.current_window_handle pages.load("blank.html") @@ -242,7 +235,6 @@ def test_set_geolocation_override_with_error(driver, pages): def test_set_timezone_override_with_context(driver, pages): - """Test setting timezone override with a browsing context.""" context_id = driver.current_window_handle pages.load("blank.html") @@ -267,7 +259,6 @@ def test_set_timezone_override_with_context(driver, pages): def test_set_timezone_override_with_user_context(driver, pages): - """Test setting timezone override with a user context.""" user_context = driver.browser.create_user_context() context_id = driver.browsing_context.create(type=WindowTypes.TAB, user_context=user_context) @@ -287,7 +278,6 @@ def test_set_timezone_override_with_user_context(driver, pages): @pytest.mark.xfail_firefox(reason="Firefox returns UTC as timezone string in case of offset.") def test_set_timezone_override_using_offset(driver, pages): - """Test setting timezone override using offset.""" context_id = driver.current_window_handle pages.load("blank.html") @@ -320,7 +310,6 @@ def test_set_timezone_override_using_offset(driver, pages): ], ) def test_set_locale_override_with_contexts(driver, pages, locale, expected_locale): - """Test setting locale override with browsing contexts.""" context_id = driver.current_window_handle driver.emulation.set_locale_override(locale=locale, contexts=[context_id]) @@ -345,7 +334,6 @@ def test_set_locale_override_with_contexts(driver, pages, locale, expected_local ], ) def test_set_locale_override_with_user_contexts(driver, pages, value): - """Test setting locale override with user contexts.""" user_context = driver.browser.create_user_context() try: context_id = driver.browsing_context.create(type=WindowTypes.TAB, user_context=user_context) @@ -362,3 +350,72 @@ def test_set_locale_override_with_user_contexts(driver, pages, value): driver.browsing_context.close(context_id) finally: driver.browser.remove_user_context(user_context) + + +@pytest.mark.xfail_firefox(reason="Not yet supported") +def test_set_scripting_enabled_with_contexts(driver, pages): + context_id = driver.current_window_handle + + # disable scripting + driver.emulation.set_scripting_enabled(enabled=False, contexts=[context_id]) + + driver.browsing_context.navigate( + context=context_id, + url="data:text/html,", + wait="complete", + ) + result = driver.script._evaluate("'foo' in window", {"context": context_id}, await_promise=False) + assert result.result["value"] is False, "Page script should not have executed when scripting is disabled" + + # clear override via None to restore JS + driver.emulation.set_scripting_enabled(enabled=None, contexts=[context_id]) + driver.browsing_context.navigate( + context=context_id, + url="data:text/html,", + wait="complete", + ) + result = driver.script._evaluate("'foo' in window", {"context": context_id}, await_promise=False) + assert result.result["value"] is True, "Page script should execute after clearing the override" + + +@pytest.mark.xfail_firefox(reason="Not yet supported") +def test_set_scripting_enabled_with_user_contexts(driver, pages): + user_context = driver.browser.create_user_context() + try: + context_id = driver.browsing_context.create(type=WindowTypes.TAB, user_context=user_context) + try: + driver.switch_to.window(context_id) + + driver.emulation.set_scripting_enabled(enabled=False, user_contexts=[user_context]) + + url = pages.url("javascriptPage.html") + driver.browsing_context.navigate(context_id, url, wait="complete") + + # Check that inline event handlers don't work; this page has an onclick handler + click_field = driver.find_element("id", "clickField") + initial_value = click_field.get_attribute("value") # initial value is 'Hello' + click_field.click() + + # Get the value after click, it should remain unchanged if scripting is disabled + result_value = driver.script._evaluate( + "document.getElementById('clickField').value", {"context": context_id}, await_promise=False + ) + assert result_value.result["value"] == initial_value, ( + "Inline onclick handler should not execute, i.e, value should not change to 'clicked'" + ) + + # Clear the scripting override + driver.emulation.set_scripting_enabled(enabled=None, user_contexts=[user_context]) + + driver.browsing_context.navigate(context_id, url, wait="complete") + + # Click the element again, it should change to 'Clicked' now + driver.find_element("id", "clickField").click() + result_value = driver.script._evaluate( + "document.getElementById('clickField').value", {"context": context_id}, await_promise=False + ) + assert result_value.result["value"] == "Clicked" + finally: + driver.browsing_context.close(context_id) + finally: + driver.browser.remove_user_context(user_context)