mouseenter-mouseleave-on-drag.html (6558B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test for redundant mouseenter or mouseleave events</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/resources/testdriver.js"></script> 8 <script src="/resources/testdriver-actions.js"></script> 9 <script src="/resources/testdriver-vendor.js"></script> 10 </head> 11 <style> 12 #outer { 13 background: grey; 14 width: 100px; 15 height: 100px; 16 } 17 #inner { 18 background: red; 19 position: relative; 20 left: 30px; 21 top: 30px; 22 width: 40px; 23 height: 40px; 24 } 25 #done { 26 background: green; 27 width: 40px; 28 height: 40px; 29 } 30 </style> 31 32 <body> 33 <!-- Verifies that dragging mouse in/out of an element doesn't fire redundant 34 mouseenter or mouseleave events (crbug.com/356090 & crbug.com/470258) --> 35 <div id="outer"> 36 <div id="inner"></div> 37 </div> 38 <div id="done"></div> 39 </body> 40 <script> 41 let eventLog = []; 42 let nextUncheckedEventIndex = 0; 43 44 // Ensure match to the next sequence of events in the event log. 45 function assert_next_events(target, expectedEventNames, message) { 46 for (let i = 0; i < expectedEventNames.length; i++) { 47 assert_true(nextUncheckedEventIndex < eventLog.length, 48 `${message}: empty event queue`); 49 const observed = eventLog[nextUncheckedEventIndex++]; 50 const expected = `${expectedEventNames[i]}@${target.id}`; 51 assert_equals(observed, expected,`${message}: Event mismatch`); 52 } 53 } 54 55 // After validating the expected events, all entries in the event map 56 // must be false or we have recorded an unexpected event. 57 function assert_empty_event_queue(message) { 58 const uncheckedEvents = eventLog.length - nextUncheckedEventIndex; 59 assert_equals(uncheckedEvents, 0, 60 `${message}: Unexpected events ` + 61 `${eventLog.slice(-uncheckedEvents).join(", ")}`); 62 } 63 64 function addEventListeners(test) { 65 const eventTypes = [ 66 'mousedown', 67 'mouseenter', 68 'mouseleave', 69 'mousemove', 70 'mouseout', 71 'mouseover', 72 'mouseup' 73 ]; 74 ['inner', 'outer'].forEach(id => { 75 const element = document.getElementById(id); 76 eventTypes.forEach(eventType => { 77 const listener = (e) => { 78 if (e.eventPhase == Event.AT_TARGET) { 79 eventLog.push(`${eventType}@${id}`); 80 } 81 }; 82 element.addEventListener(eventType, listener); 83 test.add_cleanup(() => { 84 element.removeEventListener(eventType, listener); 85 }); 86 }) 87 }); 88 } 89 90 // A click on `done` marks the end of actions in each promise_test. 91 async function getClick(target, test) { 92 return new Promise(resolve => { 93 const listener = e => resolve(e); 94 target.addEventListener('click', listener, { once: true }); 95 if (test) { 96 test.add_cleanup(() => 97 target.removeEventListener('click', listener, { once: true })); 98 } 99 }); 100 } 101 102 window.onload = async () => { 103 const outer = document.getElementById('outer'); 104 const inner = document.getElementById('inner'); 105 const done = document.getElementById('done'); 106 const leftOuter = 0; 107 const rightOuter = 100; 108 const leftInner = 30; 109 const rightInner = 70; 110 const centerY = 50; 111 112 promise_test(async t => { 113 addEventListeners(t); 114 const completionPromise = getClick(done, t); 115 const actions =new test_driver.Actions(); 116 actions.pointerMove(leftOuter + 10, centerY) 117 .pointerDown({button: actions.ButtonType.LEFT}) 118 .pointerMove(rightOuter - 10, centerY) 119 .pointerUp({button: actions.ButtonType.LEFT}) 120 .pointerMove(0, 0, {origin: done}) 121 .pointerDown() 122 .pointerUp() 123 .send(); 124 await actions; 125 await completionPromise; 126 127 assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'], 128 'Move over outer element'); 129 assert_next_events(outer, ['mousedown', 'mousemove', 'mouseup'], 130 'Drag across outer element'); 131 assert_next_events(outer, ['mouseout', 'mouseleave'], 132 'Move to origin'); 133 assert_empty_event_queue('Drag across outer element'); 134 }, 'Test dragging across inner div'); 135 136 promise_test(async t => { 137 addEventListeners(t); 138 const completionPromise = getClick(done, t); 139 const actions =new test_driver.Actions(); 140 actions.pointerMove(leftOuter + 10, centerY) 141 .pointerDown({button: actions.ButtonType.LEFT}) 142 .pointerMove(leftInner + 10, centerY) 143 .pointerUp({button: actions.ButtonType.LEFT}) 144 .pointerMove(0, 0, {origin: done}) 145 .pointerDown() 146 .pointerUp() 147 .send(); 148 await actions; 149 await completionPromise; 150 151 assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'], 152 'Move over outer element'); 153 assert_next_events(outer, ['mousedown', 'mouseout'], 154 'Initiate drag'); 155 assert_next_events(inner, 156 ['mouseover', 'mouseenter', 'mousemove', 'mouseup'], 157 'Drag into inner element'); 158 assert_next_events(inner, ['mouseout', 'mouseleave'], 159 'Move to origin'); 160 assert_next_events(outer, [ 'mouseleave'], 161 'Move to origin'); 162 assert_empty_event_queue('Drag into inner element'); 163 }, 'Test dragging into inner div'); 164 165 promise_test(async t => { 166 addEventListeners(t); 167 const completionPromise = getClick(done, t); 168 const actions =new test_driver.Actions(); 169 actions.pointerMove(leftInner + 10, centerY) 170 .pointerDown({button: actions.ButtonType.LEFT}) 171 .pointerMove(rightInner + 10, centerY) 172 .pointerUp({button: actions.ButtonType.LEFT}) 173 .pointerMove(0, 0, {origin: done}) 174 .pointerDown() 175 .pointerUp() 176 .send(); 177 await actions; 178 await completionPromise; 179 180 assert_next_events(inner, ['mouseover'], 'Move over inner element'); 181 assert_next_events(outer, ['mouseenter'], 'Enter outer'); 182 assert_next_events(inner, ['mouseenter', 'mousemove'], 183 'Move across inner element'); 184 assert_next_events(inner, ['mousedown', 'mouseout', 'mouseleave'], 185 'Drag out of inner'); 186 assert_next_events(outer, ['mouseover', 'mousemove', 'mouseup'], 187 'Drag into outer'); 188 assert_next_events(outer, ['mouseout', 'mouseleave'], 189 'Move to origin'); 190 assert_empty_event_queue('Drag into inner element'); 191 }, 'Test dragging out of inner div'); 192 }; 193 </script> 194 </html>