diff options
Diffstat (limited to 'testing/web-platform/tests/pointerevents')
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 |