helper_long_tap.html (8857B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width; initial-scale=1.0"> 6 <title>Ensure we get a touch-cancel after a contextmenu comes up</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 type="application/javascript"> 11 12 function addMouseEventListeners(aTarget) { 13 aTarget.addEventListener("mousemove", recordEvent, true); 14 aTarget.addEventListener("mouseover", recordEvent, true); 15 aTarget.addEventListener("mouseenter", recordEvent, true); 16 aTarget.addEventListener("mouseout", recordEvent, true); 17 aTarget.addEventListener("mouseleave", recordEvent, true); 18 } 19 20 function removeMouseEventListeners(aTarget) { 21 aTarget.removeEventListener("mousemove", recordEvent, true); 22 aTarget.removeEventListener("mouseover", recordEvent, true); 23 aTarget.removeEventListener("mouseenter", recordEvent, true); 24 aTarget.removeEventListener("mouseout", recordEvent, true); 25 aTarget.removeEventListener("mouseleave", recordEvent, true); 26 } 27 28 async function longPressLink() { 29 let target = document.getElementById("b"); 30 addMouseEventListeners(target); 31 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, function() { 32 dump("Finished synthesizing touch-start, waiting for events...\n"); 33 }); 34 } 35 36 var eventsFired = 0; 37 function recordEvent(e) { 38 let target = document.getElementById("b"); 39 const platform = getPlatform(); 40 if (platform == "windows") { 41 // On Windows we get a mouselongtap event once the long-tap has been detected 42 // by APZ, and that's what we use as the trigger to lift the finger. That then 43 // triggers the contextmenu. This matches the platform convention. 44 switch (eventsFired) { 45 case 0: is(e.type, "touchstart", "Got a touchstart"); break; 46 case 1: 47 is(e.type, "mouselongtap", "Got a mouselongtap"); 48 setTimeout(async () => { 49 await synthesizeNativeTouch(document.getElementById("b"), 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE); 50 }, 0); 51 break; 52 case 2: is(e.type, "touchend", "Got a touchend"); break; 53 case 3: is(e.type, "mouseover", "Got a mouseover"); break; 54 case 4: is(e.type, "mouseenter", "Got a mouseenter"); break; 55 case 5: is(e.type, "mousemove", "Got a mousemove"); break; 56 case 6: is(e.type, "contextmenu", "Got a contextmenu"); e.preventDefault(); break; 57 default: ok(false, "Got an unexpected event of type " + e.type); break; 58 } 59 eventsFired++; 60 61 if (eventsFired == 7) { 62 removeMouseEventListeners(target); 63 dump("Finished waiting for events, doing an APZ flush to see if any more unexpected events come through...\n"); 64 promiseOnlyApzControllerFlushed().then(function() { 65 dump("Done APZ flush, ending test...\n"); 66 subtestDone(); 67 }); 68 } 69 } else if (platform != "android") { 70 // On non-Windows desktop platforms we get a contextmenu event once the 71 // long-tap has been detected. Since we prevent-default that, we don't get 72 // a mouselongtap event at all, and instead get a touchcancel. 73 switch (eventsFired) { 74 case 0: is(e.type, "touchstart", "Got a touchstart"); break; 75 case 1: is(e.type, "mouseover", "Got a mouseover"); break; 76 case 2: is(e.type, "mouseenter", "Got a mouseenter"); break; 77 case 3: is(e.type, "mousemove", "Got a mousemove"); break; 78 case 4: is(e.type, "contextmenu", "Got a contextmenu"); 79 // Do preventDefault() in this content, thus we will not get any 80 // touchcancel event. 81 e.preventDefault(); 82 setTimeout(async () => { 83 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() { 84 dump("Finished synthesizing touch-end, waiting for a touchend event...\n"); 85 }); 86 }, 0); 87 break; 88 case 5: is(e.type, "touchend", "Got a touchend"); 89 // Send another long press. 90 setTimeout(async () => { 91 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, function() { 92 dump("Finished synthesizing touch-start, waiting for events...\n"); 93 }); 94 }, 0); 95 break; 96 case 6: is(e.type, "touchstart", "Got another touchstart"); break; 97 // NOTE: In this another event case, we don't get mouseover or mouseenter 98 // event either since the target element hasn't been changed. 99 case 7: is(e.type, "mousemove", "Got another mousemove"); break; 100 case 8: is(e.type, "contextmenu", "Got another contextmenu"); 101 // DON'T DO preventDefault() this time, thus we should get a touchcancel 102 // event. 103 break; 104 case 9: is(e.type, "mouselongtap", "Got a mouselongtap"); break; 105 case 10: is(e.type, "touchcancel", "Got a touchcancel"); break; 106 default: ok(false, "Got an unexpected event of type " + e.type); break; 107 } 108 eventsFired++; 109 110 if (eventsFired == 11) { 111 removeMouseEventListeners(target); 112 113 setTimeout(async () => { 114 // Ensure the context menu got closed, otherwise in the next test case 115 // events will be consumed by the context menu unfortunately. 116 await closeContextMenu(); 117 118 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() { 119 dump("Finished synthesizing touch-end, doing an APZ flush to see if any more unexpected events come through...\n"); 120 promiseOnlyApzControllerFlushed().then(function() { 121 dump("Done APZ flush, ending test...\n"); 122 subtestDone(); 123 }); 124 }); 125 }, 0); 126 } 127 } else { 128 // On Android we get a contextmenu event once the long-tap has been 129 // detected. If contextmenu opens we get a touchcancel event, and if 130 // contextmenu didn't open because of preventDefault() in the content, 131 // we will not get the touchcancel event. 132 switch (eventsFired) { 133 case 0: is(e.type, "touchstart", "Got a touchstart"); break; 134 case 1: is(e.type, "mouseover", "Got a mouseover"); break; 135 case 2: is(e.type, "mouseenter", "Got a mouseenter"); break; 136 case 3: is(e.type, "mousemove", "Got a mousemove"); break; 137 case 4: is(e.type, "contextmenu", "Got a contextmenu"); 138 // Do preventDefault() in this content, thus we will not get any 139 // touchcancel event. 140 e.preventDefault(); 141 setTimeout(async () => { 142 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() { 143 dump("Finished synthesizing touch-end, waiting for a touchend event...\n"); 144 }); 145 }, 0); 146 break; 147 case 5: is(e.type, "touchend", "Got a touchend"); 148 // Send another long press. 149 setTimeout(async () => { 150 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, function() { 151 dump("Finished synthesizing touch-start, waiting for events...\n"); 152 }); 153 }, 0); 154 break; 155 case 6: is(e.type, "touchstart", "Got another touchstart"); break; 156 // NOTE: In this another event case, we don't get mouseover or mouseenter 157 // event either since the target element hasn't been changed. 158 case 7: is(e.type, "mousemove", "Got another mousemove"); break; 159 case 8: is(e.type, "contextmenu", "Got another contextmenu"); 160 // DON'T DO preventDefault() this time, thus we should get a touchcancel 161 // event. 162 break; 163 case 9: is(e.type, "touchcancel", "Got a touchcancel"); break; 164 default: ok(false, "Got an unexpected event of type " + e.type); break; 165 } 166 eventsFired++; 167 168 if (eventsFired == 10) { 169 removeMouseEventListeners(target); 170 setTimeout(async () => { 171 await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() { 172 dump("Finished synthesizing touch-end, doing an APZ flush to see if any more unexpected events come through...\n"); 173 promiseOnlyApzControllerFlushed().then(function() { 174 dump("Done APZ flush, ending test...\n"); 175 subtestDone(); 176 }); 177 }); 178 }, 0); 179 } 180 } 181 } 182 183 window.addEventListener("touchstart", recordEvent, { passive: true, capture: true }); 184 window.addEventListener("touchend", recordEvent, { passive: true, capture: true }); 185 window.addEventListener("touchcancel", recordEvent, true); 186 window.addEventListener("contextmenu", recordEvent, true); 187 SpecialPowers.addChromeEventListener("mouselongtap", recordEvent, true); 188 189 waitUntilApzStable() 190 .then(longPressLink); 191 192 </script> 193 </head> 194 <body> 195 <a id="b" href="#">Link to nowhere</a> 196 </body> 197 </html>