summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/pointerevents
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/pointerevents')
-rw-r--r--testing/web-platform/tests/pointerevents/compat/pointerevent_touch_target_after_pointerdown_target_removed.tentative.html281
-rw-r--r--testing/web-platform/tests/pointerevents/pointerevent_click_during_capture.html290
-rw-r--r--testing/web-platform/tests/pointerevents/pointerevent_mouse_capture_change_hover.html12
3 files changed, 441 insertions, 142 deletions
diff --git a/testing/web-platform/tests/pointerevents/compat/pointerevent_touch_target_after_pointerdown_target_removed.tentative.html b/testing/web-platform/tests/pointerevents/compat/pointerevent_touch_target_after_pointerdown_target_removed.tentative.html
new file mode 100644
index 0000000000..124133d25c
--- /dev/null
+++ b/testing/web-platform/tests/pointerevents/compat/pointerevent_touch_target_after_pointerdown_target_removed.tentative.html
@@ -0,0 +1,281 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Compatibility mapping with touch events after removing pointerdown target</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+div {
+ min-height: 32px;
+}
+</style>
+<script>
+"use strict";
+
+addEventListener("load", () => {
+ const checkEvents = [
+ "touchstart",
+ "touchmove",
+ "touchend",
+ "touchcancel",
+ "pointerdown",
+ "pointermove",
+ "pointerup",
+ "click",
+ ];
+ let events = [];
+ function log(event) {
+ events.push({type: event.type, target: event.target});
+ }
+ for (const type of checkEvents) {
+ addEventListener(type, log, {capture: true});
+ }
+ function stringifyEvent(event) {
+ return `{ type: ${event.type}, target: ${format_value(event.target)} }`;
+ }
+ function stringifyEvents(events) {
+ if (!events.length) {
+ return "[]";
+ }
+ let result = "";
+ for (const event of events) {
+ if (result === "") {
+ result = "[ ";
+ } else {
+ result += ", ";
+ }
+ result += stringifyEvent(event);
+ }
+ result += " ]";
+ return result;
+ }
+ function ignoreEvents(events, ignoringEvents) {
+ let ret = [];
+ for (const event of events) {
+ if (!ignoringEvents.includes(event.type)) {
+ ret.push(event);
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * The event target of touch events should be dispatched at dispatching the
+ * preceding `pointerdown`. Then, even after the `pointerdown` target is
+ * removed from the DOM tree, following touch events should be fired on it.
+ * However, following pointer events should be fired at the event targets
+ * under the pointer.
+ */
+
+ for (const removerType of ["pointerdown", "touchstart"]) {
+ promise_test(
+ async t => {
+ const pointerDownTarget = document.createElement("div");
+ pointerDownTarget.id = "pointerDownTarget";
+ const pointerDownTargetParent = document.createElement("div");
+ pointerDownTargetParent.id = "pointerDownTargetParent";
+ pointerDownTargetParent.appendChild(pointerDownTarget);
+ document.body.appendChild(pointerDownTargetParent);
+ const pointerDownTargetRect = pointerDownTarget.getBoundingClientRect();
+
+ events = [];
+ pointerDownTarget.addEventListener(removerType, () => {
+ pointerDownTarget.remove();
+ // Keep listening to the events on the removed target node.
+ for (const type of ["touchstart", "touchmove", "touchend"]) {
+ pointerDownTarget.addEventListener(type, log, {capture: true});
+ }
+ }, {once: true});
+ await new test_driver.Actions()
+ .addPointer("touchPointer", "touch")
+ .setPointer("touchPointer")
+ .pointerMove(pointerDownTargetRect.left + 10, pointerDownTargetRect.top + 10)
+ .pointerDown()
+ .pointerMove(pointerDownTargetRect.left + 12, pointerDownTargetRect.top + 12)
+ .pointerUp()
+ .send();
+
+ const expectedEvents = [
+ { type: "pointerdown", target: pointerDownTarget },
+ { type: "touchstart", target: pointerDownTarget },
+ { type: "pointermove", target: pointerDownTargetParent },
+ { type: "touchmove", target: pointerDownTarget },
+ { type: "pointerup", target: pointerDownTargetParent },
+ { type: "touchend", target: pointerDownTarget },
+ { type: "click", target: pointerDownTargetParent },
+ ];
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click", "touchmove"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["click", "touchmove"]))
+ )
+ },
+ `${
+ t.name
+ }, touch events should be fired on the touchstart target even though an orphan and pointer events should be fired on the parent`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["touchmove"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["touchmove"]))
+ )
+ },
+ `${t.name}, click event should be fired on the pointerdown target parent`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["click"]))
+ )
+ },
+ `${t.name}, touchmove event should be fired on the pointerdown target`
+ );
+ document.body.innerHTML = "";
+ },
+ `After a ${removerType} listener removes its target`
+ );
+
+ promise_test(
+ async t => {
+ const pointerDownTarget = document.createElement("div");
+ pointerDownTarget.id = "pointerDownTarget";
+ const pointerDownTargetParent = document.createElement("div");
+ pointerDownTargetParent.id = "pointerDownTargetParent";
+ pointerDownTargetParent.appendChild(pointerDownTarget);
+ document.body.appendChild(pointerDownTargetParent);
+ const pointerDownTargetRect = pointerDownTarget.getBoundingClientRect();
+
+ events = [];
+ pointerDownTarget.addEventListener(removerType, () => {
+ pointerDownTarget.remove();
+ pointerDownTargetParent.appendChild(pointerDownTarget);
+ }, {once: true});
+ await new test_driver.Actions()
+ .addPointer("touchPointer", "touch")
+ .setPointer("touchPointer")
+ .pointerMove(pointerDownTargetRect.left + 10, pointerDownTargetRect.top + 10)
+ .pointerDown()
+ .pointerMove(pointerDownTargetRect.left + 12, pointerDownTargetRect.top + 12)
+ .pointerUp()
+ .send();
+
+ const expectedEvents = [
+ { type: "pointerdown", target: pointerDownTarget },
+ { type: "touchstart", target: pointerDownTarget },
+ { type: "pointermove", target: pointerDownTarget },
+ { type: "touchmove", target: pointerDownTarget },
+ { type: "pointerup", target: pointerDownTarget },
+ { type: "touchend", target: pointerDownTarget },
+ { type: "click", target: pointerDownTarget },
+ ];
+
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click", "touchmove"])),
+ stringifyEvents(ignoreEvents(events, ["click", "touchmove"])),
+ )
+ },
+ `${t.name}, touch events and pointer events should be fired on the pointerdown target`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["touchmove"])),
+ stringifyEvents(ignoreEvents(events, ["touchmove"])),
+ )
+ },
+ `${t.name}, click event should be fired on the pointerdown target`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click"])),
+ stringifyEvents(ignoreEvents(events, ["click"])),
+ )
+ },
+ `${t.name}, touchmove event should be fired on the pointerdown target`
+ );
+ document.body.innerHTML = "";
+ },
+ `After a ${removerType} listener removes but appends the target to same position again`
+ );
+
+ promise_test(
+ async t => {
+ const pointerDownTarget = document.createElement("div");
+ pointerDownTarget.id = "pointerDownTarget";
+ const pointerDownTargetParent = document.createElement("div");
+ pointerDownTargetParent.id = "pointerDownTargetParent";
+ pointerDownTargetParent.appendChild(pointerDownTarget);
+ document.body.appendChild(pointerDownTargetParent);
+ const pointerDownTargetRect = pointerDownTarget.getBoundingClientRect();
+
+ events = [];
+ pointerDownTarget.addEventListener(removerType, () => {
+ pointerDownTarget.remove();
+ document.body.appendChild(pointerDownTarget);
+ }, {once: true});
+ await new test_driver.Actions()
+ .addPointer("touchPointer", "touch")
+ .setPointer("touchPointer")
+ .pointerMove(pointerDownTargetRect.left + 10, pointerDownTargetRect.top + 10)
+ .pointerDown()
+ .pointerMove(pointerDownTargetRect.left + 12, pointerDownTargetRect.top + 12)
+ .pointerUp()
+ .send();
+
+ const expectedEvents = [
+ { type: "pointerdown", target: pointerDownTarget },
+ { type: "touchstart", target: pointerDownTarget },
+ { type: "pointermove", target: pointerDownTargetParent },
+ { type: "touchmove", target: pointerDownTarget },
+ { type: "pointerup", target: pointerDownTargetParent },
+ { type: "touchend", target: pointerDownTarget },
+ { type: "click", target: pointerDownTargetParent },
+ ];
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click", "touchmove"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["click", "touchmove"]))
+ )
+ },
+ `${
+ t.name
+ }, touch events should be fired on the pointerdown target, but pointer events should be fired on the pointerdown target parent`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["touchmove"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["touchmove"]))
+ )
+ },
+ `${t.name}, click event should be fired on the pointerdown target parent`
+ );
+ test(
+ () => {
+ assert_equals(
+ stringifyEvents(ignoreEvents(events, ["click"])),
+ stringifyEvents(ignoreEvents(expectedEvents, ["click"]))
+ )
+ },
+ `${t.name}, touchmove event should be fired on the pointerdown target parent`
+ );
+ document.body.innerHTML = "";
+ },
+ `After a ${removerType} listener moves the target to different position`
+ );
+ }
+}, {once: true});
+</script>
+<body></body>
+</html>
diff --git a/testing/web-platform/tests/pointerevents/pointerevent_click_during_capture.html b/testing/web-platform/tests/pointerevents/pointerevent_click_during_capture.html
index e7448c7a8b..d179144557 100644
--- a/testing/web-platform/tests/pointerevents/pointerevent_click_during_capture.html
+++ b/testing/web-platform/tests/pointerevents/pointerevent_click_during_capture.html
@@ -1,138 +1,156 @@
-<!doctype html>
+<!DOCTYPE HTML>
+<title>Target of click-like events with pointer capture</title>
+<link rel="help" href="https://w3c.github.io/pointerevents/#event-dispatch" />
+<meta name="variant" content="?mouse-click">
+<meta name="variant" content="?mouse-auxclick">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="pointerevent_support.js"></script>
+
+<style>
+ div {
+ padding: 10px;
+ }
+ #parent {
+ background: grey;
+ }
+ #child1 {
+ background: green;
+ }
+ #child2 {
+ background: blue;
+ }
+</style>
+
+<div id="parent">
+ <div id="child1"></div>
+ <div id="child2"></div>
+</div>
+<div id="done"></div>
+
+<script>
+ 'use strict';
+
+ const [pointer_type, event_to_test] = location.search.substring(1).split("-");
+ assert_true(["click", "auxclick"].includes(event_to_test));
+ assert_equals(pointer_type, "mouse");
+ // Other pointer types can generate click/auxclick and should be tested here.
+
+ const test_pointer = pointer_type + 'TestPointer';
+
+ let event_log = [];
+
+ function logEvent(event) {
+ if (event.eventPhase == event.AT_TARGET) {
+ event_log.push(event.type + '@' + event.target.id);
+ }
+ }
+
+ const parent = document.getElementById('parent');
+ const child2 = document.getElementById('child2');
+ const child1 = document.getElementById('child1');
+ const done = document.getElementById('done');
+
+ let logged_events = [
+ 'gotpointercapture', 'lostpointercapture',
+ 'pointerdown', 'pointerup', event_to_test
+ ];
+ logged_events.forEach(ename => {
+ [parent, child2, child1].forEach(target => {
+ target.addEventListener(ename, logEvent);
+ });
+ });
+
+ function dragBetweenChildrenAndClickOnDone(from_child, to_child, test) {
+ let actions_promise = new test_driver.Actions();
+
+ const button_type = (event_to_test === "click")
+ ? actions_promise.ButtonType.LEFT
+ : actions_promise.ButtonType.MIDDLE;
+
+ actions_promise.addPointer(test_pointer, pointer_type)
+ .pointerMove(0, 0, {origin:from_child})
+ .pointerDown({button:button_type})
+ .pointerMove(0, 0, {origin:to_child})
+ .pointerUp({button:button_type})
+ .pointerMove(0, 0, {origin:done})
+ .pointerDown()
+ .pointerUp();
+
+ let done_click_promise = getEvent('click', done, test);
+
+ return actions_promise.send().then(done_click_promise);
+ }
+
+ promise_test(async test => {
+ event_log = [];
+
+ await dragBetweenChildrenAndClickOnDone(child1, child1, test);
+
+ assert_equals(event_log.join(','),
+ `pointerdown@child1,pointerup@child1,${event_to_test}@child1`);
+ }, 'pointerdown/up at child1, no capture');
+
+ promise_test(async test => {
+ event_log = [];
+
+ getEvent('pointerdown', child1, test)
+ .then(event => child1.setPointerCapture(event.pointerId));
+ await dragBetweenChildrenAndClickOnDone(child1, child1, test);
+
+ assert_equals(event_log.join(','),
+ 'pointerdown@child1,gotpointercapture@child1,' +
+ `pointerup@child1,lostpointercapture@child1,${event_to_test}@child1`);
+ }, 'pointerdown/up at child1, capture at child1');
+
+ promise_test(async test => {
+ event_log = [];
+
+ getEvent('pointerdown', child1, test)
+ .then(event => child2.setPointerCapture(event.pointerId));
+ await dragBetweenChildrenAndClickOnDone(child1, child1, test);
+
+ assert_equals(event_log.join(','),
+ 'pointerdown@child1,gotpointercapture@child2,' +
+ `pointerup@child2,lostpointercapture@child2,${event_to_test}@child2`);
+ }, 'pointerdown/up at child1, capture at child2');
+
+ promise_test(async test => {
+ event_log = [];
+
+ await dragBetweenChildrenAndClickOnDone(child1, child2, test);
+
+ assert_equals(event_log.join(','),
+ `pointerdown@child1,pointerup@child2,${event_to_test}@parent`);
+ }, 'pointerdown at child1, pointerup at child2, no capture');
+
+ promise_test(async test => {
+ event_log = [];
+
+ getEvent('pointerdown', child1, test)
+ .then(event => child1.setPointerCapture(event.pointerId));
+ await dragBetweenChildrenAndClickOnDone(child1, child2, test);
+
+ assert_equals(event_log.join(','),
+ 'pointerdown@child1,gotpointercapture@child1,' +
+ `pointerup@child1,lostpointercapture@child1,${event_to_test}@child1`);
+ }, 'pointerdown at child1, pointerup at child2, capture at child1');
+
+ promise_test(async test => {
+ event_log = [];
+
+ getEvent('pointerdown', child1, test)
+ .then(event => child2.setPointerCapture(event.pointerId));
+ await dragBetweenChildrenAndClickOnDone(child1, child2, test);
+
+ assert_equals(event_log.join(','),
+ 'pointerdown@child1,gotpointercapture@child2,' +
+ `pointerup@child2,lostpointercapture@child2,${event_to_test}@child2`);
+ }, 'pointerdown at child1, pointerup at child2, capture at child2');
+</script>
<html>
- <head>
- <title>click event target during capture</title>
- <meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
- <script src="/resources/testharness.js"></script>
- <script src="/resources/testharnessreport.js"></script>
- <script src="pointerevent_support.js"></script>
- <script src="/resources/testdriver.js"></script>
- <script src="/resources/testdriver-actions.js"></script>
- <script src="/resources/testdriver-vendor.js"></script>
- <style>
- .box {
- margin: 10px;
- }
- #grey {
- background: grey;
- }
- #blue {
- background: blue;
- }
- #green {
- background: green;
- }
- </style>
- <script type="text/javascript">
- PhaseEnum = {
- Phase1: "phase1",
- Phase2: "phase2",
- Phase1WithCapturing: "phase1withcapturing",
- Phase2WithCapturing: "phase2withcapturing",
- }
- var phase;
- var receivedEvents;
-
- function resetTestState() {
- phase = PhaseEnum.Phase1;
- receivedEvents = [];
- }
-
- function run() {
- var test_pointerEvent = setup_pointerevent_test("click target during capture", ['mouse']);
- var grey = document.getElementById('grey');
- var blue = document.getElementById('blue');
- var green = document.getElementById('green');
- var actions_promise;
-
- ['gotpointercapture', 'lostpointercapture', 'pointerdown', 'pointerup', 'click'].forEach(function(eventName) {
- [grey, blue, green].forEach(function(target) {
- target.addEventListener(eventName, function(event) {
- if (event.eventPhase == event.AT_TARGET) {
- receivedEvents.push(event.type + '@' + target.id);
- if (phase == PhaseEnum.Phase1 && target == green && event.type == 'click') {
- test(function() {
- assert_equals(receivedEvents.join(','), 'pointerdown@green,pointerup@green,click@green', 'An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets');
- }, "Click target when pointerup/down targeted at the same element with no capture");
- phase = PhaseEnum.Phase2;
- receivedEvents = [];
- }
- if (phase == PhaseEnum.Phase2 && target == grey && event.type == 'click') {
- test(function() {
- assert_equals(receivedEvents.join(','), 'pointerdown@blue,pointerup@green,click@grey', 'An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets');
- }, "Click target when pointerup/down targeted at different elements with no capture");
- phase = PhaseEnum.Phase1WithCapturing;
- receivedEvents = [];
- }
- if (target == blue && event.type == 'lostpointercapture') {
- if (phase == PhaseEnum.Phase1WithCapturing) {
- test_pointerEvent.step(function() {
- assert_equals(receivedEvents.join(','), 'pointerdown@green,gotpointercapture@blue,pointerup@blue,click@blue,lostpointercapture@blue', 'An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets');
- });
- phase = PhaseEnum.Phase2WithCapturing;
- receivedEvents = [];
- } else if (phase == PhaseEnum.Phase2WithCapturing) {
- test_pointerEvent.step(function() {
- assert_equals(receivedEvents.join(','), 'pointerdown@blue,gotpointercapture@blue,pointerup@blue,click@blue,lostpointercapture@blue', 'An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets');
- });
- // Make sure the test finishes after all the input actions are completed.
- actions_promise.then( () => {
- test_pointerEvent.done();
- });
- }
- }
- if (event.type == 'pointerdown' && (target == blue || target == green)) {
- if (phase == PhaseEnum.Phase1WithCapturing || phase == PhaseEnum.Phase2WithCapturing)
- blue.setPointerCapture(event.pointerId);
- }
- }
- });
- });
- });
-
- // Inject mouse inputs.
- //
- // TODO(mustaq@chromium.org): It is no longer testable manually.
- // Switch it to a promise_test to simplify the code, and remove
- // the instructions on HTML.
- var actions_promise = new test_driver.Actions()
- .pointerMove(0, 0, {origin: green})
- .pointerDown()
- .pointerUp()
- .pointerMove(0, 0, {origin: blue})
- .pointerDown()
- .pointerMove(0, 0, {origin: green})
- .pointerUp()
- .pointerMove(0, 0, {origin: green})
- .pointerDown()
- .pointerUp()
- .pointerMove(0, 0, {origin: blue})
- .pointerDown()
- .pointerMove(0, 0, {origin: green})
- .pointerUp()
- .send();
-
- }
- </script>
- </head>
- <body onload="run()">
- <h1>Pointer Event: click event during capture</h1>
- <h2 id="pointerTypeDescription"></h2>
- <h4>Test Description:
- Click event should be sent to the first common ancestor of the pointerdown and pointerup targets.
- <ol>
- <li>Click on the green box with the left button of mouse.</li>
- <li>Press down the left button on the blue box and drag to the green box and release the button.</li>
- <li>Repeat the two steps above once again.</li>
- </ol>
- </h4>
- <br>
- <div>
- <div id="grey" class="box">
- <div id="green" class="box"></div>
- <div id="blue" class="box"></div>
- </div>
- </div>
- </body>
</html>
diff --git a/testing/web-platform/tests/pointerevents/pointerevent_mouse_capture_change_hover.html b/testing/web-platform/tests/pointerevents/pointerevent_mouse_capture_change_hover.html
index ef824dafd9..eb46000938 100644
--- a/testing/web-platform/tests/pointerevents/pointerevent_mouse_capture_change_hover.html
+++ b/testing/web-platform/tests/pointerevents/pointerevent_mouse_capture_change_hover.html
@@ -61,8 +61,8 @@ function releaseCapture(event) {
function run() {
promise_test (async() => {
- // Move to (0, 0) to reset hovering.
- await new test_driver.Actions().pointerMove(0, 0).send();
+ // Move to (1, 1) to reset hovering.
+ await new test_driver.Actions().pointerMove(1, 1).send();
receivedEventList = [];
// pointerdown at green -> set capture to green -> green receive the following moves.
@@ -93,8 +93,8 @@ function run() {
}, "Mouse down and capture to green.");
promise_test (async() => {
- // Move to (0, 0) to reset hovering.
- await new test_driver.Actions().addPointer("mouse").pointerMove(0, 0).send();
+ // Move to (1, 1) to reset hovering.
+ await new test_driver.Actions().addPointer("mouse").pointerMove(1, 1).send();
receivedEventList = [];
// pointerdown at green -> set capture to blue -> blue receive the following moves.
@@ -129,8 +129,8 @@ function run() {
}, "Mouse down at green and capture to blue.");
promise_test (async() => {
- // Move to (0, 0) to reset hovering.
- await new test_driver.Actions().addPointer("mouse").pointerMove(0, 0).send();
+ // Move to (1, 1) to reset hovering.
+ await new test_driver.Actions().addPointer("mouse").pointerMove(1, 1).send();
receivedEventList = [];
// pointerdown at green -> set capture to green -> green receive first move -> release capture -> blue receive the next move