-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WPT coverage for Pointer Events for slotted elements.
This CL adds tests for two untested aspects of PointerEvents in slots: - PE event sequence around slots when the shadow DOM remains unchanged. - Boundary events after modifications to slotted elements. This covers the last remaining WPT for: w3c/pointerevents#477 Bug: 40156858 Change-Id: I9823595a0b15672d0395d4e117ccc6462c3e42f2
- Loading branch information
1 parent
3856e17
commit 8272232
Showing
2 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
174 changes: 174 additions & 0 deletions
174
pointerevents/pointerevent_after_target_removed_from_slot.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<!DOCTYPE HTML> | ||
<link rel="help" href="https://w3c.github.io/pointerevents/#firing-events-using-the-pointerevent-interface"> | ||
<title>Enter/leave events fired to parent after child is removed from slot</title> | ||
<meta name="variant" content="?mouse"> | ||
<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> | ||
|
||
<template id="template"> | ||
<style> | ||
div { | ||
width: 100px; | ||
height: 100px; | ||
} | ||
</style> | ||
<div id="parent"> | ||
<slot>slot</slot> | ||
</div> | ||
</template> | ||
|
||
<style> | ||
div, my-elem { | ||
width: 100px; | ||
height: 100px; | ||
display: block; | ||
} | ||
</style> | ||
|
||
<my-elem id="host"> | ||
<div id="child">child</div> | ||
</my-elem> | ||
<div id="done">done</div> | ||
|
||
<script> | ||
"use strict"; | ||
|
||
customElements.define( | ||
"my-elem", | ||
class extends HTMLElement { | ||
constructor() { | ||
super(); | ||
let content = document.getElementById("template").content; | ||
const shadowRoot = this.attachShadow({ mode: "open" }); | ||
shadowRoot.appendChild(content.cloneNode(true)); | ||
} | ||
}, | ||
); | ||
|
||
const pointer_type = location.search.substring(1); | ||
|
||
const shadow_host = document.getElementById("host"); | ||
const parent = shadow_host.shadowRoot.getElementById("parent"); | ||
const slot = parent.firstElementChild; | ||
const slotted_child = document.getElementById("child"); | ||
const done = document.getElementById("done"); | ||
|
||
let event_log = []; | ||
let elem_to_remove; | ||
|
||
function logEvent(e) { | ||
if (e.eventPhase == e.AT_TARGET) { | ||
event_log.push(e.type + "@" + e.target.id); | ||
} | ||
} | ||
|
||
function removeChildFromSlot() { | ||
elem_to_remove.remove(); | ||
event_log.push("(child-removed)"); | ||
} | ||
|
||
function restoreChildInSlot() { | ||
if (!slotted_child.parentElement) { | ||
shadow_host.appendChild(slotted_child); | ||
} | ||
if (!slot.parentElement) { | ||
parent.appendChild(slot); | ||
} | ||
} | ||
|
||
function setup() { | ||
const events = ["pointerover", "pointerout", | ||
"pointerenter", "pointerleave", "pointerdown", "pointerup"]; | ||
let targets = [parent, slotted_child]; | ||
for (let i = 0; i < targets.length; i++) { | ||
events.forEach(event => targets[i].addEventListener(event, logEvent)); | ||
} | ||
} | ||
|
||
function addPromiseTest(remover_event, tested_elem_to_remove, | ||
expected_events) { | ||
assert_true(["slot", "slotted-child"].includes(tested_elem_to_remove), | ||
"Unexpcted tested_elem_to_remove param"); | ||
|
||
const test_name = `Pointer events from ${pointer_type} `+ | ||
`received before/after ${tested_elem_to_remove} removal `+ | ||
`at ${remover_event}`; | ||
|
||
promise_test(async test => { | ||
event_log = []; | ||
elem_to_remove = (tested_elem_to_remove == "slot" ? slot : slotted_child); | ||
|
||
restoreChildInSlot(); | ||
child.addEventListener(remover_event, removeChildFromSlot, | ||
{ once: true }); | ||
// TODO([email protected]): It would be more robust if we could remove | ||
// the event listener above through `test.add_cleanup()` but strangely the | ||
// cleanup call fails after the test that removes the slotted-child! This | ||
// happens even if we make the shadow DOM construction dynamic inside this | ||
// `promise_test`!!! | ||
|
||
let done_click_promise = getEvent("click", done); | ||
|
||
let actions = new test_driver.Actions() | ||
.addPointer("TestPointer", pointer_type) | ||
.pointerMove(-30, -30, {origin: shadow_host}) | ||
.pointerDown() | ||
.pointerUp() | ||
.pointerMove(30, 30, {origin: shadow_host}) | ||
.pointerDown() | ||
.pointerUp() | ||
.pointerMove(0, 0, {origin: done}) | ||
.pointerDown() | ||
.pointerUp(); | ||
|
||
await actions.send(); | ||
await done_click_promise; | ||
|
||
assert_equals(event_log.toString(), expected_events.toString(), | ||
"events received"); | ||
}, test_name); | ||
} | ||
|
||
setup(); | ||
|
||
addPromiseTest( | ||
"pointerdown", | ||
"slot", | ||
["pointerover@child", "pointerenter@parent", "pointerenter@child", | ||
"pointerdown@child", "(child-removed)", | ||
"pointerout@child", "pointerleave@child", | ||
"pointerover@parent", "pointerup@parent", | ||
"pointerdown@parent", "pointerup@parent", | ||
"pointerout@parent", "pointerleave@parent"] | ||
); | ||
addPromiseTest( | ||
"pointerdown", | ||
"slotted-child", | ||
["pointerover@child", "pointerenter@parent", "pointerenter@child", | ||
"pointerdown@child", "(child-removed)", | ||
"pointerover@parent", "pointerup@parent", | ||
"pointerdown@parent", "pointerup@parent", | ||
"pointerout@parent", "pointerleave@parent"] | ||
); | ||
addPromiseTest( | ||
"pointerup", | ||
"slot", | ||
["pointerover@child", "pointerenter@parent", "pointerenter@child", | ||
"pointerdown@child", "pointerup@child", "(child-removed)", | ||
"pointerout@child", "pointerleave@child", | ||
"pointerover@parent", "pointerdown@parent", "pointerup@parent", | ||
"pointerout@parent", "pointerleave@parent"] | ||
); | ||
addPromiseTest( | ||
"pointerup", | ||
"slotted-child", | ||
["pointerover@child", "pointerenter@parent", "pointerenter@child", | ||
"pointerdown@child", "pointerup@child", "(child-removed)", | ||
"pointerover@parent", "pointerdown@parent", "pointerup@parent", | ||
"pointerout@parent", "pointerleave@parent"] | ||
); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<!DOCTYPE HTML> | ||
<link rel="help" href="https://w3c.github.io/pointerevents/#firing-events-using-the-pointerevent-interface"> | ||
<title>Enter/leave events fired to parent after child is removed from slot</title> | ||
<meta name="variant" content="?mouse"> | ||
<meta name="variant" content="?touch"> | ||
<meta name="variant" content="?pen"> | ||
<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> | ||
|
||
<template id="template"> | ||
<style> | ||
div { | ||
width: 100px; | ||
height: 100px; | ||
} | ||
</style> | ||
<div id="parent"> | ||
<slot id="slot">slot</slot> | ||
</div> | ||
</template> | ||
|
||
<style> | ||
div, my-elem { | ||
width: 100px; | ||
height: 100px; | ||
display: block; | ||
} | ||
</style> | ||
|
||
<my-elem id="host"> | ||
<div id="child">child</div> | ||
</my-elem> | ||
<div id="done">done</div> | ||
|
||
<script> | ||
"use strict"; | ||
|
||
customElements.define( | ||
"my-elem", | ||
class extends HTMLElement { | ||
constructor() { | ||
super(); | ||
let content = document.getElementById("template").content; | ||
const shadowRoot = this.attachShadow({ mode: "open" }); | ||
shadowRoot.appendChild(content.cloneNode(true)); | ||
} | ||
}, | ||
); | ||
|
||
const pointer_type = location.search.substring(1); | ||
|
||
const shadow_host = document.getElementById("host"); | ||
const parent = shadow_host.shadowRoot.getElementById("parent"); | ||
const slot = parent.firstElementChild; | ||
const slotted_child = document.getElementById("child"); | ||
const done = document.getElementById("done"); | ||
|
||
let event_log = []; | ||
|
||
function logEvent(e) { | ||
if (e.eventPhase == e.AT_TARGET) { | ||
event_log.push(e.type + "@" + e.target.id); | ||
} | ||
} | ||
|
||
function setup() { | ||
const events = ["pointerover", "pointerout", | ||
"pointerenter", "pointerleave", "pointerdown", "pointerup"]; | ||
let targets = [shadow_host, parent, slot, slotted_child]; | ||
for (let i = 0; i < targets.length; i++) { | ||
events.forEach(event => targets[i].addEventListener(event, logEvent)); | ||
} | ||
} | ||
|
||
setup(); | ||
|
||
promise_test(async test => { | ||
event_log = []; | ||
|
||
let done_click_promise = getEvent("click", done); | ||
|
||
let actions = new test_driver.Actions() | ||
.addPointer("TestPointer", pointer_type) | ||
.pointerMove(0, 0, {origin: shadow_host}) | ||
.pointerDown() | ||
.pointerUp() | ||
.pointerMove(0, 0, {origin: done}) | ||
.pointerDown() | ||
.pointerUp(); | ||
|
||
await actions.send(); | ||
await done_click_promise; | ||
|
||
const expected_events = [ | ||
"pointerover@child", | ||
"pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@child", | ||
"pointerdown@child", "pointerup@child", | ||
"pointerout@child", | ||
"pointerleave@child", "pointerleave@slot", "pointerleave@parent", "pointerleave@host" | ||
]; | ||
assert_equals(event_log.toString(), expected_events.toString(), | ||
"events received"); | ||
}, `Pointer events from ${pointer_type} to slotted element and shadow-host`); | ||
</script> |