pointerevent_after_target_removed_from_slot.html (7439B)
1 <!DOCTYPE HTML> 2 <link rel="help" 3 href="https://w3c.github.io/pointerevents/#firing-events-using-the-pointerevent-interface"> 4 <title>Pointerevents fired after a slotted element is removed</title> 5 <meta name="variant" content="?mouse"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src="/resources/testdriver.js"></script> 9 <script src="/resources/testdriver-actions.js"></script> 10 <script src="/resources/testdriver-vendor.js"></script> 11 <script src="pointerevent_support.js"></script> 12 13 <style> 14 div { 15 width: 100px; 16 height: 100px; 17 display: block; 18 } 19 </style> 20 21 <div id="host"> 22 <template id="template" shadowrootmode="open"> 23 <style> 24 div { 25 width: 100px; 26 height: 100px; 27 } 28 </style> 29 <div id="parent"> 30 <slot id="slot"> 31 <div></div> 32 </slot> 33 </div> 34 </template> 35 36 <div id="filler"></div> 37 </div> 38 <div id="done"></div> 39 40 <script> 41 "use strict"; 42 43 const pointer_type = location.search.substring(1); 44 45 const host = document.getElementById("host"); 46 const parent = host.shadowRoot.getElementById("parent"); 47 const slot = parent.firstElementChild; 48 const filler = document.getElementById("filler"); 49 const done = document.getElementById("done"); 50 51 let event_log = []; 52 53 function logEvent(e) { 54 if (e.eventPhase == e.AT_TARGET) { 55 event_log.push(e.type + "@" + e.target.id); 56 } 57 } 58 59 const modifier_methods = { 60 "remove-slot": { 61 "remover": () => { slot.remove(); event_log.push("(removed)"); }, 62 "restorer": () => { parent.appendChild(slot); } 63 }, 64 "remove-filler": { 65 "remover": () => { filler.remove(); event_log.push("(removed)"); }, 66 "restorer": () => { host.appendChild(filler); } 67 }, 68 "change-slotname": { 69 "remover": () => { filler.slot = "xyz"; event_log.push("(removed)"); }, 70 "restorer": () => { filler.slot = ""; } 71 } 72 } 73 74 function setup() { 75 const events = ["pointerover", "pointerout", 76 "pointerenter", "pointerleave", "pointerdown", "pointerup"]; 77 let targets = [host, parent, slot, filler]; 78 for (let i = 0; i < targets.length; i++) { 79 events.forEach(event => targets[i].addEventListener(event, logEvent)); 80 } 81 } 82 83 function addPromiseTest(remover_event, removal_type, 84 expected_events) { 85 assert_true(Object.keys(modifier_methods).includes(removal_type), 86 "[sanity check] Unknown removal_type param"); 87 88 const test_name = `${pointer_type} events with ${removal_type} ` + 89 `at ${remover_event}`; 90 91 promise_test(async test => { 92 event_log = []; 93 94 filler.addEventListener(remover_event, 95 modifier_methods[removal_type].remover, 96 { once: true }); 97 test.add_cleanup(modifier_methods[removal_type].restorer); 98 99 // TODO(mustaq@chromium.org): It would be more robust if we could remove 100 // the event listener above through `test.add_cleanup()` but strangely the 101 // cleanup call fails after the test that removes the filler! This 102 // happens even if we make the shadow DOM construction dynamic inside this 103 // `promise_test`!!! 104 105 let done_click_promise = getEvent("click", done); 106 107 let actions = new test_driver.Actions() 108 .addPointer("TestPointer", pointer_type) 109 .pointerMove(-30, -30, {origin: host}) 110 .pointerDown() 111 .pointerUp() 112 .pointerMove(30, 30, {origin: host}) 113 .pointerDown() 114 .pointerUp() 115 .pointerMove(0, 0, {origin: done}) 116 .pointerDown() 117 .pointerUp(); 118 119 await actions.send(); 120 await done_click_promise; 121 122 let removal_in_event_log = event_log.indexOf("(removed)"); 123 assert_true(removal_in_event_log != -1, 124 "(removed) in event log"); 125 126 let removal_in_expected_list = expected_events.indexOf("(removed)"); 127 assert_true(removal_in_expected_list != -1, 128 "[sanity check] (removed) in expected events"); 129 130 assert_equals(event_log.slice(0, removal_in_event_log).toString(), 131 expected_events.slice(0, removal_in_expected_list).toString(), 132 "events received before removal"); 133 assert_equals(event_log.slice(removal_in_event_log+1).toString(), 134 expected_events.slice(removal_in_expected_list+1).toString(), 135 "events received after removal"); 136 }, test_name); 137 } 138 139 setup(); 140 141 addPromiseTest( 142 "pointerdown", 143 "remove-slot", 144 [ 145 "pointerover@filler", 146 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 147 "pointerdown@filler", "(removed)", 148 "pointerout@filler", "pointerleave@filler", 149 "pointerover@parent", "pointerover@host", "pointerup@parent", "pointerup@host", 150 "pointerdown@parent", "pointerdown@host", "pointerup@parent", "pointerup@host", 151 "pointerout@parent", "pointerout@host", 152 "pointerleave@parent", "pointerleave@host" 153 ] 154 ); 155 addPromiseTest( 156 "pointerdown", 157 "remove-filler", 158 [ 159 "pointerover@filler", 160 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 161 "pointerdown@filler", "(removed)", 162 "pointerover@slot", "pointerup@slot", 163 "pointerdown@slot", "pointerup@slot", 164 "pointerout@slot", 165 "pointerleave@slot", "pointerleave@parent", "pointerleave@host" 166 ] 167 ); 168 addPromiseTest( 169 "pointerdown", 170 "change-slotname", 171 [ 172 "pointerover@filler", 173 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 174 "pointerdown@filler", "(removed)", 175 "pointerout@filler", "pointerleave@filler", 176 "pointerover@parent", "pointerover@host", "pointerup@parent", "pointerup@host", 177 "pointerdown@parent", "pointerdown@host", "pointerup@parent", "pointerup@host", 178 "pointerout@parent", "pointerout@host", 179 "pointerleave@parent", "pointerleave@host" 180 ] 181 ); 182 addPromiseTest( 183 "pointerup", 184 "remove-slot", 185 [ 186 "pointerover@filler", 187 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 188 "pointerdown@filler", "pointerup@filler", "(removed)", 189 "pointerout@filler", "pointerleave@filler", 190 "pointerover@parent", "pointerover@host", 191 "pointerdown@parent", "pointerdown@host", "pointerup@parent", "pointerup@host", 192 "pointerout@parent", "pointerout@host", 193 "pointerleave@parent", "pointerleave@host" 194 ] 195 ); 196 addPromiseTest( 197 "pointerup", 198 "remove-filler", 199 [ 200 "pointerover@filler", 201 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 202 "pointerdown@filler", "pointerup@filler", "(removed)", 203 "pointerover@slot", 204 "pointerdown@slot", "pointerup@slot", 205 "pointerout@slot", 206 "pointerleave@slot", "pointerleave@parent", "pointerleave@host" 207 ] 208 ); 209 addPromiseTest( 210 "pointerup", 211 "change-slotname", 212 [ 213 "pointerover@filler", 214 "pointerenter@host", "pointerenter@parent", "pointerenter@slot", "pointerenter@filler", 215 "pointerdown@filler", "pointerup@filler", "(removed)", 216 "pointerout@filler", "pointerleave@filler", 217 "pointerover@parent", "pointerover@host", 218 "pointerdown@parent", "pointerdown@host", "pointerup@parent", "pointerup@host", 219 "pointerout@parent", "pointerout@host", 220 "pointerleave@parent", "pointerleave@host" 221 ] 222 ); 223 </script>