Bug 1824230 - [wdspec] Add WebDriver BiDi tests for actions on elements in ShadowRoot r=webdriver-reviewers,whimboo

Depends on D182474

Differential Revision: https://phabricator.services.mozilla.com/D182498
This commit is contained in:
Julian Descottes 2023-07-03 08:56:32 +00:00
Родитель ecb0e3716e
Коммит d14b62e23e
9 изменённых файлов: 395 добавлений и 14 удалений

Просмотреть файл

@ -1,4 +1,16 @@
[pointer_pen.py]
[test_pen_pointer_in_shadow_tree[outer-open\]]
expected: FAIL
[test_pen_pointer_in_shadow_tree[outer-closed\]]
expected: FAIL
[test_pen_pointer_in_shadow_tree[inner-open\]]
expected: FAIL
[test_pen_pointer_in_shadow_tree[inner-closed\]]
expected: FAIL
[test_pen_pointer_properties]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1658880
expected: FAIL

Просмотреть файл

@ -2,15 +2,19 @@ import json
from webdriver.bidi.modules.script import ContextTarget
async def get_events(bidi_session, context):
"""Return list of key events recorded on the test_actions.html page."""
async def get_object_from_context(bidi_session, context, object_path):
"""Return a plain JS object from a given context, accessible at the given object_path"""
events_str = await bidi_session.script.evaluate(
expression="JSON.stringify(allEvents.events)",
expression=f"JSON.stringify({object_path})",
target=ContextTarget(context),
await_promise=False,
)
events = json.loads(events_str["value"])
return json.loads(events_str["value"])
async def get_events(bidi_session, context):
"""Return list of key events recorded on the test_actions.html page."""
events = await get_object_from_context(bidi_session, context, "allEvents.events")
# `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in
# test_actions.html), so this converts them back into unicode literals.

Просмотреть файл

@ -1,10 +1,35 @@
from webdriver.bidi.modules.script import ContextTarget
from ... import get_viewport_dimensions, remote_mapping_to_dict
from .. import get_object_from_context
def remote_mapping_to_dict(js_object):
obj = {}
for key, value in js_object:
obj[key] = value["value"]
return obj
async def assert_pointer_events(
bidi_session, context, expected_events, target, pointer_type
):
events = await get_object_from_context(
bidi_session, context["context"], "window.recordedEvents"
)
assert len(events) == len(expected_events)
event_types = [e["type"] for e in events]
assert expected_events == event_types
for e in events:
assert e["target"] == target
assert e["pointerType"] == pointer_type
async def get_inview_center_bidi(bidi_session, context, element):
elem_rect = await get_element_rect(bidi_session, context=context, element=element)
viewport_rect = await get_viewport_dimensions(bidi_session, context=context)
viewport_rect = await get_viewport_rect(bidi_session, context=context)
x = {
"left": max(0, min(elem_rect["x"], elem_rect["x"] + elem_rect["width"])),
@ -39,3 +64,68 @@ el => el.getBoundingClientRect().toJSON()
)
return remote_mapping_to_dict(result["value"])
async def get_shadow_root_from_test_page(bidi_session, context, nested=False):
custom_element = await bidi_session.script.call_function(
function_declaration="""() => document.querySelector("custom-element")""",
target=ContextTarget(context["context"]),
await_promise=False,
)
shadow_root = custom_element["value"]["shadowRoot"]
if nested:
custom_element = await bidi_session.script.call_function(
function_declaration="""shadowRoot => shadowRoot.querySelector("inner-custom-element")""",
target=ContextTarget(context["context"]),
arguments=[shadow_root],
await_promise=False,
)
shadow_root = custom_element["value"]["shadowRoot"]
return shadow_root
async def get_viewport_rect(bidi_session, context):
expression = """
({
height: window.innerHeight || document.documentElement.clientHeight,
width: window.innerWidth || document.documentElement.clientWidth,
});
"""
result = await bidi_session.script.evaluate(
expression=expression,
target=ContextTarget(context["context"]),
await_promise=False,
)
return remote_mapping_to_dict(result["value"])
async def record_pointer_events(bidi_session, context, container, selector):
# Record basic mouse / pointer events on the element matching the given
# selector in the container.
# The serialized element will be returned
target = await bidi_session.script.call_function(
function_declaration=f"""container => {{
const target = container.querySelector("{selector}");
window.recordedEvents = [];
function onPointerEvent(event) {{
window.recordedEvents.push({{
"type": event.type,
"pointerType": event.pointerType,
"target": event.target.id
}});
}}
target.addEventListener("pointerdown", onPointerEvent);
target.addEventListener("pointerup", onPointerEvent);
return target;
}}
""",
arguments=[container],
target=ContextTarget(context["context"]),
await_promise=False,
)
return target

Просмотреть файл

