Skip to content
30 changes: 21 additions & 9 deletions py/selenium/webdriver/common/bidi/browsing_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
from dataclasses import dataclass
from typing import Any

from typing_extensions import Sentinel

from selenium.webdriver.common.bidi.common import command_builder
from selenium.webdriver.common.bidi.session import Session

UNDEFINED = Sentinel("UNDEFINED")


class ReadinessState:
"""Represents the stage of document loading at which a navigation command will return."""
Expand Down Expand Up @@ -980,30 +984,38 @@ def reload(
def set_viewport(
self,
context: str | None = None,
viewport: dict | None = None,
device_pixel_ratio: float | None = None,
viewport: dict | None | UNDEFINED = UNDEFINED,
device_pixel_ratio: float | None | UNDEFINED = UNDEFINED,
user_contexts: list[str] | None = None,
) -> None:
"""Modifies specific viewport characteristics on the given top-level traversable.

Args:
context: The browsing context ID.
viewport: The viewport parameters.
device_pixel_ratio: The device pixel ratio.
viewport: The viewport parameters - {"width": <int>, "height": <int>} (`None` resets to default).
device_pixel_ratio: The device pixel ratio (`None` resets to default).
user_contexts: The user context IDs.

Raises:
Exception: If the browsing context is not a top-level traversable.
Exception: If the browsing context is not a top-level traversable
ValueError: If neither `context` nor `user_contexts` is provided
ValueError: If both `context` and `user_contexts` are provided
"""
if context is not None and user_contexts is not None:
raise ValueError("Cannot specify both context and user_contexts")

if context is None and user_contexts is None:
raise ValueError("Must specify either context or user_contexts")

params: dict[str, Any] = {}
if context is not None:
params["context"] = context
if viewport is not None:
elif user_contexts is not None:
params["userContexts"] = user_contexts
if viewport is not UNDEFINED:
params["viewport"] = viewport
if device_pixel_ratio is not None:
if device_pixel_ratio is not UNDEFINED:
params["devicePixelRatio"] = device_pixel_ratio
if user_contexts is not None:
params["userContexts"] = user_contexts

self.conn.execute(command_builder("browsingContext.setViewport", params))

Expand Down
79 changes: 67 additions & 12 deletions py/test/selenium/webdriver/common/bidi_browsing_context_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,31 +348,86 @@ def test_set_viewport(driver, pages):
context_id = driver.current_window_handle
driver.get(pages.url("formPage.html"))

driver.browsing_context.set_viewport(context=context_id, viewport={"width": 250, "height": 300})
try:
driver.browsing_context.set_viewport(context=context_id, viewport={"width": 251, "height": 301})

viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")
viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")

assert viewport_size[0] == 250
assert viewport_size[1] == 300
assert viewport_size[0] == 251
assert viewport_size[1] == 301
finally:
driver.browsing_context.set_viewport(context=context_id, viewport=None, device_pixel_ratio=None)


def test_set_viewport_with_device_pixel_ratio(driver, pages):
"""Test setting the viewport with device pixel ratio."""
context_id = driver.current_window_handle
driver.get(pages.url("formPage.html"))

driver.browsing_context.set_viewport(
context=context_id, viewport={"width": 250, "height": 300}, device_pixel_ratio=5
)
try:
driver.browsing_context.set_viewport(
context=context_id, viewport={"width": 252, "height": 302}, device_pixel_ratio=5
)

viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")

assert viewport_size[0] == 252
assert viewport_size[1] == 302

device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")

assert device_pixel_ratio == 5
finally:
driver.browsing_context.set_viewport(context=context_id, viewport=None, device_pixel_ratio=None)


def test_set_viewport_with_no_args_doesnt_change_values(driver, pages):
"""Test setting the viewport with no args doesn't change viewport or device pixel ratio."""
context_id = driver.current_window_handle
driver.get(pages.url("formPage.html"))

try:
driver.browsing_context.set_viewport(
context=context_id, viewport={"width": 253, "height": 303}, device_pixel_ratio=6
)

driver.browsing_context.set_viewport(context=context_id)

viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")

assert viewport_size[0] == 253
assert viewport_size[1] == 303

device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")

assert device_pixel_ratio == 6
finally:
driver.browsing_context.set_viewport(context=context_id, viewport=None, device_pixel_ratio=None)

viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")

assert viewport_size[0] == 250
assert viewport_size[1] == 300
def test_set_viewport_back_to_default(driver, pages):
"""Test resetting the viewport and device pixel ratio to defaults."""
context_id = driver.current_window_handle
driver.get(pages.url("formPage.html"))

default_viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")
default_device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")

try:
driver.browsing_context.set_viewport(
context=context_id, viewport={"width": 254, "height": 304}, device_pixel_ratio=10
)

driver.browsing_context.set_viewport(context=context_id, viewport=None, device_pixel_ratio=None)

device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")
viewport_size = driver.execute_script("return [window.innerWidth, window.innerHeight];")
device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")

assert device_pixel_ratio == 5
assert viewport_size[0] == default_viewport_size[0]
assert viewport_size[1] == default_viewport_size[1]
assert device_pixel_ratio == default_device_pixel_ratio
finally:
driver.browsing_context.set_viewport(context=context_id, viewport=None, device_pixel_ratio=None)


def test_print_page(driver, pages):
Expand Down