mouseover-at-removing-mousedown-target.html (2855B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="timeout" content="long"> 6 <meta name="variant" content="?duration=16"> <!-- 60fps --> 7 <meta name="variant" content="?duration=42"> <!-- 24fps --> 8 <title>Check whether `mouseup` events are fired after pending boundary events</title> 9 <script src=/resources/testharness.js></script> 10 <script src=/resources/testharnessreport.js></script> 11 <script src=/resources/testdriver.js></script> 12 <script src=/resources/testdriver-actions.js></script> 13 <script src=/resources/testdriver-vendor.js></script> 14 <style> 15 div#parent { 16 width: 100%; 17 height: 50px; 18 background-color: gray; 19 } 20 div#child { 21 width: 100%; 22 height: 40px; 23 background-color: lime; 24 } 25 </style> 26 </head> 27 <body> 28 <div id="parent"><div id="child"></div></div> 29 <script> 30 "use strict"; 31 32 const searchParams = new URLSearchParams(document.location.search); 33 const duration = parseInt(searchParams.get("duration")); 34 35 async function runTest(t) { 36 const parent = document.getElementById("parent"); 37 const child = document.getElementById("child"); 38 const mouseEvents = []; 39 function onMouseOverOrUp(event) { 40 // Ignore events before `mousedown` to make this test simpler. 41 if (mouseEvents[0]?.startsWith("mousedown")) { 42 mouseEvents.push(`${event.type}@${event.target.localName}${event.target.id ? `#${event.target.id}` : ""}`); 43 } 44 } 45 try { 46 child.getBoundingClientRect(); // flush layout 47 child.addEventListener("mousedown", event => { 48 event.target.remove(); 49 mouseEvents.push("mousedown@div#child"); 50 }, {once: true}); 51 document.addEventListener("mouseover", onMouseOverOrUp, {capture: true}); 52 document.addEventListener("mouseup", onMouseOverOrUp, {once: true, capture: true}); 53 const actions = new test_driver.Actions(duration); 54 await actions.pointerMove(10, 10, {origin: child}) 55 .pointerDown({button: actions.ButtonType.LEFT}) 56 .pointerUp({button: actions.ButtonType.LEFT}) 57 .send(); 58 await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); 59 assert_equals( 60 mouseEvents.toString(), 61 "mousedown@div#child,mouseover@div#parent,mouseup@div#parent", 62 t.name 63 ); 64 } finally { 65 document.removeEventListener("mouseover", onMouseOverOrUp, {capture: true}); 66 parent.appendChild(child); 67 } 68 } 69 70 // This test tries to detect intermittent case that mouseout might be fired 71 // after a while from a DOM tree change. Therefore, trying same test 30 times. 72 for (let i = 0; i < 30; i++) { 73 promise_test(async t => { 74 await runTest(t); 75 // Make things stabler to start next test. 76 await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); 77 }, `mouseover should be fired before mouseup if mousedown target is removed (${i})`); 78 } 79 </script> 80 </body> 81 </html>