@ -1,9 +1,11 @@
import pytest
from webdriver.bidi.modules.input import Actions
from webdriver.bidi.modules.script import ContextTarget
from tests.support.keys import Keys
from .. import get_keys_value
from . import get_shadow_root_from_test_page
pytestmark = pytest.mark.asyncio
@ -45,6 +47,48 @@ async def test_key_codepoint(
assert keys_value == value
@pytest.mark.parametrize("mode", ["open", "closed"])
@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
async def test_key_shadow_tree(bidi_session, top_context, get_test_page, mode, nested):
await bidi_session.browsing_context.navigate(
context=top_context["context"],
url=get_test_page(
shadow_doc="<div><input type=text></div>",
shadow_root_mode=mode,
nested_shadow_dom=nested,
),
wait="complete",
)
shadow_root = await get_shadow_root_from_test_page(bidi_session, top_context, nested)
input_el = await bidi_session.script.call_function(
function_declaration=f"""shadowRoot => {{
const input = shadowRoot.querySelector('input');
input.focus();
return input;
}}
""",
arguments=[shadow_root],
target=ContextTarget(top_context["context"]),
await_promise=False,
)
actions = Actions()
(actions.add_key().key_down("a").key_up("a"))
await bidi_session.input.perform_actions(
actions=actions, context=top_context["context"]
)
input_value = await bidi_session.script.call_function(
function_declaration="input => input.value",
arguments=[input_el],
target=ContextTarget(top_context["context"]),
await_promise=False,
)
assert input_value["value"] == "a"
async def test_null_response_value(bidi_session, top_context):
actions = Actions()
actions.add_key().key_down("a").key_up("a")

Просмотреть файл

@ -75,9 +75,7 @@ async def test_non_printable_key_sends_events(
(Keys.R_SHIFT, "R_SHIFT"),
],
)
async def test_key_modifier_key(
bidi_session, top_context, setup_key_test, key, event
):
async def test_key_modifier_key(bidi_session, top_context, setup_key_test, key, event):
code = ALL_EVENTS[event]["code"]
value = ALL_EVENTS[event]["key"]

Просмотреть файл

