browser_touch_all_events.js (6783B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 "use strict"; 6 7 const TEST_URL = `${URL_ROOT_COM_SSL}touch_iframe_parent.html`; 8 const TEST_URL2 = `${URL_ROOT_COM_SSL}touch_iframe_parent_desktop.html`; 9 const REMOTE_IFRAME_URL = `${URL_ROOT_ORG_SSL}touch_iframe_child.html`; 10 11 const EXPECTED_TAP_EVENTS = 12 "pointerdown touchstart pointerup touchend mousemove mousedown mouseup click"; 13 const EXPECTED_DRAG_EVENTS = 14 "pointerdown touchstart pointermove touchmove pointerup touchend"; 15 const EXPECTED_DOUBLE_TAP_EVENTS = `${EXPECTED_TAP_EVENTS} ${EXPECTED_TAP_EVENTS} dblclick`; 16 const EXPECTED_DOUBLE_TAP_ZOOM_EVENTS = `pointerdown touchstart pointerup touchend pointerdown touchstart pointerup touchend`; 17 const EXPECTED_LONG_TAP_EVENTS = `pointerdown touchstart mousemove contextmenu pointerup touchend`; 18 19 addRDMTask(TEST_URL, async function ({ ui }) { 20 reloadOnTouchChange(true); 21 await toggleTouchSimulation(ui); 22 await runTests( 23 ui, 24 ["topFrame", "localIFrame", "remoteIFrame"], 25 ["tap", "drag", "double_tap", "long_tap"] 26 ); 27 await toggleTouchSimulation(ui); 28 }); 29 30 // The following tests change the page's zoom state, so we run each of them 31 // separately to ensure they don't interfere with each other. 32 for (const frameName of ["topFrame", "localIFrame", "remoteIFrame"]) { 33 addRDMTask(TEST_URL2, async function ({ ui }) { 34 reloadOnTouchChange(true); 35 await toggleTouchSimulation(ui); 36 await runTests(ui, [frameName], ["double_tap_zoom"]); 37 await toggleTouchSimulation(ui); 38 }); 39 } 40 41 function runTests(ui, frameNames, tests) { 42 return spawnViewportTask( 43 ui, 44 { 45 tests, 46 frameNames, 47 REMOTE_IFRAME_URL, 48 EXPECTED_TAP_EVENTS, 49 EXPECTED_DOUBLE_TAP_EVENTS, 50 EXPECTED_DOUBLE_TAP_ZOOM_EVENTS, 51 EXPECTED_LONG_TAP_EVENTS, 52 EXPECTED_DRAG_EVENTS, 53 }, 54 async args => { 55 const frames = { 56 topFrame: content.document.body, 57 localIFrame: content.document.getElementById("local-iframe"), 58 remoteIFrame: content.document.getElementById("remote-iframe"), 59 }; 60 61 // Load the remote iframe and wait for it to be loaded. 62 frames.remoteIFrame.src = args.REMOTE_IFRAME_URL; 63 await ContentTaskUtils.waitForEvent(frames.remoteIFrame, "load"); 64 // Wait for the remote iframe to be ready to receive events. 65 await SpecialPowers.spawn(frames.remoteIFrame, [], async () => { 66 await SpecialPowers.contentTransformsReceived(content); 67 }); 68 69 const body = content.document.body; 70 71 async function checkEventLog(expectedFrame, expectedEvents, test) { 72 const lastExpectedEvent = expectedEvents.substring( 73 expectedEvents.lastIndexOf(" ") + 1 74 ); 75 await waitForEventFromFrame(expectedFrame, lastExpectedEvent, 2000); 76 // wait some more to ensure there are no unexpected delayed events 77 await waitForTime(500); 78 79 for (const frameName of ["topFrame", "localIFrame", "remoteIFrame"]) { 80 const expected = 81 frameName === expectedFrame ? expectedEvents : undefined; 82 is( 83 body.dataset[frameName], 84 expected, 85 `${frameName} received the expected events in the ${test} test` 86 ); 87 } 88 } 89 90 function clearEventLog() { 91 for (const key of Object.keys(body.dataset)) { 92 delete body.dataset[key]; 93 } 94 } 95 96 function waitForTime(ms) { 97 return new Promise(resolve => { 98 content.setTimeout(resolve, ms); 99 }); 100 } 101 102 function synthesizeMouseEvent(target, type, offsetX, offsetY) { 103 return new Promise(resolve => { 104 EventUtils.synthesizeNativeMouseEvent( 105 { 106 target, 107 type, 108 offsetX, 109 offsetY, 110 win: content, 111 }, 112 resolve 113 ); 114 }); 115 } 116 117 async function synthesizeClick(target, waitFor) { 118 await synthesizeMouseEvent(target, "mousedown", 50, 50); 119 if (waitFor) { 120 await waitFor(); 121 } 122 await synthesizeMouseEvent(target, "mouseup", 50, 50); 123 } 124 125 async function waitForEventFromFrame(frameName, type, timeout = 100) { 126 await ContentTaskUtils.waitForCondition( 127 () => body.dataset[frameName]?.split(" ").includes(type), 128 `Waiting for ${type} event from ${frameName}`, 129 10, 130 timeout / 10 131 ); 132 } 133 134 for (const frameName of args.frameNames) { 135 const frame = frames[frameName]; 136 for (const test of args.tests) { 137 clearEventLog(); 138 switch (test) { 139 case "tap": { 140 await synthesizeClick(frame); 141 await checkEventLog(frameName, args.EXPECTED_TAP_EVENTS, test); 142 break; 143 } 144 145 case "drag": { 146 await synthesizeMouseEvent(frame, "mousedown", 50, 50); 147 await synthesizeMouseEvent(frame, "mousemove", 60, 50); 148 // wait for the touchmove event to be received before synthesizing the next one 149 // to ensure the received events are in the expected order 150 await waitForEventFromFrame(frameName, "touchmove"); 151 await synthesizeMouseEvent(frame, "mouseup", 60, 50); 152 await checkEventLog(frameName, args.EXPECTED_DRAG_EVENTS, test); 153 break; 154 } 155 156 case "long_tap": { 157 await synthesizeClick(frame, () => 158 waitForEventFromFrame(frameName, "contextmenu", 1000) 159 ); 160 await checkEventLog( 161 frameName, 162 args.EXPECTED_LONG_TAP_EVENTS, 163 test 164 ); 165 break; 166 } 167 168 case "double_tap": { 169 await synthesizeClick(frame); 170 // wait for the click event to be received before synthesizing the next one 171 // to ensure the received events are in the expected order 172 await waitForEventFromFrame(frameName, "click"); 173 await synthesizeClick(frame); 174 await checkEventLog( 175 frameName, 176 args.EXPECTED_DOUBLE_TAP_EVENTS, 177 test 178 ); 179 break; 180 } 181 182 case "double_tap_zoom": { 183 await synthesizeClick(frame); 184 await synthesizeClick(frame); 185 await checkEventLog( 186 frameName, 187 args.EXPECTED_DOUBLE_TAP_ZOOM_EVENTS, 188 test 189 ); 190 break; 191 } 192 } 193 } 194 } 195 } 196 ); 197 }