From 100c03be79937ed44d4ce2ad11b6bfbcc7320cb0 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 24 Oct 2025 14:37:48 +0530 Subject: [PATCH 1/2] add `set_timezone_override` command --- .../webdriver/common/bidi/emulation.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/py/selenium/webdriver/common/bidi/emulation.py b/py/selenium/webdriver/common/bidi/emulation.py index 3c8b609235f37..b9339d33dc190 100644 --- a/py/selenium/webdriver/common/bidi/emulation.py +++ b/py/selenium/webdriver/common/bidi/emulation.py @@ -215,3 +215,38 @@ def set_geolocation_override( params["userContexts"] = user_contexts self.conn.execute(command_builder("emulation.setGeolocationOverride", params)) + + def set_timezone_override( + self, + timezone: Optional[str] = None, + contexts: Optional[list[str]] = None, + user_contexts: Optional[list[str]] = None, + ) -> None: + """Set timezone override for the given contexts or user contexts. + + Parameters: + ----------- + timezone: Timezone identifier (IANA timezone name or offset string like '+01:00'), + 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. + """ + if contexts is not None and user_contexts is not None: + raise ValueError("Cannot specify both contexts and user_contexts") + + if contexts is None and user_contexts is None: + raise ValueError("Must specify either contexts or user_contexts") + + params: dict[str, Any] = {"timezone": timezone} + + if contexts is not None: + params["contexts"] = contexts + elif user_contexts is not None: + params["userContexts"] = user_contexts + + self.conn.execute(command_builder("emulation.setTimezoneOverride", params)) From 3fdaef6a697d79f20b3761a808f7af8eae368c19 Mon Sep 17 00:00:00 2001 From: Navin Chandra Date: Fri, 24 Oct 2025 14:38:09 +0530 Subject: [PATCH 2/2] add tests --- .../webdriver/common/bidi_emulation_tests.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/py/test/selenium/webdriver/common/bidi_emulation_tests.py b/py/test/selenium/webdriver/common/bidi_emulation_tests.py index 8778088615fba..ff4a083be3365 100644 --- a/py/test/selenium/webdriver/common/bidi_emulation_tests.py +++ b/py/test/selenium/webdriver/common/bidi_emulation_tests.py @@ -21,6 +21,22 @@ from selenium.webdriver.common.window import WindowTypes +def get_browser_timezone_string(driver): + result = driver.script._evaluate( + "Intl.DateTimeFormat().resolvedOptions().timeZone", + {"context": driver.current_window_handle}, + await_promise=False, + ) + return result.result["value"] + + +def get_browser_timezone_offset(driver): + result = driver.script._evaluate( + "new Date().getTimezoneOffset()", {"context": driver.current_window_handle}, await_promise=False + ) + return result.result["value"] + + def get_browser_geolocation(driver, user_context=None): origin = driver.execute_script("return window.location.origin;") driver.permissions.set_permission("geolocation", PermissionState.GRANTED, origin, user_context=user_context) @@ -214,3 +230,66 @@ def test_set_geolocation_override_with_error(driver, pages): result = get_browser_geolocation(driver) assert "error" in result, f"Expected geolocation error, got: {result}" + + +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") + + initial_timezone_string = get_browser_timezone_string(driver) + + # Set timezone to Tokyo (UTC+9) + driver.emulation.set_timezone_override(timezone="Asia/Tokyo", contexts=[context_id]) + + timezone_offset = get_browser_timezone_offset(driver) + timezone_string = get_browser_timezone_string(driver) + + # Tokyo is UTC+9, so the offset should be -540 minutes (negative because it's ahead of UTC) + assert timezone_offset == -540, f"Expected timezone offset -540, got: {timezone_offset}" + assert timezone_string == "Asia/Tokyo", f"Expected timezone 'Asia/Tokyo', got: {timezone_string}" + + # Clear the timezone override + driver.emulation.set_timezone_override(timezone=None, contexts=[context_id]) + + # verify setting timezone to None clears the timezone override + timezone_after_clear_with_none = get_browser_timezone_string(driver) + assert timezone_after_clear_with_none == initial_timezone_string + + +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) + + driver.switch_to.window(context_id) + pages.load("blank.html") + + driver.emulation.set_timezone_override(timezone="America/New_York", user_contexts=[user_context]) + + timezone_string = get_browser_timezone_string(driver) + assert timezone_string == "America/New_York", f"Expected timezone 'America/New_York', got: {timezone_string}" + + driver.emulation.set_timezone_override(timezone=None, user_contexts=[user_context]) + + driver.browsing_context.close(context_id) + driver.browser.remove_user_context(user_context) + + +@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") + + # set timezone to India (UTC+05:30) using offset + driver.emulation.set_timezone_override(timezone="+05:30", contexts=[context_id]) + + timezone_offset = get_browser_timezone_offset(driver) + timezone_string = get_browser_timezone_string(driver) + + # India is UTC+05:30, so the offset should be -330 minutes (negative because it's ahead of UTC) + assert timezone_offset == -330, f"Expected timezone offset -540, got: {timezone_offset}" + assert timezone_string == "+05:30", f"Expected timezone '+05:30', got: {timezone_string}" + + driver.emulation.set_timezone_override(timezone=None, contexts=[context_id])