@ -1,12 +1,19 @@
import pytest
from webdriver.bidi.modules.input import Actions, get_element_origin
from webdriver.bidi.modules.script import ContextTarget
from tests.support.asserts import assert_move_to_coordinates
from tests.support.helpers import filter_dict
from .. import get_events
from . import get_element_rect, get_inview_center_bidi
from . import (
assert_pointer_events,
get_element_rect,
get_inview_center_bidi,
get_shadow_root_from_test_page,
record_pointer_events,
)
pytestmark = pytest.mark.asyncio
@ -117,6 +124,53 @@ async def test_click_element_center(
assert e["target"] == "outer"
@pytest.mark.parametrize("mode", ["open", "closed"])
@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
async def test_click_element_in_shadow_tree(
bidi_session, top_context, get_test_page, mode, nested
):
await bidi_session.browsing_context.navigate(
context=top_context["context"],
url=get_test_page(
shadow_doc="""
<div id="pointer-target"
style="width: 10px; height: 10px; background-color:blue;">
</div>""",
shadow_root_mode=mode,
nested_shadow_dom=nested,
),
wait="complete",
)
shadow_root = await get_shadow_root_from_test_page(
bidi_session, top_context, nested
)
target = await record_pointer_events(
bidi_session, top_context, shadow_root, "#pointer-target"
)
actions = Actions()
(
actions.add_pointer()
.pointer_move(x=0, y=0, origin=get_element_origin(target))
.pointer_down(button=0)
.pointer_up(button=0)
)
await bidi_session.input.perform_actions(
actions=actions, context=top_context["context"]
)
await assert_pointer_events(
bidi_session,
top_context,
expected_events=["pointerdown", "pointerup"],
target="pointer-target",
pointer_type="mouse",
)
async def test_click_navigation(
bidi_session,
top_context,

Просмотреть файл

@ -1,13 +1,67 @@
import pytest
from webdriver.bidi.modules.input import Actions, get_element_origin
from webdriver.bidi.modules.script import ContextTarget
from .. import get_events
from . import get_inview_center_bidi
from . import (
assert_pointer_events,
get_inview_center_bidi,
get_shadow_root_from_test_page,
record_pointer_events,
)
pytestmark = pytest.mark.asyncio
@pytest.mark.parametrize("mode", ["open", "closed"])
@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
async def test_pen_pointer_in_shadow_tree(
bidi_session, top_context, get_test_page, mode, nested
):
await bidi_session.browsing_context.navigate(
context=top_context["context"],
url=get_test_page(
shadow_doc="""
<div id="pointer-target"
style="width: 10px; height: 10px; background-color:blue;">
</div>""",
shadow_root_mode=mode,
nested_shadow_dom=nested,
),
wait="complete",
)
shadow_root = await get_shadow_root_from_test_page(
bidi_session, top_context, nested
)
# Add a simplified event recorder to track events in the test ShadowRoot.
target = await record_pointer_events(
bidi_session, top_context, shadow_root, "#pointer-target"
)
actions = Actions()
(
actions.add_pointer(pointer_type="pen")
.pointer_move(x=0, y=0, origin=get_element_origin(target))
.pointer_down(button=0)
.pointer_up(button=0)
)
await bidi_session.input.perform_actions(
actions=actions, context=top_context["context"]
)
await assert_pointer_events(
bidi_session,
top_context,
expected_events=["pointerdown", "pointerup"],
target="pointer-target",
pointer_type="pen",
)
async def test_pen_pointer_properties(
bidi_session, top_context, get_element, load_static_test_page
):

Просмотреть файл

@ -1,13 +1,67 @@
import pytest
from webdriver.bidi.modules.input import Actions, get_element_origin
from webdriver.bidi.modules.script import ContextTarget
from .. import get_events
from . import get_inview_center_bidi
from . import (
assert_pointer_events,
get_inview_center_bidi,
get_shadow_root_from_test_page,
record_pointer_events,
)
pytestmark = pytest.mark.asyncio
@pytest.mark.parametrize("mode", ["open", "closed"])
@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
async def test_touch_pointer_in_shadow_tree(
bidi_session, top_context, get_test_page, mode, nested
):
await bidi_session.browsing_context.navigate(
context=top_context["context"],
url=get_test_page(
shadow_doc="""
<div id="pointer-target"
style="width: 10px; height: 10px; background-color:blue;">
</div>""",
shadow_root_mode=mode,
nested_shadow_dom=nested,
),
wait="complete",
)
shadow_root = await get_shadow_root_from_test_page(
bidi_session, top_context, nested
)
# Add a simplified event recorder to track events in the test ShadowRoot.
target = await record_pointer_events(
bidi_session, top_context, shadow_root, "#pointer-target"
)
actions = Actions()
(
actions.add_pointer(pointer_type="touch")
.pointer_move(x=0, y=0, origin=get_element_origin(target))
.pointer_down(button=0)
.pointer_up(button=0)
)
await bidi_session.input.perform_actions(
actions=actions, context=top_context["context"]
)
await assert_pointer_events(
bidi_session,
top_context,
expected_events=["pointerdown", "pointerup"],
target="pointer-target",
pointer_type="touch",
)
async def test_touch_pointer_properties(
bidi_session, top_context, get_element, load_static_test_page
):

Просмотреть файл

@ -1,7 +1,10 @@
import pytest
from webdriver.bidi.modules.input import Actions, get_element_origin
from .. import get_events
from webdriver.bidi.modules.script import ContextTarget
from .. import get_events, get_object_from_context
from . import get_shadow_root_from_test_page
pytestmark = pytest.mark.asyncio
@ -79,3 +82,71 @@ async def test_wheel_scroll_overflow(
assert events[0]["deltaY"] >= delta_y
assert events[0]["deltaZ"] == 0
assert events[0]["target"] == "scrollContent"
@pytest.mark.parametrize("mode", ["open", "closed"])
@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
async def test_wheel_scroll_shadow_tree(
bidi_session, top_context, get_test_page, mode, nested
):
await bidi_session.browsing_context.navigate(
context=top_context["context"],
url=get_test_page(
shadow_doc="""
<div id="scrollableShadowTree"
style="width: 100px; height: 100px; overflow: auto;">
<div
id="scrollableShadowTreeContent"
style="width: 600px; height: 1000px; background-color:blue"></div>
</div>""",
shadow_root_mode=mode,
nested_shadow_dom=nested,
),
wait="complete",
)
shadow_root = await get_shadow_root_from_test_page(bidi_session, top_context, nested)
# Add a simplified event recorder to track events in the test ShadowRoot.
scrollable = await bidi_session.script.call_function(
function_declaration=f"""shadowRoot => {{
window.wheelEvents = [];
const scrollable = shadowRoot.querySelector("#scrollableShadowTree");
scrollable.addEventListener("wheel",
function(event) {{
window.wheelEvents.push({{
"deltaX": event.deltaX,
"deltaY": event.deltaY,
"target": event.target.id
}});
}}
);
return scrollable;
}}
""",
arguments=[shadow_root],
target=ContextTarget(top_context["context"]),
await_promise=False,
)
actions = Actions()
actions.add_wheel().scroll(
x=0,
y=0,
delta_x=5,
delta_y=10,
origin=get_element_origin(scrollable),
)
await bidi_session.input.perform_actions(
actions=actions, context=top_context["context"]
)
events = await get_object_from_context(
bidi_session, top_context["context"], "window.wheelEvents"
)
assert len(events) == 1
assert events[0]["deltaX"] >= 5
assert events[0]["deltaY"] >= 10
assert events[0]["target"] == "scrollableShadowTreeContent"