From 81e3d503ca2c1d0a5f899fa0ab440b3764922ae9 Mon Sep 17 00:00:00 2001 From: Maksim Sadym Date: Tue, 16 Apr 2024 15:05:11 +0200 Subject: [PATCH] Test iframe submission extend testdriver bidi with required methods --- .../the-iframe-element/sandbox_006_bidi.htm | 41 +++++++++ .../the-iframe-element/sandbox_007_bidi.htm | 40 +++++++++ resources/testdriver.js | 37 ++++++++ .../wptrunner/executors/asyncactions.py | 86 ++++++++++++++++++- .../wptrunner/executors/executorwebdriver.py | 33 ++++++- .../wptrunner/wptrunner/executors/protocol.py | 37 +++++++- tools/wptrunner/wptrunner/testdriver-extra.js | 31 ++++++- 7 files changed, 299 insertions(+), 6 deletions(-) create mode 100644 html/semantics/embedded-content/the-iframe-element/sandbox_006_bidi.htm create mode 100644 html/semantics/embedded-content/the-iframe-element/sandbox_007_bidi.htm diff --git a/html/semantics/embedded-content/the-iframe-element/sandbox_006_bidi.htm b/html/semantics/embedded-content/the-iframe-element/sandbox_006_bidi.htm new file mode 100644 index 00000000000000..c6b807ee3c6377 --- /dev/null +++ b/html/semantics/embedded-content/the-iframe-element/sandbox_006_bidi.htm @@ -0,0 +1,41 @@ + + +Test console log are present + + + + + + + diff --git a/html/semantics/embedded-content/the-iframe-element/sandbox_007_bidi.htm b/html/semantics/embedded-content/the-iframe-element/sandbox_007_bidi.htm new file mode 100644 index 00000000000000..ccf76008759c16 --- /dev/null +++ b/html/semantics/embedded-content/the-iframe-element/sandbox_007_bidi.htm @@ -0,0 +1,40 @@ + + +Test console log are present + + + + + + + diff --git a/resources/testdriver.js b/resources/testdriver.js index 636bdc4d23aac9..54826cbc723183 100644 --- a/resources/testdriver.js +++ b/resources/testdriver.js @@ -53,6 +53,30 @@ Represents `WebDriver BiDi `_ protocol. */ bidi: { + /** + * `browsingContext `_ module. + */ + browsing_context: { + /** + * `browsingContext.getTree `_ command. + * @param {{max_depth?: number, root?: (string | Window)}} props - Parameters for the command. + * @return {Promise} + */ + get_tree: async function(props) { + return window.test_driver_internal.bidi.browsing_context.get_tree(props); + }, + locate_nodes: async function(props) { + return window.test_driver_internal.bidi.browsing_context.locate_nodes(props); + } + }, + /** + * `input `_ module. + */ + input: { + click: async function(props) { + return window.test_driver_internal.bidi.input.click(props); + } + }, /** * `log `_ module. */ @@ -1075,6 +1099,19 @@ in_automation: false, bidi: { + browsing_context: { + get_tree: function () { + throw new Error("bidi.browsing_context.get_tree is not implemented by testdriver-vendor.js"); + }, + locate_nodes: function () { + throw new Error("bidi.browsing_context.locate_nodes is not implemented by testdriver-vendor.js"); + } + }, + input: { + click: function () { + throw new Error("bidi.browsing_context.get_tree is not implemented by testdriver-vendor.js"); + }, + }, log: { entry_added: { subscribe: function () { diff --git a/tools/wptrunner/wptrunner/executors/asyncactions.py b/tools/wptrunner/wptrunner/executors/asyncactions.py index 735aa017ce1611..3505c363f70a66 100644 --- a/tools/wptrunner/wptrunner/executors/asyncactions.py +++ b/tools/wptrunner/wptrunner/executors/asyncactions.py @@ -2,6 +2,7 @@ import sys from typing import Dict, List, Literal, Optional, Union +from typing_extensions import NotRequired, TypedDict # TODO: check if type annotation is supported by all the required versions of Python. @@ -12,7 +13,7 @@ class WindowProxyProperties(Dict): # TODO: check if type annotation is supported by all the required versions of Python. # noinspection PyCompatibility -class WindowProxyRemoteValue(Dict): +class WindowProxyRemoteValue(TypedDict): """ WebDriver BiDi browsing context descriptor. """ @@ -20,6 +21,83 @@ class WindowProxyRemoteValue(Dict): value: WindowProxyProperties +class BidiBrowsingContextGetTreeAction: + name = "bidi.browsing_context.get_tree" + + # TODO: check if type annotation is supported by all the required versions of Python. + # noinspection PyCompatibility + class Payload(TypedDict): + max_depth: NotRequired[int] + root: NotRequired[Union[WindowProxyRemoteValue, str]] + + def __init__(self, logger, protocol): + self.logger = logger + self.protocol = protocol + + async def __call__(self, payload: Payload): + root = None + if "root" in payload: + root = payload["root"] + if isinstance(root, dict) and "type" in root and root["type"] == "window": + root = root["value"]["context"] + return await self.protocol.bidi_browsing_context.get_tree(root) + + +class BidiBrowsingContextLocateNodesAction: + name = "bidi.browsing_context.locate_nodes" + + # TODO: check if type annotation is supported by all the required versions of Python. + # noinspection PyCompatibility + class Payload(TypedDict): + context: Union[WindowProxyRemoteValue, str] + locator: List[Dict] + + def __init__(self, logger, protocol): + self.logger = logger + self.protocol = protocol + + async def __call__(self, payload: Payload): + context = payload["context"] + if isinstance(context, dict) and "type" in context and context["type"] == "window": + context = context["value"]["context"] + return await self.protocol.bidi_browsing_context.locate_nodes(context, payload["locator"]) + + +# TODO: check if type annotation is supported by all the required versions of Python. +# noinspection PyCompatibility +class SourceActions(TypedDict): + """ + WebDriver BiDi browsing context descriptor. + """ + type: Literal["window"] + value: WindowProxyProperties + + +class BidiInputPerformAction: + name = "bidi.input.perform_actions" + + # TODO: check if type annotation is supported by all the required versions of Python. + # noinspection PyCompatibility + class Payload(TypedDict): + context: Union[str, WindowProxyRemoteValue] + actions: List[Dict] + + def __init__(self, logger, protocol): + self.logger = logger + self.protocol = protocol + + async def __call__(self, payload: Payload): + """ + :param payload: https://w3c.github.io/webdriver-bidi/#command-input-performActions + :return: + """ + context = payload["context"] + if isinstance(context, dict) and "type" in context and context["type"] == "window": + context = context["value"]["context"] + + return await self.protocol.bidi_input.perform_actions(payload["actions"], context) + + class BidiSessionSubscribeAction: name = "bidi.session.subscribe" @@ -54,4 +132,8 @@ async def __call__(self, payload: Payload): return await self.protocol.bidi_events.subscribe(events, contexts) -async_actions = [BidiSessionSubscribeAction] +async_actions = [ + BidiBrowsingContextGetTreeAction, + BidiBrowsingContextLocateNodesAction, + BidiInputPerformAction, + BidiSessionSubscribeAction] diff --git a/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/tools/wptrunner/wptrunner/executors/executorwebdriver.py index c55bbf8a9fd56a..48e96e8763ac64 100644 --- a/tools/wptrunner/wptrunner/executors/executorwebdriver.py +++ b/tools/wptrunner/wptrunner/executors/executorwebdriver.py @@ -37,7 +37,9 @@ RPHRegistrationsProtocolPart, FedCMProtocolPart, VirtualSensorProtocolPart, + BidiBrowsingContextProtocolPart, BidiEventsProtocolPart, + BidiInputProtocolPart, BidiScriptProtocolPart, merge_dicts) @@ -109,6 +111,33 @@ def wait(self): return False +class WebDriverBidiBrowsingContextProtocolPart(BidiBrowsingContextProtocolPart): + def __init__(self, parent): + super().__init__(parent) + self.webdriver = None + + def setup(self): + self.webdriver = self.parent.webdriver + + async def get_tree(self, root=None, max_depth=None): + return await self.webdriver.bidi_session.browsing_context.get_tree(root=root, max_depth=max_depth) + + async def locate_nodes(self, context, locator): + return await self.webdriver.bidi_session.browsing_context.locate_nodes(context=context, locator=locator) + + +class WebDriverBidiInputProtocolPart(BidiInputProtocolPart): + def __init__(self, parent): + super().__init__(parent) + self.webdriver = None + + def setup(self): + self.webdriver = self.parent.webdriver + + async def perform_actions(self, actions, context): + return await self.webdriver.bidi_session.input.perform_actions(context=context, actions=actions) + + class WebDriverBidiEventsProtocolPart(BidiEventsProtocolPart): _subscriptions = [] @@ -569,7 +598,9 @@ def after_connect(self): class WebDriverBidiProtocol(WebDriverProtocol): enable_bidi = True - implements = [WebDriverBidiEventsProtocolPart, + implements = [WebDriverBidiBrowsingContextProtocolPart, + WebDriverBidiEventsProtocolPart, + WebDriverBidiInputProtocolPart, WebDriverBidiScriptProtocolPart, *(part for part in WebDriverProtocol.implements) ] diff --git a/tools/wptrunner/wptrunner/executors/protocol.py b/tools/wptrunner/wptrunner/executors/protocol.py index bc86a024ef60b2..f6fd8f4894030c 100644 --- a/tools/wptrunner/wptrunner/executors/protocol.py +++ b/tools/wptrunner/wptrunner/executors/protocol.py @@ -2,10 +2,9 @@ import traceback from http.client import HTTPConnection -from typing import Any, Awaitable, Callable, Optional, Mapping +from typing import ClassVar, List, Type, Any, Awaitable, Callable, Optional, Mapping from abc import ABCMeta, abstractmethod -from typing import ClassVar, List, Type def merge_dicts(target, source): @@ -322,6 +321,40 @@ def get_computed_role(self, element): pass +class BidiBrowsingContextProtocolPart(ProtocolPart): + """Protocol part for managing BiDi events""" + __metaclass__ = ABCMeta + name = "bidi_browsing_context" + + @abstractmethod + async def get_tree(self, root=None, max_depth=None): + """ + Get the tree of browsing contexts. + :param root: The root of the tree. If `None`, returns all the browsing contexts. + :param max_depth: The maximum depth of the tree to return. If `None`, returns the entire tree. + :return: The tree of browsing contexts. + """ + pass + + @abstractmethod + async def locate_nodes(self, context, locator): + pass + + +class BidiInputProtocolPart(ProtocolPart): + """Protocol part for managing BiDi events""" + __metaclass__ = ABCMeta + name = "bidi_input" + + @abstractmethod + async def perform_actions(self, actions, context): + """ + Perform a sequence of actions in a specific context as specified in + https://w3c.github.io/webdriver-bidi/#command-input-performActions + """ + pass + + class BidiEventsProtocolPart(ProtocolPart): """Protocol part for managing BiDi events""" __metaclass__ = ABCMeta diff --git a/tools/wptrunner/wptrunner/testdriver-extra.js b/tools/wptrunner/wptrunner/testdriver-extra.js index b2bba897c1cd33..9123f362005259 100644 --- a/tools/wptrunner/wptrunner/testdriver-extra.js +++ b/tools/wptrunner/wptrunner/testdriver-extra.js @@ -196,7 +196,36 @@ window.test_driver_internal.in_automation = true; - window.test_driver_internal.bidi.log.entry_added.subscribe = function (props) { + window.test_driver_internal.bidi.browsing_context.get_tree = function (props) { + return create_action("bidi.browsing_context.get_tree", props); + } + window.test_driver_internal.bidi.browsing_context.locate_nodes = function (props) { + return create_action("bidi.browsing_context.locate_nodes", props); + } + + window.test_driver_internal.bidi.input.click = function (props) { + const actions = [{ + type: "pointer", + id: "main_mouse", + actions: [{ + "type": "pointerMove", + "x": 0, + "y": 0, + "origin": props.origin + }, { + "type": "pointerDown", + "button": 0, + }, { + "type": "pointerUp", + "button": 0, + }] + }] + + return create_action("bidi.input.perform_actions", {context: props.context, actions}); + } + + window.test_driver_internal.bidi.log.entry_added. + subscribe = function (props) { return subscribe({ ...(props ?? {}), events: ["log.entryAdded"]