test_sanityEventUtils.html (35062B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Profiling test suite for EventUtils</title> 5 <script type="text/javascript"> 6 var start = new Date(); 7 </script> 8 <script src="/tests/SimpleTest/EventUtils.js"></script> 9 <script type="text/javascript"> 10 var loadTime = new Date(); 11 </script> 12 <script src="/tests/SimpleTest/SimpleTest.js"></script> 13 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 14 </head> 15 <body onload="starttest()"> 16 <input type="radio" id="radioTarget1" name="group">Radio Target 1</input> 17 <input id="textBoxA"> 18 <input id="textBoxB"> 19 <input id="testMouseEvent" type="button" value="click"> 20 <input id="testKeyEvent" > 21 <input id="testStrEvent" > 22 <div id="scrollB" style="width: 190px;height: 250px;overflow:auto"> 23 <p>blah blah blah blah</p> 24 <p>blah blah blah blah</p> 25 <p>blah blah blah blah</p> 26 <p>blah blah blah blah</p> 27 <p>blah blah blah blah</p> 28 <p>blah blah blah blah</p> 29 <p>blah blah blah blah</p> 30 <p>blah blah blah blah</p> 31 </div> 32 <script class="testbody" type="text/javascript"> 33 info("\nProfile::EventUtilsLoadTime: " + (loadTime - start) + "\n"); 34 function starttest() { 35 SimpleTest.waitForFocus( 36 async function () { 37 SimpleTest.waitForExplicitFinish(); 38 var startTime = new Date(); 39 var check = false; 40 function doCheck() { 41 check = true; 42 } 43 44 const kIsHeadless = await SpecialPowers.spawnChrome([], () => { 45 return Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless; 46 }); 47 48 if (navigator.appVersion.includes("Android")) { 49 // This is the workaround for test failure on debug build. 50 await SpecialPowers.pushPrefEnv({set: [["formhelper.autozoom.force-disable.test-only", true]]}); 51 } 52 53 /* test send* functions */ 54 $("testMouseEvent").addEventListener("click", doCheck, {once: true}); 55 sendMouseEvent({type:'click'}, "testMouseEvent"); 56 is(check, true, 'sendMouseEvent should dispatch click event'); 57 58 await (async function testSynthesizeNativeMouseEvent() { 59 let events = []; 60 let listener = event => events.push(event); 61 let preventDefault = event => event.preventDefault(); 62 // promiseNativeMouseEventAndWaitForEvent uses capturing listeners 63 // internally, so use capturing listeners also here. 64 $("testMouseEvent").addEventListener("mousedown", listener, true); 65 $("testMouseEvent").addEventListener("mouseup", listener, true); 66 // Clicking with modifiers may open context menu so that we should prevent to open it. 67 window.addEventListener("contextmenu", preventDefault, { capture: true }); 68 for (const test of [ 69 { 70 description: "ShiftLeft", 71 modifiers: { shiftKey: true }, 72 }, 73 { 74 description: "ShiftRight", 75 modifiers: { shiftRightKey: true }, 76 }, 77 { 78 description: "CtrlLeft", 79 modifiers: { ctrlKey: true }, 80 }, 81 { 82 description: "CtrlRight", 83 modifiers: { ctrlRightKey: true }, 84 }, 85 { 86 description: "AltLeft", 87 modifiers: { altKey: true }, 88 }, 89 { 90 description: "AltRight", 91 modifiers: { altRightKey: true }, 92 }, 93 { 94 description: "MetaLeft", 95 modifiers: { metaKey: true }, 96 skip: () => { 97 // We've not supported "Meta" as Windows logo key or Super/Hyper keys. 98 return navigator.platform.includes("Win") || navigator.platform.includes("Linux"); 99 }, 100 }, 101 { 102 description: "MetaRight", 103 modifiers: { metaRightKey: true }, 104 skip: () => { 105 // We've not supported "Meta" as Windows logo key or Super/Hyper keys. 106 return navigator.platform.includes("Win") || navigator.platform.includes("Linux"); 107 }, 108 }, 109 { 110 description: "CapsLock", 111 modifiers: { capsLockKey: true }, 112 }, 113 { 114 description: "NumLock", 115 modifiers: { numLockKey: true }, 116 skip: () => { 117 // macOS does not have `NumLock` key nor state. 118 return navigator.platform.includes("Mac"); 119 }, 120 }, 121 { 122 description: "Ctrl+Shift", 123 modifiers: { ctrlKey: true, shiftKey: true }, 124 skip: () => { 125 // We forcibly open context menu on macOS so the following test 126 // will fail to receive mouse events. 127 return navigator.platform.includes("Mac"); 128 }, 129 }, 130 { 131 description: "Alt+Shift", 132 modifiers: { altKey: true, shiftKey: true }, 133 }, 134 { 135 description: "Meta+Shift", 136 modifiers: { metaKey: true, shiftKey: true }, 137 skip: () => { 138 // We've not supported "Meta" as Windows logo key or Super/Hyper keys. 139 return navigator.platform.includes("Win") || navigator.platform.includes("Linux"); 140 }, 141 }, 142 ]) { 143 if (test.skip && test.skip()) { 144 continue; 145 } 146 events = []; 147 info(`testSynthesizeNativeMouseEvent: sending native mouse click (${test.description})`); 148 await promiseNativeMouseEventAndWaitForEvent({ 149 type: "click", 150 target: $("testMouseEvent"), 151 atCenter: true, 152 modifiers: test.modifiers, 153 eventTypeToWait: "mouseup", 154 }); 155 is(events.length, 2, 156 `testSynthesizeNativeMouseEvent: a pair of "mousedown" and "mouseup" events should be fired (${test.description})`); 157 is(events[0]?.type, "mousedown", 158 `testSynthesizeNativeMouseEvent: "mousedown" should be fired (${test.description})`); 159 is(events[1]?.type, "mouseup", 160 `testSynthesizeNativeMouseEvent: "mouseup" should be fired (${test.description})`); 161 if (events.length !== 2) { 162 continue; 163 } 164 for (const mod of [{ keyName: "Alt", propNames: [ "altKey", "altRightKey" ]}, 165 { keyName: "Control", propNames: [ "ctrlKey", "ctrlRightKey" ]}, 166 { keyName: "Shift", propNames: [ "shiftKey", "shiftRightKey" ]}, 167 { keyName: "Meta", propNames: [ "metaKey", "metaRightKey" ]}, 168 { keyName: "CapsLock", propNames: [ "capsLockKey" ]}, 169 { keyName: "NumLock", propNames: [ "numLockKey" ]}, 170 ]) { 171 const activeExpected = 172 (test.modifiers.hasOwnProperty(mod.propNames[0]) && 173 test.modifiers[mod.propNames[0]]) || 174 (mod.propNames.length !== 1 && 175 test.modifiers.hasOwnProperty(mod.propNames[1]) && 176 test.modifiers[mod.propNames[1]]); 177 const checkFn = activeExpected && ( 178 // Bug 1693240: We don't support setting modifiers while posting a mouse event on Windows. 179 navigator.platform.includes("Win") || 180 // Bug 1693237: We don't support setting modifiers on Android. 181 navigator.appVersion.includes("Android") || 182 // In Headless mode, modifiers are not supported by this kind of APIs. 183 kIsHeadless) ? todo_is : is; 184 checkFn(events[0]?.getModifierState(mod.keyName), activeExpected, 185 `testSynthesizeNativeMouseEvent: "mousedown".getModifierState("${mod.keyName}") should return ${activeExpected} (${test.description}`); 186 checkFn(events[1]?.getModifierState(mod.keyName), activeExpected, 187 `testSynthesizeNativeMouseEvent: "mouseup".getModifierState("${mod.keyName}") should return ${activeExpected} (${test.description}`); 188 } 189 } 190 const supportsX1AndX2Buttons = 191 // On Windows, it triggers APP_COMMAND. Therefore, this test is unloaded. 192 !navigator.platform.includes("Win") && 193 // On macOS, it seems that no API to specify X1 and X2 button at creating an NSEvent. 194 !navigator.platform.includes("Mac") && 195 // On Linux, it seems that X1 button and X2 button events are not synthesized correctly. 196 !navigator.platform.includes("Linux"); 197 for (let i = 0; i < (supportsX1AndX2Buttons ? 5 : 3); i++) { 198 events = []; 199 info(`testSynthesizeNativeMouseEvent: sending native mouse click (button=${i})`); 200 await promiseNativeMouseEventAndWaitForEvent({ 201 type: "click", 202 target: $("testMouseEvent"), 203 atCenter: true, 204 button: i, 205 eventTypeToWait: "mouseup", 206 }); 207 is(events.length, 2, 208 `testSynthesizeNativeMouseEvent: a pair of "mousedown" and "mouseup" events should be fired (button=${i})`); 209 is(events[0]?.type, "mousedown", 210 `testSynthesizeNativeMouseEvent: "mousedown" should be fired (button=${i})`); 211 is(events[1]?.type, "mouseup", 212 `testSynthesizeNativeMouseEvent: "mouseup" should be fired (button=${i})`); 213 if (events.length !== 2) { 214 continue; 215 } 216 is(events[0].button, i, 217 `testSynthesizeNativeMouseEvent: button of "mousedown" event should be ${i}`); 218 is(events[1].button, i, 219 `testSynthesizeNativeMouseEvent: button of "mouseup" event should be ${i}`); 220 } 221 $("testMouseEvent").removeEventListener("mousedown", listener); 222 $("testMouseEvent").removeEventListener("mouseup", listener); 223 window.removeEventListener("contextmenu", preventDefault, { capture: true }); 224 })(); 225 226 check = false; 227 $("testKeyEvent").addEventListener("keypress", doCheck, {once: true}); 228 $("testKeyEvent").focus(); 229 sendChar("x"); 230 is($("testKeyEvent").value, "x", "sendChar should work"); 231 is(check, true, "sendChar should dispatch keyPress"); 232 $("testKeyEvent").value = ""; 233 234 $("testStrEvent").focus(); 235 sendString("string"); 236 is($("testStrEvent").value, "string", "sendString should work"); 237 $("testStrEvent").value = ""; 238 239 var keydown = false; 240 var keypress = false; 241 $("testKeyEvent").focus(); 242 $("testKeyEvent").addEventListener("keydown", function() { keydown = true; }, {once: true}); 243 $("testKeyEvent").addEventListener("keypress", function() { keypress = true; }, {once: true}); 244 sendKey("DOWN"); 245 ok(keydown, "sendKey should dispatch keyDown"); 246 ok(!keypress, "sendKey shouldn't dispatch keyPress for non-printable key"); 247 248 /* test synthesizeMouse* */ 249 //focus trick enables us to run this in iframes 250 $("radioTarget1").addEventListener('focus', function () { 251 synthesizeMouse($("radioTarget1"), 1, 1, {}); 252 is($("radioTarget1").checked, true, "synthesizeMouse should work") 253 $("radioTarget1").checked = false; 254 disableNonTestMouseEvents(true); 255 synthesizeMouse($("radioTarget1"), 1, 1, {}); 256 is($("radioTarget1").checked, true, "synthesizeMouse should still work with non-test mouse events disabled"); 257 $("radioTarget1").checked = false; 258 disableNonTestMouseEvents(false); 259 }, {once: true}); 260 $("radioTarget1").focus(); 261 262 //focus trick enables us to run this in iframes 263 $("textBoxA").addEventListener("focus", function () { 264 check = false; 265 $("textBoxA").addEventListener("click", function() { check = true; }, { once: true }); 266 synthesizeMouseAtCenter($("textBoxA"), {}); 267 is(check, true, 'synthesizeMouse should dispatch mouse event'); 268 269 check = false; 270 $("scrollB").addEventListener("click", function() { check = true; }, { once: true }); 271 synthesizeMouseExpectEvent($("scrollB"), 1, 1, {}, $("scrollB"), "click", "synthesizeMouseExpectEvent should fire click event"); 272 is(check, true, 'synthesizeMouse should dispatch mouse event'); 273 }, {once: true}); 274 $("textBoxA").focus(); 275 276 /** 277 * TODO: testing synthesizeWheel requires a setTimeout 278 * since there is delay between the scroll event and a check, so for now just test 279 * that we can successfully call it to avoid having setTimeout vary the runtime metric. 280 * Testing of this method is currently done here: 281 * toolkit/content/tests/chrome/test_mousescroll.xul 282 */ 283 synthesizeWheel($("scrollB"), 5, 5, {'deltaY': 10.0, deltaMode: WheelEvent.DOM_DELTA_LINE}); 284 285 /* test synthesizeKey* */ 286 check = false; 287 $("testKeyEvent").addEventListener("keypress", doCheck, {once:true}); 288 $("testKeyEvent").focus(); 289 sendString("a"); 290 is($("testKeyEvent").value, "a", "synthesizeKey should work"); 291 is(check, true, "synthesizeKey should dispatch keyPress"); 292 $("testKeyEvent").value = ""; 293 294 // If |.code| value is not specified explicitly, it should be computed 295 // from the |.key| value or |.keyCode| value. If a printable key is 296 // specified, the |.code| value should be guessed with US-English 297 // keyboard layout. 298 for (let test of [{ arg: "KEY_Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN }, 299 { arg: "VK_RETURN", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN }, 300 { arg: "KEY_Backspace", code: "Backspace", keyCode: KeyboardEvent.DOM_VK_BACK_SPACE }, 301 { arg: "KEY_Delete", code: "Delete", keyCode: KeyboardEvent.DOM_VK_DELETE }, 302 { arg: "KEY_Home", code: "Home", keyCode: KeyboardEvent.DOM_VK_HOME }, 303 { arg: "KEY_End", code: "End", keyCode: KeyboardEvent.DOM_VK_END }, 304 { arg: "KEY_ArrowDown", code: "ArrowDown", keyCode: KeyboardEvent.DOM_VK_DOWN }, 305 { arg: "KEY_ArrowUp", code: "ArrowUp", keyCode: KeyboardEvent.DOM_VK_UP }, 306 { arg: "KEY_ArrowLeft", code: "ArrowLeft", keyCode: KeyboardEvent.DOM_VK_LEFT }, 307 { arg: "KEY_ArrowRight", code: "ArrowRight", keyCode: KeyboardEvent.DOM_VK_RIGHT }, 308 { arg: "KEY_Shift", code: "ShiftLeft", keyCode: KeyboardEvent.DOM_VK_SHIFT }, 309 { arg: "KEY_Control", code: "ControlLeft", keyCode: KeyboardEvent.DOM_VK_CONTROL }, 310 { arg: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A }, 311 { arg: "B", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B }, 312 { arg: " ", code: "Space", keyCode: KeyboardEvent.DOM_VK_SPACE }, 313 { arg: "0", code: "Digit0", keyCode: KeyboardEvent.DOM_VK_0 }, 314 { arg: "(", code: "Digit9", keyCode: KeyboardEvent.DOM_VK_9 }, 315 { arg: "!", code: "Digit1", keyCode: KeyboardEvent.DOM_VK_1 }, 316 { arg: "[", code: "BracketLeft", keyCode: KeyboardEvent.DOM_VK_OPEN_BRACKET }, 317 { arg: ";", code: "Semicolon", keyCode: KeyboardEvent.DOM_VK_SEMICOLON }, 318 { arg: "\"", code: "Quote", keyCode: KeyboardEvent.DOM_VK_QUOTE }, 319 { arg: "~", code: "Backquote", keyCode: KeyboardEvent.DOM_VK_BACK_QUOTE }, 320 { arg: "<", code: "Comma", keyCode: KeyboardEvent.DOM_VK_COMMA }, 321 { arg: ".", code: "Period", keyCode: KeyboardEvent.DOM_VK_PERIOD }]) { 322 let testKeydown, keyup; 323 $("testKeyEvent").focus(); 324 $("testKeyEvent").addEventListener("keydown", (e) => { testKeydown = e; }, {once: true}); 325 $("testKeyEvent").addEventListener("keyup", (e) => { keyup = e; }, {once: true}); 326 synthesizeKey(test.arg); 327 is(testKeydown.code, test.code, `Synthesizing "${test.arg}" should set code value of "keydown" to "${test.code}"`); 328 is(testKeydown.keyCode, test.keyCode, `Synthesizing "${test.arg}" should set keyCode value of "keydown" to "${test.keyCode}"`); 329 is(keyup.code, test.code, `Synthesizing "${test.arg}" key should set code value of "keyup" to "${test.code}"`); 330 is(keyup.keyCode, test.keyCode, `Synthesizing "${test.arg}" key should set keyCode value of "keyup" to "${test.keyCode}"`); 331 $("testKeyEvent").value = ""; 332 } 333 334 /* test synthesizeComposition */ 335 var description = ""; 336 var keydownEvent = null; 337 var keyupEvent = null; 338 function onKeyDown(aEvent) { 339 ok(!keydownEvent, description + "keydown should be fired only once" + (keydownEvent ? keydownEvent.key : "") + ", " + (keyupEvent ? keyupEvent.key : "")); 340 keydownEvent = aEvent; 341 } 342 function onKeyUp(aEvent) { 343 ok(!keyupEvent, description + "keyup should be fired only once"); 344 keyupEvent = aEvent; 345 } 346 function resetKeyDownAndKeyUp(aDescription) { 347 description = aDescription + ": "; 348 keydownEvent = null; 349 keyupEvent = null; 350 check = false; 351 } 352 function checkKeyDownAndKeyUp(aKeyDown, aKeyUp) { 353 if (aKeyDown) { 354 is(keydownEvent.keyCode, aKeyDown.keyCode, 355 description + "keydown event should be dispatched (checking keyCode)"); 356 is(keydownEvent.key, aKeyDown.key, 357 description + "keydown event should be dispatched (checking key)"); 358 } else { 359 is(keydownEvent, null, 360 description + "keydown event shouldn't be fired"); 361 } 362 if (aKeyUp) { 363 is(keyupEvent.keyCode, aKeyUp.keyCode, 364 description + "keyup event should be dispatched (checking keyCode)"); 365 is(keyupEvent.key, aKeyUp.key, 366 description + "keyup event should be dispatched (checking key)"); 367 } else { 368 is(keyupEvent, null, 369 description + "keyup event shouldn't be fired"); 370 } 371 } 372 $("textBoxB").addEventListener("keydown", onKeyDown); 373 $("textBoxB").addEventListener("keyup", onKeyUp); 374 375 $("textBoxB").focus(); 376 377 // If key event is not specified, fake keydown and keyup events which are 378 // marked as "processed by IME" should be fired. 379 resetKeyDownAndKeyUp("synthesizing eCompositionStart without specifying keyboard event"); 380 window.addEventListener("compositionstart", doCheck, {once: true}); 381 synthesizeComposition({type: "compositionstart"}); 382 ok(check, description + "synthesizeComposition() should dispatch compositionstart"); 383 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 384 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 385 386 resetKeyDownAndKeyUp("trying to synthesize eCompositionUpdate directly without specifying keyboard event"); 387 window.addEventListener("compositionupdate", doCheck, {once: true}); 388 synthesizeComposition({type: "compositionupdate", data: "a"}); 389 ok(!check, description + "synthesizeComposition() should not dispatch compositionupdate without error"); 390 checkKeyDownAndKeyUp(null, null); 391 392 resetKeyDownAndKeyUp("synthesizing eCompositionChange without specifying keyboard event"); 393 window.addEventListener("text", doCheck, {once: true}); 394 synthesizeCompositionChange( 395 { "composition": 396 { "string": "a", 397 "clauses": 398 [ 399 { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE } 400 ] 401 }, 402 "caret": { "start": 1, "length": 0 } 403 } 404 ); 405 ok(check, description + "synthesizeCompositionChange should cause dispatching a DOM text event"); 406 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 407 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 408 409 resetKeyDownAndKeyUp("synthesizing eCompositionChange for removing clauses without specifying keyboard event"); 410 synthesizeCompositionChange( 411 { "composition": 412 { "string": "a", 413 "clauses": 414 [ 415 { "length": 0, "attr": 0 } 416 ] 417 }, 418 "caret": { "start": 1, "length": 0 } 419 } 420 ); 421 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 422 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 423 424 resetKeyDownAndKeyUp("trying to synthesize eCompositionEnd directly without specifying keyboard event"); 425 window.addEventListener("compositionend", doCheck, {once: true}); 426 synthesizeComposition({type: "compositionend", data: "a"}); 427 ok(!check, description + "synthesizeComposition() should not dispatch compositionend"); 428 checkKeyDownAndKeyUp(null, null); 429 430 resetKeyDownAndKeyUp("synthesizing eCompositionCommit without specifying keyboard event"); 431 synthesizeComposition({type: "compositioncommit", data: "a"}); 432 ok(check, description + "synthesizeComposition() should dispatch compositionend"); 433 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 434 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 435 436 var querySelectedText = synthesizeQuerySelectedText(); 437 ok(querySelectedText, "query selected text event result is null"); 438 ok(querySelectedText.succeeded, "query selected text event failed"); 439 is(querySelectedText.offset, 1, 440 "query selected text event returns wrong offset"); 441 is(querySelectedText.text, "", 442 "query selected text event returns wrong selected text"); 443 $("textBoxB").value = ""; 444 445 querySelectedText = synthesizeQuerySelectedText(); 446 ok(querySelectedText, "query selected text event result is null"); 447 ok(querySelectedText.succeeded, "query selected text event failed"); 448 is(querySelectedText.offset, 0, 449 "query selected text event returns wrong offset"); 450 is(querySelectedText.text, "", 451 "query selected text event returns wrong selected text"); 452 var endTime = new Date(); 453 info("\nProfile::EventUtilsRunTime: " + (endTime-startTime) + "\n"); 454 455 // In most cases, automated tests shouldn't try to synthesize 456 // compositionstart manually. Let's check if synthesizeCompositionChange() 457 // dispatches compositionstart automatically. 458 resetKeyDownAndKeyUp("synthesizing eCompositionChange without specifying keyboard event when there is no composition"); 459 window.addEventListener("compositionstart", doCheck, {once: true}); 460 synthesizeCompositionChange( 461 { "composition": 462 { "string": "a", 463 "clauses": 464 [ 465 { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE } 466 ] 467 }, 468 "caret": { "start": 1, "length": 0 } 469 } 470 ); 471 ok(check, description + "synthesizeCompositionChange should dispatch \"compositionstart\" automatically if there is no composition"); 472 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 473 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 474 475 resetKeyDownAndKeyUp("synthesizing eCompositionCommitAsIs without specifying keyboard event"); 476 synthesizeComposition({type: "compositioncommitasis"}); 477 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 478 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 479 480 // If key event is specified, keydown event which is marked as "processed 481 // by IME" should be fired and keyup event which is NOT marked as so 482 // should be fired too. 483 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event"); 484 synthesizeComposition({type: "compositionstart", key: {key: "a"}}); 485 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 486 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"}); 487 488 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event"); 489 synthesizeCompositionChange( 490 {"composition": 491 {"string": "b", "clauses": [ 492 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 493 ]}, 494 "caret": {"start": 1, "length": 0}, 495 "key": {key: "b"}, 496 } 497 ); 498 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 499 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"}); 500 501 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event"); 502 synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter"}}); 503 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 504 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"}); 505 506 // keyup shouldn't be dispatched automatically if type is specified as keydown 507 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose type is keydown"); 508 synthesizeComposition({type: "compositionstart", key: {key: "a", type: "keydown"}}); 509 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 510 null); 511 512 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose type is keydown"); 513 synthesizeCompositionChange( 514 {"composition": 515 {"string": "b", "clauses": [ 516 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 517 ]}, 518 "caret": {"start": 1, "length": 0}, 519 "key": {key: "b", type: "keydown"}, 520 } 521 ); 522 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 523 null); 524 525 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose type is keydown"); 526 synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", type: "keydown"}}); 527 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 528 null); 529 530 // keydown shouldn't be dispatched automatically if type is specified as keyup 531 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose type is keyup"); 532 synthesizeComposition({type: "compositionstart", key: {key: "a", type: "keyup"}}); 533 checkKeyDownAndKeyUp(null, 534 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"}); 535 536 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose type is keyup"); 537 synthesizeCompositionChange( 538 {"composition": 539 {"string": "b", "clauses": [ 540 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 541 ]}, 542 "caret": {"start": 1, "length": 0}, 543 "key": {key: "b", type: "keyup"}, 544 } 545 ); 546 checkKeyDownAndKeyUp(null, 547 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"}); 548 549 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose type is keyup"); 550 synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", type: "keyup"}}); 551 checkKeyDownAndKeyUp(null, 552 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"}); 553 554 // keydown event shouldn't be marked as "processed by IME" if doNotMarkKeydownAsProcessed is true 555 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose doNotMarkKeydownAsProcessed is true"); 556 synthesizeComposition({type: "compositionstart", key: {key: "a", doNotMarkKeydownAsProcessed: true}}); 557 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_A, key: "a"}, 558 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"}); 559 560 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose doNotMarkKeydownAsProcessed is true"); 561 synthesizeCompositionChange( 562 {"composition": 563 {"string": "b", "clauses": [ 564 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 565 ]}, 566 "caret": {"start": 1, "length": 0}, 567 "key": {key: "b", doNotMarkKeydownAsProcessed: true}, 568 } 569 ); 570 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"}, 571 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"}); 572 573 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose doNotMarkKeydownAsProcessed is true"); 574 synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", doNotMarkKeydownAsProcessed: true}}); 575 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"}, 576 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"}); 577 578 // keyup event should be marked as "processed by IME" if markKeyupAsProcessed is true 579 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose markKeyupAsProcessed is true"); 580 synthesizeComposition({type: "compositionstart", key: {key: "a", markKeyupAsProcessed: true}}); 581 checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 582 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 583 584 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose markKeyupAsProcessed is true"); 585 synthesizeCompositionChange( 586 {"composition": 587 {"string": "b", "clauses": [ 588 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 589 ]}, 590 "caret": {"start": 1, "length": 0}, 591 "key": {key: "b", markKeyupAsProcessed: true}, 592 } 593 ); 594 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 595 {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 596 597 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose markKeyupAsProcessed is true"); 598 synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", markKeyupAsProcessed: true}}); 599 checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}, 600 {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"}); 601 602 // If key event is explicitly declared with null, keyboard events shouldn't 603 // be fired for emulating text inputs without keyboard such as voice input or something. 604 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event as null"); 605 synthesizeComposition({type: "compositionstart", key: null}); 606 checkKeyDownAndKeyUp(null, null); 607 608 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event as null"); 609 synthesizeCompositionChange( 610 {"composition": 611 {"string": "b", "clauses": [ 612 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 613 ]}, 614 "caret": {"start": 1, "length": 0}, 615 "key": null, 616 } 617 ); 618 checkKeyDownAndKeyUp(null, null); 619 620 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event as null"); 621 synthesizeComposition({type: "compositioncommit", data: "c", key: null}); 622 checkKeyDownAndKeyUp(null, null); 623 624 // If key event is explicitly declared with empty object, keyboard events 625 // shouldn't be fired for emulating text inputs without keyboard such as 626 // voice input or something. 627 resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event as empty"); 628 synthesizeComposition({type: "compositionstart", key: {}}); 629 checkKeyDownAndKeyUp(null, null); 630 631 resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event as empty"); 632 synthesizeCompositionChange( 633 {"composition": 634 {"string": "b", "clauses": [ 635 {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE} 636 ]}, 637 "caret": {"start": 1, "length": 0}, 638 "key": {}, 639 } 640 ); 641 checkKeyDownAndKeyUp(null, null); 642 643 resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event as empty"); 644 synthesizeComposition({type: "compositioncommit", data: "c", key: {}}); 645 checkKeyDownAndKeyUp(null, null); 646 647 $("textBoxB").removeEventListener("keydown", onKeyDown); 648 $("textBoxB").removeEventListener("keyup", onKeyUp); 649 650 651 // Async event synthesizing. 652 // On Android this does not work. 653 if (navigator.userAgent.includes("Android")) { 654 SimpleTest.finish(); 655 return; 656 } 657 658 await (async function () { 659 await SpecialPowers.pushPrefEnv({set: [["test.events.async.enabled", true]]}); 660 try { 661 disableNonTestMouseEvents(true); 662 let mouseMoveCount = 0; 663 let waitForAllSynthesizedMouseMove = 664 new Promise(resolve => { 665 window.addEventListener("mousemove", function onMouseMove(aEvent) { 666 mouseMoveCount++; 667 is(aEvent.target, $("testMouseEvent"), 668 `The mousemove event target of ${ 669 mouseMoveCount 670 } should be the input#testMouseEvent, but ${ 671 aEvent.target.nodeName 672 }`); 673 if (mouseMoveCount === 30) { 674 window.removeEventListener("mousemove", onMouseMove, { capture: true }); 675 resolve(); 676 } 677 }, { capture: true }); 678 }); 679 for (let i = 0; i < 30; i++) { 680 synthesizeMouse($("testMouseEvent"), 3 + i % 2, 3 + i % 2, { type: "mousemove" }); 681 } 682 await waitForAllSynthesizedMouseMove; 683 } finally { 684 disableNonTestMouseEvents(false); 685 } 686 })(); 687 688 SimpleTest.finish(); 689 } 690 ); 691 }; 692 </script> 693 </body> 694 </html>