pointerevent_after_target_appended.html (8452B)
1 <!DOCTYPE HTML> 2 <title>Enter/leave events fired to parent after child is added</title> 3 <link rel="help" href="https://w3c.github.io/pointerevents/#firing-events-using-the-pointerevent-interface"> 4 <meta name="variant" content="?mouse"> 5 <meta name="variant" content="?touch"> 6 <meta name="variant" content="?pen"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/resources/testdriver.js"></script> 10 <script src="/resources/testdriver-actions.js"></script> 11 <script src="/resources/testdriver-vendor.js"></script> 12 <script src="pointerevent_support.js"></script> 13 14 <style> 15 div.target { 16 width: 100px; 17 height: 100px; 18 } 19 </style> 20 <div class="target" id="parent"> 21 <div class="target" id="child">child</div> 22 </div> 23 <div id="done">done</div> 24 25 <script> 26 'use strict'; 27 const pointer_type = location.search.substring(1); 28 29 const parent = document.getElementById("parent"); 30 const child = document.getElementById("child"); 31 const done = document.getElementById("done"); 32 33 let event_log = []; 34 let logged_event_prefix = ""; 35 let received_compat_mouse_events = false; 36 37 function logEvent(e) { 38 if (e.type.startsWith(logged_event_prefix) && e.eventPhase == e.AT_TARGET) { 39 event_log.push(e.type + "@" + e.target.id); 40 } 41 if (e.type.startsWith("mouse")) { 42 received_compat_mouse_events = true; 43 } 44 } 45 46 function attachChild(e) { 47 if (e.eventPhase == e.AT_TARGET) { 48 parent.appendChild(child); 49 event_log.push("(child-attached)"); 50 } 51 } 52 53 let child_moved = false; 54 55 function moveChild(e) { 56 if (!child_moved) { 57 child_moved = true; 58 parent.appendChild(child); 59 event_log.push("(child-moved)"); 60 } 61 } 62 63 function setup() { 64 const logged_event_suffixes = 65 ["over", "out", "enter", "leave", "down", "up"]; 66 let targets = document.getElementsByClassName("target"); 67 for (let i = 0; i < targets.length; i++) { 68 logged_event_suffixes.forEach(suffix => { 69 targets[i].addEventListener("pointer" + suffix, logEvent); 70 targets[i].addEventListener("mouse" + suffix, logEvent); 71 }); 72 } 73 } 74 75 function addPromiseTestForNewChild(attaching_event, 76 tested_event_prefix, expected_events) { 77 const test_name = `${tested_event_prefix} events from ${pointer_type} `+ 78 `received before/after child attached at ${attaching_event}`; 79 80 promise_test(async test => { 81 event_log = []; 82 logged_event_prefix = tested_event_prefix; 83 84 // We started with child attached to ease event listener setup above. 85 parent.removeChild(child); 86 87 parent.addEventListener(attaching_event, attachChild); 88 test.add_cleanup(() => { 89 parent.removeEventListener(attaching_event, attachChild); 90 }); 91 92 let done_click_promise = getEvent("click", done); 93 94 let actions = new test_driver.Actions() 95 .addPointer("TestPointer", pointer_type) 96 .pointerMove(-30, -30, {origin: parent}) 97 .pointerDown() 98 .pointerUp() 99 .pointerMove(30, 30, {origin: parent}) 100 .pointerDown() 101 .pointerUp() 102 .pointerMove(0, 0, {origin: done}) 103 .pointerDown() 104 .pointerUp(); 105 106 await actions.send(); 107 await done_click_promise; 108 109 if (tested_event_prefix == "mouse" && !received_compat_mouse_events) { 110 expected_events = []; 111 } 112 113 assert_equals(event_log.toString(), expected_events.toString(), 114 "events received"); 115 }, test_name); 116 } 117 118 function addPromiseTestForMovedChild(mover_event, 119 tested_event_prefix, expected_events) { 120 const test_name = `${tested_event_prefix} events from ${pointer_type} `+ 121 `received before/after child moved at ${mover_event}`; 122 123 promise_test(async test => { 124 event_log = []; 125 logged_event_prefix = tested_event_prefix; 126 child_moved = false; 127 128 child.addEventListener(mover_event, moveChild); 129 test.add_cleanup(() => { 130 child.removeEventListener(mover_event, moveChild); 131 }); 132 133 let done_click_promise = getEvent("click", done); 134 135 let actions = new test_driver.Actions() 136 .addPointer("TestPointer", pointer_type) 137 .pointerMove(-30, -30, {origin: parent}) 138 .pointerDown() 139 .pointerUp() 140 .pointerMove(30, 30, {origin: parent}) 141 .pointerDown() 142 .pointerUp() 143 .pointerMove(0, 0, {origin: done}) 144 .pointerDown() 145 .pointerUp(); 146 147 await actions.send(); 148 await done_click_promise; 149 150 if (tested_event_prefix == "mouse" && !received_compat_mouse_events) { 151 expected_events = []; 152 } 153 154 assert_equals(event_log.toString(), expected_events.toString(), 155 "events received"); 156 }, test_name); 157 } 158 159 setup(); 160 161 const hoverable = pointer_type != "touch"; 162 163 // Tests for dispatched pointer events. 164 addPromiseTestForNewChild( 165 "pointerdown", 166 "pointer", 167 hoverable 168 ? ["pointerover@parent", "pointerenter@parent", 169 "pointerdown@parent", "(child-attached)", 170 "pointerout@parent", "pointerover@child", "pointerenter@child", 171 "pointerup@child", 172 "pointerdown@child", "pointerup@child", 173 "pointerout@child", "pointerleave@child", "pointerleave@parent"] 174 : ["pointerover@parent", "pointerenter@parent", 175 "pointerdown@parent", "(child-attached)", 176 // pointerup should imply a pointermove over the attached child. 177 "pointerout@parent", "pointerover@child", "pointerenter@child", 178 // pointerup should cause pointerout/pointerleave if the input source is not hoverable. 179 "pointerup@child", "pointerout@child", "pointerleave@child", "pointerleave@parent", 180 // then, pointerdown should imply a pointermove again. 181 "pointerover@child", "pointerenter@child", "pointerenter@parent", "pointerdown@child", 182 "pointerup@child", "pointerout@child", "pointerleave@child", "pointerleave@parent"] 183 ); 184 addPromiseTestForNewChild("pointerup", "pointer", [ 185 "pointerover@parent", "pointerenter@parent", 186 "pointerdown@parent", "pointerup@parent", "(child-attached)", 187 "pointerout@parent", "pointerover@child", "pointerenter@child", 188 "pointerdown@child", "pointerup@child", 189 "pointerout@child", "pointerleave@child", "pointerleave@parent" 190 ]); 191 addPromiseTestForMovedChild("pointerdown", "pointer", [ 192 "pointerover@child", "pointerenter@parent", "pointerenter@child", 193 "pointerdown@child", "(child-moved)", 194 "pointerover@child", "pointerenter@child", 195 "pointerup@child", 196 "pointerdown@child", "pointerup@child", 197 "pointerout@child", "pointerleave@child", "pointerleave@parent" 198 ]); 199 addPromiseTestForMovedChild("pointerup", "pointer", [ 200 "pointerover@child", "pointerenter@parent", "pointerenter@child", 201 "pointerdown@child", "pointerup@child", "(child-moved)", 202 "pointerover@child", "pointerenter@child", 203 "pointerdown@child", "pointerup@child", 204 "pointerout@child", "pointerleave@child", "pointerleave@parent" 205 ]); 206 207 // Same tests for dispatched compatibility mouse events. 208 addPromiseTestForNewChild("mousedown", "mouse", [ 209 "mouseover@parent", "mouseenter@parent", 210 "mousedown@parent", "(child-attached)", 211 "mouseout@parent", "mouseover@child", "mouseenter@child", 212 "mouseup@child", 213 "mousedown@child", "mouseup@child", 214 "mouseout@child", "mouseleave@child", "mouseleave@parent" 215 ]); 216 addPromiseTestForNewChild("mouseup", "mouse", [ 217 "mouseover@parent", "mouseenter@parent", 218 "mousedown@parent", "mouseup@parent", "(child-attached)", 219 "mouseout@parent", "mouseover@child", "mouseenter@child", 220 "mousedown@child", "mouseup@child", 221 "mouseout@child", "mouseleave@child", "mouseleave@parent" 222 ]); 223 addPromiseTestForMovedChild("mousedown", "mouse", [ 224 "mouseover@child", "mouseenter@parent", "mouseenter@child", 225 "mousedown@child", "(child-moved)", 226 "mouseover@child", "mouseenter@child", 227 "mouseup@child", 228 "mousedown@child", "mouseup@child", 229 "mouseout@child", "mouseleave@child", "mouseleave@parent" 230 ]); 231 addPromiseTestForMovedChild("mouseup", "mouse", [ 232 "mouseover@child", "mouseenter@parent", "mouseenter@child", 233 "mousedown@child", "mouseup@child", "(child-moved)", 234 "mouseover@child", "mouseenter@child", 235 "mousedown@child", "mouseup@child", 236 "mouseout@child", "mouseleave@child", "mouseleave@parent" 237 ]); 238 </script>