mochitest_support_external.js (8835B)
1 // This file supports translating W3C tests 2 // to tests on auto MochiTest system with minimum changes. 3 // Author: Maksim Lebedev <alessarik@gmail.com> 4 5 /* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ 6 7 // Function allows to prepare our tests after load document 8 addEventListener( 9 "load", 10 function (event) { 11 console.log("OnLoad external document"); 12 prepareTest(); 13 }, 14 false 15 ); 16 17 // Function allows to initialize prerequisites before testing 18 function prepareTest() { 19 SimpleTest.waitForExplicitFinish(); 20 SimpleTest.requestCompleteLog(); 21 startTest(); 22 } 23 24 function setImplicitPointerCapture(capture, callback) { 25 console.log("SET dom.w3c_pointer_events.implicit_capture as " + capture); 26 SpecialPowers.pushPrefEnv( 27 { 28 set: [["dom.w3c_pointer_events.implicit_capture", capture]], 29 }, 30 callback 31 ); 32 } 33 34 var utils = SpecialPowers.Ci.nsIDOMWindowUtils; 35 36 // Mouse Event Helper Object 37 var MouseEventHelper = (function () { 38 return { 39 MOUSE_ID: utils.DEFAULT_MOUSE_POINTER_ID, 40 PEN_ID: utils.DEFAULT_PEN_POINTER_ID, 41 // State 42 // TODO: Separate this to support mouse and pen simultaneously. 43 BUTTONS_STATE: utils.MOUSE_BUTTONS_NO_BUTTON, 44 45 // Button 46 BUTTON_NONE: -1, // Used by test framework only. (replaced before sending) 47 BUTTON_LEFT: utils.MOUSE_BUTTON_LEFT_BUTTON, 48 BUTTON_MIDDLE: utils.MOUSE_BUTTON_MIDDLE_BUTTON, 49 BUTTON_RIGHT: utils.MOUSE_BUTTON_RIGHT_BUTTON, 50 51 // Buttons 52 BUTTONS_NONE: utils.MOUSE_BUTTONS_NO_BUTTON, 53 BUTTONS_LEFT: utils.MOUSE_BUTTONS_LEFT_BUTTON, 54 BUTTONS_MIDDLE: utils.MOUSE_BUTTONS_MIDDLE_BUTTON, 55 BUTTONS_RIGHT: utils.MOUSE_BUTTONS_RIGHT_BUTTON, 56 BUTTONS_4TH: utils.MOUSE_BUTTONS_4TH_BUTTON, 57 BUTTONS_5TH: utils.MOUSE_BUTTONS_5TH_BUTTON, 58 59 // Utils 60 computeButtonsMaskFromButton(aButton) { 61 // Since the range of button values is 0 ~ 2 (see nsIDOMWindowUtils.idl), 62 // we can use an array to find out the desired mask. 63 var mask = [ 64 this.BUTTONS_NONE, // -1 (MouseEventHelper.BUTTON_NONE) 65 this.BUTTONS_LEFT, // 0 66 this.BUTTONS_MIDDLE, // 1 67 this.BUTTONS_RIGHT, // 2 68 ][aButton + 1]; 69 70 ok(mask !== undefined, "Unrecognized button value caught!"); 71 return mask; 72 }, 73 74 checkExitState() { 75 ok(!this.BUTTONS_STATE, "Mismatched mousedown/mouseup caught."); 76 }, 77 }; 78 })(); 79 80 function createMouseEvent(aEventType, aParams) { 81 var eventObj = { type: aEventType }; 82 83 // Default to mouse. 84 eventObj.inputSource = 85 aParams && "inputSource" in aParams 86 ? aParams.inputSource 87 : MouseEvent.MOZ_SOURCE_MOUSE; 88 // Compute pointerId 89 eventObj.id = 90 eventObj.inputSource === MouseEvent.MOZ_SOURCE_MOUSE 91 ? MouseEventHelper.MOUSE_ID 92 : MouseEventHelper.PEN_ID; 93 // Check or generate a |button| value. 94 var isButtonEvent = aEventType === "mouseup" || aEventType === "mousedown"; 95 96 // Set |button| to the default value first. 97 eventObj.button = isButtonEvent 98 ? MouseEventHelper.BUTTON_LEFT 99 : MouseEventHelper.BUTTON_NONE; 100 101 // |button| is passed, use and check it. 102 if (aParams && "button" in aParams) { 103 var hasButtonValue = aParams.button !== MouseEventHelper.BUTTON_NONE; 104 ok( 105 !isButtonEvent || hasButtonValue, 106 "Inappropriate |button| value caught." 107 ); 108 eventObj.button = aParams.button; 109 } 110 111 // Generate a |buttons| value and update buttons state 112 var buttonsMask = MouseEventHelper.computeButtonsMaskFromButton( 113 eventObj.button 114 ); 115 switch (aEventType) { 116 case "mousedown": 117 MouseEventHelper.BUTTONS_STATE |= buttonsMask; // Set button flag. 118 break; 119 case "mouseup": 120 MouseEventHelper.BUTTONS_STATE &= ~buttonsMask; // Clear button flag. 121 break; 122 } 123 eventObj.buttons = MouseEventHelper.BUTTONS_STATE; 124 125 // Replace the button value for mousemove events. 126 // Since in widget level design, even when no button is pressed at all, the 127 // value of WidgetMouseEvent.button is still 0, which is the same value as 128 // the one for mouse left button. 129 if (aEventType === "mousemove") { 130 eventObj.button = MouseEventHelper.BUTTON_LEFT; 131 } 132 return eventObj; 133 } 134 135 // Helper function to send MouseEvent with different parameters 136 function sendMouseEvent(int_win, elemId, mouseEventType, params) { 137 var elem = int_win.document.getElementById(elemId); 138 if (elem) { 139 var rect = elem.getBoundingClientRect(); 140 var eventObj = createMouseEvent(mouseEventType, params); 141 142 // Default to the center of the target element but we can still send to a 143 // position outside of the target element. 144 var offsetX = 145 params && "offsetX" in params ? params.offsetX : rect.width / 2; 146 var offsetY = 147 params && "offsetY" in params ? params.offsetY : rect.height / 2; 148 149 console.log(elemId, eventObj); 150 synthesizeMouse(elem, offsetX, offsetY, eventObj, int_win); 151 } else { 152 is(!!elem, true, "Document should have element with id: " + elemId); 153 } 154 } 155 156 // Helper function to send MouseEvent with position 157 function sendMouseEventAtPoint(aWindow, aLeft, aTop, aMouseEventType, aParams) { 158 var eventObj = createMouseEvent(aMouseEventType, aParams); 159 console.log(eventObj); 160 synthesizeMouseAtPoint(aLeft, aTop, eventObj, aWindow); 161 } 162 163 // Touch Event Helper Object 164 var TouchEventHelper = { 165 // State 166 TOUCH_ID: utils.DEFAULT_TOUCH_POINTER_ID, 167 TOUCH_STATE: false, 168 169 // Utils 170 checkExitState() { 171 ok(!this.TOUCH_STATE, "Mismatched touchstart/touchend caught."); 172 }, 173 }; 174 175 // Helper function to send TouchEvent with different parameters 176 // TODO: Support multiple touch points to test more features such as 177 // PointerEvent.isPrimary and pinch-zoom. 178 function sendTouchEvent(int_win, elemId, touchEventType, params) { 179 var elem = int_win.document.getElementById(elemId); 180 if (elem) { 181 var rect = elem.getBoundingClientRect(); 182 var eventObj = { 183 type: touchEventType, 184 id: TouchEventHelper.TOUCH_ID, 185 }; 186 187 // Update touch state 188 switch (touchEventType) { 189 case "touchstart": 190 TouchEventHelper.TOUCH_STATE = true; // Set touch flag. 191 break; 192 case "touchend": 193 case "touchcancel": 194 TouchEventHelper.TOUCH_STATE = false; // Clear touch flag. 195 break; 196 } 197 198 // Default to the center of the target element but we can still send to a 199 // position outside of the target element. 200 var offsetX = 201 params && "offsetX" in params ? params.offsetX : rect.width / 2; 202 var offsetY = 203 params && "offsetY" in params ? params.offsetY : rect.height / 2; 204 205 console.log(elemId, eventObj); 206 synthesizeTouch(elem, offsetX, offsetY, eventObj, int_win); 207 } else { 208 is(!!elem, true, "Document should have element with id: " + elemId); 209 } 210 } 211 212 // Helper function to trigger drag and drop. 213 async function doDragAndDrop(int_win, srcElemId, destElemId, params = {}) { 214 params.srcElement = int_win.document.getElementById(srcElemId); 215 params.destElement = int_win.document.getElementById(destElemId); 216 params.srcWindow = int_win; 217 params.destWindow = int_win; 218 params.id = MouseEventHelper.MOUSE_ID; 219 // This is basically for android which has a larger drag threshold. 220 params.stepY = params.stepY || 25; 221 await synthesizePlainDragAndDrop(params); 222 } 223 224 // Helper function to run Point Event test in a new tab. 225 function runTestInNewWindow(aFile) { 226 var testURL = 227 location.href.substring(0, location.href.lastIndexOf("/") + 1) + aFile; 228 var testWindow = window.open(testURL, "_blank"); 229 var testDone = false; 230 231 // We start testing when receiving load event. Inject the mochitest helper js 232 // to the test case after DOM elements are constructed and before the load 233 // event is fired. 234 testWindow.addEventListener( 235 "DOMContentLoaded", 236 function () { 237 var e = testWindow.document.createElement("script"); 238 e.type = "text/javascript"; 239 e.src = 240 "../".repeat(aFile.split("/").length - 1) + 241 "mochitest_support_internal.js"; 242 testWindow.document.getElementsByTagName("head")[0].appendChild(e); 243 }, 244 { once: true } 245 ); 246 247 window.addEventListener("message", function (aEvent) { 248 switch (aEvent.data.type) { 249 case "START": 250 // Update constants 251 MouseEventHelper.MOUSE_ID = aEvent.data.message.mouseId; 252 MouseEventHelper.PEN_ID = aEvent.data.message.penId; 253 TouchEventHelper.TOUCH_ID = aEvent.data.message.touchId; 254 255 executeTest(testWindow); 256 break; 257 case "RESULT": 258 // Should not perform checking after SimpleTest.finish(). 259 if (!testDone) { 260 ok(aEvent.data.result, aEvent.data.message); 261 } 262 break; 263 case "FIN": 264 testDone = true; 265 MouseEventHelper.checkExitState(); 266 TouchEventHelper.checkExitState(); 267 testWindow.close(); 268 SimpleTest.finish(); 269 break; 270 } 271 }); 272 }