[wdspec] Add WebDriver classic tests for actions on elements in ShadowRoot
Differential Revision: https://phabricator.services.mozilla.com/D182474
bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1806897
gecko-commit: fc23046c2b2028181a35cf83a5e8e1c75a2ceaca
gecko-reviewers: webdriver-reviewers, whimboo
diff --git a/webdriver/tests/classic/perform_actions/__init__.py b/webdriver/tests/classic/perform_actions/__init__.py
index 6fec8a8..af87e19 100644
--- a/webdriver/tests/classic/perform_actions/__init__.py
+++ b/webdriver/tests/classic/perform_actions/__init__.py
@@ -1,3 +1,31 @@
+def assert_pointer_events(session, expected_events, target, pointer_type):
+ events = session.execute_script("return 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
+
+
+def record_pointer_events(session, element):
+ # Record basic mouse / pointer events on a given element.
+ session.execute_script(
+ """
+ window.recordedEvents = [];
+ function onPointerEvent(event) {
+ window.recordedEvents.push({
+ "pointerType": event.pointerType,
+ "target": event.target.id,
+ "type": event.type,
+ });
+ }
+ arguments[0].addEventListener("pointerdown", onPointerEvent);
+ arguments[0].addEventListener("pointerup", onPointerEvent);
+ """,
+ args=(element,),
+ )
def perform_actions(session, actions):
return session.transport.send(
"POST",
diff --git a/webdriver/tests/classic/perform_actions/key.py b/webdriver/tests/classic/perform_actions/key.py
index 6c34452..7809fcd 100644
--- a/webdriver/tests/classic/perform_actions/key.py
+++ b/webdriver/tests/classic/perform_actions/key.py
@@ -36,3 +36,27 @@
.perform()
assert get_keys(key_reporter) == "ef"
+
+
+@pytest.mark.parametrize("mode", ["open", "closed"])
+@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
+def test_element_in_shadow_tree(session, get_test_page, key_chain, mode, nested):
+ session.url = get_test_page(
+ shadow_doc="<div><input type=text></div>",
+ shadow_root_mode=mode,
+ nested_shadow_dom=nested,
+ )
+
+ shadow_root = session.find.css("custom-element", all=False).shadow_root
+
+ if nested:
+ shadow_root = shadow_root.find_element(
+ "css selector", "inner-custom-element"
+ ).shadow_root
+
+ input_el = shadow_root.find_element("css selector", "input")
+ input_el.click()
+
+ key_chain.key_down("a").key_up("a").perform()
+
+ assert input_el.property("value") == "a"
diff --git a/webdriver/tests/classic/perform_actions/pointer_mouse.py b/webdriver/tests/classic/perform_actions/pointer_mouse.py
index 31d0849..152447a 100644
--- a/webdriver/tests/classic/perform_actions/pointer_mouse.py
+++ b/webdriver/tests/classic/perform_actions/pointer_mouse.py
@@ -13,6 +13,8 @@
from tests.support.helpers import filter_dict
from tests.support.sync import Poll
+from . import assert_pointer_events, record_pointer_events
+
def test_null_response_value(session, mouse_chain):
value = mouse_chain.click().perform()
@@ -101,6 +103,36 @@
assert e["target"] == "outer"
+@pytest.mark.parametrize("mode", ["open", "closed"])
+@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
+def test_click_element_in_shadow_tree(
+ session, get_test_page, mouse_chain, mode, nested
+):
+ session.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,
+ )
+
+ shadow_root = session.find.css("custom-element", all=False).shadow_root
+ if nested:
+ shadow_root = shadow_root.find_element("css selector", "inner-custom-element").shadow_root
+
+ target = shadow_root.find_element("css selector", "#pointer-target")
+ record_pointer_events(session, target)
+
+ mouse_chain.click(element=target).perform()
+ assert_pointer_events(
+ session,
+ expected_events=["pointerdown", "pointerup"],
+ target="pointer-target",
+ pointer_type="mouse",
+ )
+
+
def test_click_navigation(session, url, inline):
destination = url("/webdriver/tests/support/html/test_actions.html")
start = inline("<a href=\"{}\" id=\"link\">destination</a>".format(destination))
diff --git a/webdriver/tests/classic/perform_actions/pointer_pen.py b/webdriver/tests/classic/perform_actions/pointer_pen.py
index e9cd103..fcd1aba 100644
--- a/webdriver/tests/classic/perform_actions/pointer_pen.py
+++ b/webdriver/tests/classic/perform_actions/pointer_pen.py
@@ -10,6 +10,8 @@
)
from tests.classic.perform_actions.support.refine import get_events
+from . import assert_pointer_events, record_pointer_events
+
def test_null_response_value(session, pen_chain):
value = pen_chain.click().perform()
@@ -34,6 +36,44 @@
pen_chain.click(element=element).perform()
+@pytest.mark.parametrize("mode", ["open", "closed"])
+@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
+def test_pen_pointer_in_shadow_tree(
+ session, get_test_page, pen_chain, mode, nested
+):
+ session.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,
+ )
+
+ shadow_root = session.find.css("custom-element", all=False).shadow_root
+
+ if nested:
+ shadow_root = shadow_root.find_element(
+ "css selector", "inner-custom-element"
+ ).shadow_root
+
+ target = shadow_root.find_element("css selector", "#pointer-target")
+
+ record_pointer_events(session, target)
+
+ pen_chain.pointer_move(0, 0, origin=target) \
+ .pointer_down() \
+ .pointer_up() \
+ .perform()
+
+ assert_pointer_events(
+ session,
+ expected_events=["pointerdown", "pointerup"],
+ target="pointer-target",
+ pointer_type="pen",
+ )
+
+
def test_pen_pointer_properties(session, test_actions_pointer_page, pen_chain):
pointerArea = session.find.css("#pointerArea", all=False)
center = get_inview_center(pointerArea.rect, get_viewport_rect(session))
diff --git a/webdriver/tests/classic/perform_actions/pointer_touch.py b/webdriver/tests/classic/perform_actions/pointer_touch.py
index 7f940f6..6c8e2f3 100644
--- a/webdriver/tests/classic/perform_actions/pointer_touch.py
+++ b/webdriver/tests/classic/perform_actions/pointer_touch.py
@@ -9,6 +9,7 @@
)
from tests.classic.perform_actions.support.refine import get_events
+from . import assert_pointer_events, record_pointer_events
def test_null_response_value(session, touch_chain):
value = touch_chain.click().perform()
@@ -33,6 +34,41 @@
touch_chain.click(element=element).perform()
+@pytest.mark.parametrize("mode", ["open", "closed"])
+@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
+def test_touch_pointer_in_shadow_tree(
+ session, get_test_page, touch_chain, mode, nested
+):
+ session.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,
+ )
+
+ shadow_root = session.find.css("custom-element", all=False).shadow_root
+
+ if nested:
+ shadow_root = shadow_root.find_element(
+ "css selector", "inner-custom-element"
+ ).shadow_root
+
+ target = shadow_root.find_element("css selector", "#pointer-target")
+
+ record_pointer_events(session, target)
+
+ touch_chain.pointer_move(0, 0, origin=target).pointer_down().pointer_up().perform()
+
+ assert_pointer_events(
+ session,
+ expected_events=["pointerdown", "pointerup"],
+ target="pointer-target",
+ pointer_type="touch",
+ )
+
+
def test_touch_pointer_properties(session, test_actions_pointer_page, touch_chain):
pointerArea = session.find.css("#pointerArea", all=False)
center = get_inview_center(pointerArea.rect, get_viewport_rect(session))
diff --git a/webdriver/tests/classic/perform_actions/wheel.py b/webdriver/tests/classic/perform_actions/wheel.py
index 7ee0ae7..c83c90d 100644
--- a/webdriver/tests/classic/perform_actions/wheel.py
+++ b/webdriver/tests/classic/perform_actions/wheel.py
@@ -64,6 +64,56 @@
assert events[0]["target"] == "iframeContent"
+@pytest.mark.parametrize("mode", ["open", "closed"])
+@pytest.mark.parametrize("nested", [False, True], ids=["outer", "inner"])
+def test_wheel_scroll_shadow_tree(session, get_test_page, wheel_chain, mode, nested):
+ session.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,
+ )
+
+ shadow_root = session.find.css("custom-element", all=False).shadow_root
+
+ if nested:
+ shadow_root = shadow_root.find_element(
+ "css selector", "inner-custom-element"
+ ).shadow_root
+
+ scrollable = shadow_root.find_element("css selector", "#scrollableShadowTree")
+
+ # Add a simplified event recorder to track events in the test ShadowRoot.
+ session.execute_script(
+ """
+ window.wheelEvents = [];
+ arguments[0].addEventListener("wheel",
+ function(event) {
+ window.wheelEvents.push({
+ "deltaX": event.deltaX,
+ "deltaY": event.deltaY,
+ "target": event.target.id
+ });
+ }
+ );
+ """,
+ args=(scrollable,),
+ )
+
+ wheel_chain.scroll(0, 0, 5, 10, origin=scrollable).perform()
+
+ events = session.execute_script("return window.wheelEvents;") or []
+ assert len(events) == 1
+ assert events[0]["deltaX"] >= 5
+ assert events[0]["deltaY"] >= 10
+ assert events[0]["target"] == "scrollableShadowTreeContent"
+
+
@pytest.mark.parametrize("missing", ["x", "y", "deltaX", "deltaY"])
def test_wheel_missing_prop(session, test_actions_scroll_page, wheel_chain, missing):
session.execute_script("document.scrollingElement.scrollTop = 0")