helper_no_synth_mousemove_after_pan.html (5192B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width; initial-scale=1.0,minimum-scale=1.0"> 6 <title>Test for no synthetic eMouseMove after swipe to scroll</title> 7 <script type="application/javascript" src="apz_test_native_event_utils.js"></script> 8 <script type="application/javascript" src="apz_test_utils.js"></script> 9 <script src="/tests/SimpleTest/paint_listener.js"></script> 10 <script src="/tests/SimpleTest/EventUtils.js"></script> 11 <style> 12 body { 13 margin: 0; 14 } 15 div { 16 margin: 0; 17 height: 2lh; 18 } 19 div:hover { 20 background-color: limegreen; 21 } 22 </style> 23 <script> 24 "use strict"; 25 26 addEventListener("DOMContentLoaded", () => { 27 document.body.innerHTML = ""; 28 for (let i = 0; i < 100; i++) { 29 const div = document.createElement("div"); 30 div.id = `div${i}`; 31 document.body.appendChild(div); 32 } 33 document.documentElement.getBoundingClientRect(); 34 waitUntilApzStable() 35 .then(test) 36 .then(subtestDone, subtestFailed); 37 }, {once: true}); 38 39 async function test() { 40 while (document.documentElement.scrollY == 0) { 41 // the scrollframe is not yet marked as APZ-scrollable. Mark it so 42 // before continuing. 43 document.documentElement.scrollTo(0, 1); 44 await promiseApzFlushedRepaints(); 45 } 46 const height = window.innerHeight; 47 const divToBeSwiped = document.body.querySelector(`div:nth-child(${ 48 Math.floor(height / document.body.firstElementChild.getBoundingClientRect().height) 49 })`); 50 const divToBeSwipedRect = divToBeSwiped.getBoundingClientRect(); 51 ok( 52 height > divToBeSwipedRect.height * 5, 53 `The viewport should be able to show at least 5 <div> elements, expected taller than ${ 54 divToBeSwipedRect.height * 5 55 }, but ${height}` 56 ); 57 // Wait for synthesized mousemove is flushed in the next animation frame 58 // before doing some since it'll fix the `:hover` state and mouse/pointer 59 // boundary event state with the latest layout. 60 function flushPendingSynthesizedMouseMove(aCallback) { 61 requestAnimationFrame( 62 () => requestAnimationFrame(aCallback) 63 ); 64 } 65 function promiseFlushPendingSynthesizedMouseMove() { 66 return new Promise(resolve => { 67 flushPendingSynthesizedMouseMove(resolve); 68 }); 69 } 70 71 // First, make PresShell forgets the last mouse location which may be set accidentally. 72 synthesizeMouseAtCenter(divToBeSwiped, {type: "mousecancel"}, {once: true}); 73 // Hopefully, synthesize a tap first. That may cause PresShell storing the 74 // tap point as the last mouse location since that should cause a set of 75 // compatibility mouse events. 76 info("Synthesizing a tap..."); 77 const waitForClick = new Promise(resolve => { 78 addEventListener("click", event => { 79 is( 80 event.target, 81 divToBeSwiped, 82 "`click` should be fired on the bottom <div>" 83 ); 84 const clickPosition = { x: event.clientX, y: event.clientY }; 85 flushPendingSynthesizedMouseMove(() => resolve(clickPosition)); 86 }, {once: true}); 87 }); 88 await promiseNativePointerTap( 89 divToBeSwiped, 90 "touch", 91 divToBeSwipedRect.width / 2, 92 divToBeSwipedRect.height / 2 93 ); 94 info("Waiting for the click..."); 95 const clickPosition = await waitForClick; 96 // Then, swipe from the bottom <div> to above to scroll down. 97 info("Synthesizing a swipe..."); 98 const scrollTopBefore = document.documentElement.scrollTop; 99 const waitForPointerCancel = new Promise(resolve => { 100 addEventListener("pointercancel", resolve, {once: true}); 101 }); 102 const transformEndPromise = promiseTransformEnd(); 103 await promiseNativePointerDrag( 104 divToBeSwiped, 105 "touch", 106 divToBeSwipedRect.width / 2, 107 divToBeSwipedRect.height / 2, 108 0, // deltaX 109 divToBeSwipedRect.height * -3 // deltaY 110 ); 111 info("Waiting for pointercancel which should be caused by the swipe..."); 112 await waitForPointerCancel; 113 info("Waiting for transformEndPromise..."); 114 await transformEndPromise; 115 info("Waiting for promiseApzFlushedRepaints()..."); 116 await promiseApzFlushedRepaints(); 117 await promiseFlushPendingSynthesizedMouseMove(); 118 const scrollTopAfter = document.documentElement.scrollTop; 119 ok( 120 scrollTopBefore + divToBeSwipedRect.height < scrollTopAfter, 121 `The swipe should cause scrolling down, expected greater than ${ 122 scrollTopBefore + divToBeSwipedRect.height 123 } (scrollTopBefore: ${scrollTopBefore}), but got ${scrollTopAfter}` 124 ); 125 // Finally, the scroll down causes the element underneath the start position 126 // of the swipe is a following <div> of the original <div> element. However, 127 // user must not want the <div> to have the :hover state since they have not 128 // touched the <div>. 129 const hoveredDiv = document.querySelector("div:hover"); 130 const elementAtClickedPosition = document.elementFromPoint(clickPosition.x, clickPosition.y); 131 ok( 132 !hoveredDiv || hoveredDiv != elementAtClickedPosition, 133 `The div element at the previously clicked position should not have :hover state, got ${ 134 hoveredDiv ? hoveredDiv.outerHTML : "null" 135 }${ 136 elementAtClickedPosition 137 ? ` which should never be ${elementAtClickedPosition.outerHTML}` 138 : "" 139 }` 140 ); 141 } 142 </script> 143 </head> 144 <body></body> 145 </html>