Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 45 additions & 17 deletions py/selenium/webdriver/common/bidi/emulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand All @@ -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))
81 changes: 69 additions & 12 deletions py/test/selenium/webdriver/common/bidi_emulation_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()

Expand All @@ -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(
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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")

Expand All @@ -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")

Expand All @@ -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)

Expand All @@ -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")

Expand Down Expand Up @@ -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])
Expand All @@ -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)
Expand All @@ -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,<script>window.foo=123;</script>",
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,<script>window.foo=123;</script>",
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)
Loading