Skip to content

Commit

Permalink
Test iframe submission
Browse files Browse the repository at this point in the history
extend testdriver bidi with required methods
  • Loading branch information
sadym-chromium committed Apr 16, 2024
1 parent 8b261c9 commit 084605a
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Test console log are present</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>

<iframe src="support/iframe_sandbox_006.htm" sandbox="allow-forms"></iframe>
<script type="text/javascript">
promise_test(async () => {
const tree = await test_driver.bidi.browsing_context.get_tree({root: window});
const iframe = tree[0].children[0];
const submit_button_selector_result = await test_driver.bidi.browsing_context.locate_nodes({
context: iframe.context,
locator: {type: "css", value: "#submitButton"}
});
const submit_button_shared_id = submit_button_selector_result.nodes[0].sharedId;
await test_driver.bidi.input.click({
context: iframe.context,
origin: {
type: "element",
element: {
sharedId: submit_button_shared_id
}
}
});

// Wait is required to avoid false-negative.
// TODO: replace wait with a more efficient method.
await new Promise(resolve => setTimeout(resolve, 300));

const success_message_selector_result = await test_driver.bidi.browsing_context.locate_nodes({
context: iframe.context,
locator: {type: "innerText", value: "PASS!!!"}
});

assert_equals(success_message_selector_result.nodes.length, 1);
assert_equals(success_message_selector_result.nodes[0].value.attributes.style, 'color: Green');
}, "Allow form submission inside sandbox iframe when sandbox='allow-forms'.");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Test console log are present</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>

<iframe src="support/iframe_sandbox_007.htm" sandbox="allow-scripts allow-same-origin allow-top-navigation"></iframe>
<script type="text/javascript">
promise_test(async () => {
const tree = await test_driver.bidi.browsing_context.get_tree({root: window});
const iframe = tree[0].children[0];
const submit_button_selector_result = await test_driver.bidi.browsing_context.locate_nodes({
context: iframe.context,
locator: {type: "css", value: "#submitButton"}
});
const submit_button_shared_id = submit_button_selector_result.nodes[0].sharedId;
await test_driver.bidi.input.click({
context: iframe.context,
origin: {
type: "element",
element: {
sharedId: submit_button_shared_id
}
}
});

const success_message_selector_result = await test_driver.bidi.browsing_context.locate_nodes({
context: iframe.context,
locator: {type: "innerText", value: "PASS!!!"}
});

// Wait is required to avoid false-positive passes.
// TODO: replace wait with a more efficient method.
await new Promise(resolve => setTimeout(resolve, 300));

assert_equals(success_message_selector_result.nodes.length, 0);
}, "Block form submission inside iframe with sandbox attribute.");
</script>
37 changes: 37 additions & 0 deletions resources/testdriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@
Represents `WebDriver BiDi <https://w3c.github.io/webdriver-bidi>`_ protocol.
*/
bidi: {
/**
* `browsingContext <https://w3c.github.io/webdriver-bidi/#module-browsingContext>`_ module.
*/
browsing_context: {
/**
* `browsingContext.getTree <https://w3c.github.io/webdriver-bidi/#command-browsingContext-getTree>`_ command.
* @param {{max_depth?: number, root?: (string | Window)}} props - Parameters for the command.
* @return {Promise<void>}
*/
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 <https://w3c.github.io/webdriver-bidi/#module-input>`_ module.
*/
input: {
click: async function(props) {
return window.test_driver_internal.bidi.input.click(props);
}
},
/**
* `log <https://w3c.github.io/webdriver-bidi/#module-log>`_ module.
*/
Expand Down Expand Up @@ -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 () {
Expand Down
86 changes: 84 additions & 2 deletions tools/wptrunner/wptrunner/executors/asyncactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -12,14 +13,91 @@ 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.
"""
type: Literal["window"]
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"

Expand Down Expand Up @@ -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]
33 changes: 32 additions & 1 deletion tools/wptrunner/wptrunner/executors/executorwebdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
RPHRegistrationsProtocolPart,
FedCMProtocolPart,
VirtualSensorProtocolPart,
BidiBrowsingContextProtocolPart,
BidiEventsProtocolPart,
BidiInputProtocolPart,
BidiScriptProtocolPart,
merge_dicts)

Expand Down Expand Up @@ -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 = []

Expand Down Expand Up @@ -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)
]
Expand Down
37 changes: 35 additions & 2 deletions tools/wptrunner/wptrunner/executors/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down
31 changes: 30 additions & 1 deletion tools/wptrunner/wptrunner/testdriver-extra.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down

0 comments on commit 084605a

Please sign in to comment.