file_clipboard_common.js (11660B)
1 // This test is called from both test_clipboard_editor.html and test_clipboard_noeditor.html 2 // This is to test that the code works both in the presence of a contentEditable node, and in the absense of one 3 var WATCH_TIMEOUT = 300; 4 5 // Some global variables to make the debug messages easier to track down 6 var gTestN0 = 0, 7 gTestN1 = 0, 8 gTestN2 = 0; 9 function testLoc() { 10 return " " + gTestN0 + " - " + gTestN1 + " - " + gTestN2; 11 } 12 13 // Listen for cut & copy events 14 var gCopyCount = 0, 15 gCutCount = 0; 16 document.addEventListener("copy", function () { 17 gCopyCount++; 18 }); 19 document.addEventListener("cut", function () { 20 gCutCount++; 21 }); 22 23 // Helper methods 24 function selectNode(aSelector, aCb) { 25 var dn = document.querySelector(aSelector); 26 var range = document.createRange(); 27 range.selectNodeContents(dn); 28 window.getSelection().removeAllRanges(); 29 window.getSelection().addRange(range); 30 if (aCb) { 31 aCb(); 32 } 33 } 34 35 function selectInputNode(aSelector, aCb) { 36 var dn = document.querySelector(aSelector); 37 synthesizeMouse(dn, 10, 10, {}); 38 SimpleTest.executeSoon(function () { 39 synthesizeKey("A", { accelKey: true }); 40 // Clear the user activation state which is set from synthesized mouse and 41 // key event. 42 SpecialPowers.wrap(document).clearUserGestureActivation(); 43 SimpleTest.executeSoon(aCb); 44 }); 45 } 46 47 // Callback functions for attaching to the button 48 function execCommand(aCommand, aShouldSucceed, aAsync = false) { 49 var cb = function (e) { 50 e.preventDefault(); 51 document.removeEventListener("keydown", cb); 52 53 if (aAsync) { 54 setTimeout(() => { 55 is( 56 aShouldSucceed, 57 document.execCommand(aCommand), 58 "Keydown caused " + aCommand + " invocation" + testLoc() 59 ); 60 }, 0); 61 } else { 62 is( 63 aShouldSucceed, 64 document.execCommand(aCommand), 65 "Keydown caused " + aCommand + " invocation" + testLoc() 66 ); 67 } 68 }; 69 return cb; 70 } 71 72 // The basic test set. Tries to cut/copy everything 73 function cutCopyAll( 74 aDoCut, 75 aDoCopy, 76 aDone, 77 aNegate, 78 aClipOverride, 79 aJustClipboardNegate 80 ) { 81 var execCommandAlwaysSucceed = !!(aClipOverride || aJustClipboardNegate); 82 83 function waitForClipboard(aCond, aSetup, aNext, aNegateOne) { 84 if (aClipOverride) { 85 aCond = aClipOverride; 86 aNegateOne = false; 87 } 88 if (aNegate || aNegateOne || aJustClipboardNegate) { 89 SimpleTest.waitForClipboard( 90 null, 91 aSetup, 92 aNext, 93 aNext, 94 "text/plain", 95 WATCH_TIMEOUT, 96 true 97 ); 98 } else { 99 SimpleTest.waitForClipboard(aCond, aSetup, aNext, aNext); 100 } 101 } 102 103 function validateCutCopy(aExpectedCut, aExpectedCopy) { 104 if (aNegate) { 105 aExpectedCut = aExpectedCopy = 0; 106 } // When we are negating - we always expect callbacks not to be run 107 108 is( 109 aExpectedCut, 110 gCutCount, 111 (aExpectedCut > 0 112 ? "Expect cut callback to run" 113 : "Expect cut callback not to run") + testLoc() 114 ); 115 is( 116 aExpectedCopy, 117 gCopyCount, 118 (aExpectedCopy > 0 119 ? "Expect copy callback to run" 120 : "Expect copy callback not to run") + testLoc() 121 ); 122 gCutCount = gCopyCount = 0; 123 } 124 125 function step(n) { 126 function nextStep() { 127 step(n + 1); 128 } 129 130 // Reset the user activation state before running next test. 131 SpecialPowers.wrap(document).clearUserGestureActivation(); 132 133 document.querySelector("span").textContent = "span text"; 134 document.querySelector("input[type=text]").value = "text text"; 135 document.querySelector("input[type=password]").value = "password text"; 136 document.querySelector("textarea").value = "textarea text"; 137 138 var contentEditableNode = document.querySelector( 139 "div[contentEditable=true]" 140 ); 141 if (contentEditableNode) { 142 contentEditableNode.textContent = "contenteditable text"; 143 } 144 145 gTestN2 = n; 146 switch (n) { 147 case 0: 148 // copy on readonly selection 149 selectNode("span"); 150 waitForClipboard( 151 "span text", 152 function () { 153 aDoCopy(true); 154 }, 155 nextStep 156 ); 157 return; 158 159 case 1: 160 validateCutCopy(0, 1); 161 162 // cut on readonly selection 163 selectNode("span"); 164 165 waitForClipboard( 166 "span text", 167 function () { 168 aDoCut(execCommandAlwaysSucceed); 169 }, 170 nextStep, 171 true 172 ); 173 return; 174 175 case 2: 176 validateCutCopy(1, 0); 177 178 // copy on textbox selection 179 selectInputNode("input[type=text]", nextStep); 180 return; 181 182 case 3: 183 waitForClipboard( 184 "text text", 185 function () { 186 selectInputNode("input[type=text]", function () { 187 aDoCopy(true); 188 }); 189 }, 190 nextStep 191 ); 192 return; 193 194 case 4: 195 validateCutCopy(0, 1); 196 197 // cut on textbox selection 198 selectInputNode("input[type=text]", nextStep); 199 return; 200 201 case 5: 202 waitForClipboard( 203 "text text", 204 function () { 205 aDoCut(true); 206 }, 207 nextStep 208 ); 209 return; 210 211 case 6: 212 validateCutCopy(1, 0); 213 214 // copy on password selection 215 selectInputNode("input[type=password]", nextStep); 216 return; 217 218 case 7: 219 waitForClipboard( 220 null, 221 function () { 222 aDoCopy(execCommandAlwaysSucceed); 223 }, 224 nextStep, 225 true 226 ); 227 return; 228 229 case 8: 230 validateCutCopy(0, 1); 231 232 // cut on password selection 233 selectInputNode("input[type=password]", nextStep); 234 return; 235 236 case 9: 237 waitForClipboard( 238 null, 239 function () { 240 aDoCut(execCommandAlwaysSucceed); 241 }, 242 nextStep, 243 true 244 ); 245 return; 246 247 case 10: 248 validateCutCopy(1, 0); 249 250 // copy on textarea selection 251 selectInputNode("textarea", nextStep); 252 return; 253 254 case 11: 255 waitForClipboard( 256 "textarea text", 257 function () { 258 aDoCopy(true); 259 }, 260 nextStep 261 ); 262 return; 263 264 case 12: 265 validateCutCopy(0, 1); 266 267 // cut on password selection 268 selectInputNode("textarea", nextStep); 269 return; 270 271 case 13: 272 waitForClipboard( 273 "textarea text", 274 function () { 275 aDoCut(true); 276 }, 277 nextStep 278 ); 279 return; 280 281 case 14: 282 validateCutCopy(1, 0); 283 284 // copy on no selection 285 document.querySelector("textarea").blur(); 286 287 waitForClipboard( 288 null, 289 function () { 290 aDoCopy(true); 291 }, 292 nextStep, 293 true 294 ); 295 return; 296 297 case 15: 298 validateCutCopy(0, 1); 299 300 // cut on no selection 301 waitForClipboard( 302 null, 303 function () { 304 aDoCut(execCommandAlwaysSucceed); 305 }, 306 nextStep, 307 true 308 ); 309 return; 310 311 case 16: 312 validateCutCopy(1, 0); 313 314 if (!document.querySelector("div[contentEditable=true]")) { 315 // We're done! (no contentEditable node!) 316 step(-1); 317 return; 318 } 319 break; 320 321 case 17: 322 // copy on contenteditable selection 323 waitForClipboard( 324 "contenteditable text", 325 function () { 326 selectNode("div[contentEditable=true]", function () { 327 aDoCopy(true); 328 }); 329 }, 330 nextStep 331 ); 332 return; 333 334 case 18: 335 validateCutCopy(0, 1); 336 break; 337 338 case 19: 339 // cut on contenteditable selection 340 waitForClipboard( 341 "contenteditable text", 342 function () { 343 selectNode("div[contentEditable=true]", function () { 344 aDoCut(true); 345 }); 346 }, 347 nextStep 348 ); 349 return; 350 351 case 20: 352 validateCutCopy(1, 0); 353 break; 354 355 default: 356 aDone(); 357 return; 358 } 359 360 SimpleTest.executeSoon(function () { 361 step(n + 1); 362 }); 363 } 364 365 step(0); 366 } 367 368 function allMechanisms(aCb, aClipOverride, aNegateAll) { 369 function testStep(n) { 370 gTestN1 = n; 371 switch (n) { 372 /** Test for Bug 1012662 */ 373 case 0: 374 // Keyboard issued 375 cutCopyAll( 376 function docut() { 377 synthesizeKey("x", { accelKey: true }); 378 }, 379 function docopy() { 380 synthesizeKey("c", { accelKey: true }); 381 }, 382 function done() { 383 testStep(n + 1); 384 }, 385 false, 386 aClipOverride, 387 aNegateAll 388 ); 389 return; 390 391 case 1: 392 // Button issued 393 cutCopyAll( 394 function docut(aSucc) { 395 document.addEventListener("keydown", execCommand("cut", aSucc)); 396 sendString("Q"); 397 }, 398 function docopy(aSucc) { 399 document.addEventListener("keydown", execCommand("copy", aSucc)); 400 sendString("Q"); 401 }, 402 function done() { 403 testStep(n + 1); 404 }, 405 false, 406 aClipOverride, 407 aNegateAll 408 ); 409 return; 410 411 case 2: 412 // Not triggered by user gesture 413 cutCopyAll( 414 function doCut() { 415 is( 416 false, 417 document.execCommand("cut"), 418 "Can't directly execCommand not in a user callback" 419 ); 420 }, 421 function doCopy() { 422 is( 423 false, 424 document.execCommand("copy"), 425 "Can't directly execCommand not in a user callback" 426 ); 427 }, 428 function done() { 429 testStep(n + 1); 430 }, 431 true, 432 aClipOverride, 433 aNegateAll 434 ); 435 return; 436 437 /** Test for Bug 1597857 */ 438 case 3: 439 // Button issued async 440 cutCopyAll( 441 function docut(aSucc) { 442 document.addEventListener( 443 "keydown", 444 execCommand("cut", aSucc, true) 445 ); 446 sendString("Q"); 447 }, 448 function docopy(aSucc) { 449 document.addEventListener( 450 "keydown", 451 execCommand("copy", aSucc, true) 452 ); 453 sendString("Q"); 454 }, 455 function done() { 456 testStep(n + 1); 457 }, 458 false, 459 aClipOverride, 460 aNegateAll 461 ); 462 return; 463 464 default: 465 aCb(); 466 } 467 } 468 testStep(0); 469 } 470 471 // Run the tests 472 SimpleTest.waitForExplicitFinish(); 473 SimpleTest.requestLongerTimeout(5); // On the emulator - this times out occasionally 474 SimpleTest.waitForFocus(function () { 475 function justCancel(aEvent) { 476 aEvent.preventDefault(); 477 } 478 479 function override(aEvent) { 480 aEvent.clipboardData.setData("text/plain", "overridden"); 481 aEvent.preventDefault(); 482 } 483 484 allMechanisms(function () { 485 gTestN0 = 1; 486 document.addEventListener("cut", override); 487 document.addEventListener("copy", override); 488 489 allMechanisms(function () { 490 gTestN0 = 2; 491 document.removeEventListener("cut", override); 492 document.removeEventListener("copy", override); 493 document.addEventListener("cut", justCancel); 494 document.addEventListener("copy", justCancel); 495 496 allMechanisms( 497 function () { 498 SimpleTest.finish(); 499 }, 500 null, 501 true 502 ); 503 }, "overridden"); 504 }); 505 });