summaryrefslogtreecommitdiffstats
path: root/dom/base/test/useractivation/file_clipboard_common.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/test/useractivation/file_clipboard_common.js')
-rw-r--r--dom/base/test/useractivation/file_clipboard_common.js505
1 files changed, 505 insertions, 0 deletions
diff --git a/dom/base/test/useractivation/file_clipboard_common.js b/dom/base/test/useractivation/file_clipboard_common.js
new file mode 100644
index 0000000000..fe172e52c8
--- /dev/null
+++ b/dom/base/test/useractivation/file_clipboard_common.js
@@ -0,0 +1,505 @@
+// This test is called from both test_clipboard_editor.html and test_clipboard_noeditor.html
+// This is to test that the code works both in the presence of a contentEditable node, and in the absense of one
+var WATCH_TIMEOUT = 300;
+
+// Some global variables to make the debug messages easier to track down
+var gTestN0 = 0,
+ gTestN1 = 0,
+ gTestN2 = 0;
+function testLoc() {
+ return " " + gTestN0 + " - " + gTestN1 + " - " + gTestN2;
+}
+
+// Listen for cut & copy events
+var gCopyCount = 0,
+ gCutCount = 0;
+document.addEventListener("copy", function () {
+ gCopyCount++;
+});
+document.addEventListener("cut", function () {
+ gCutCount++;
+});
+
+// Helper methods
+function selectNode(aSelector, aCb) {
+ var dn = document.querySelector(aSelector);
+ var range = document.createRange();
+ range.selectNodeContents(dn);
+ window.getSelection().removeAllRanges();
+ window.getSelection().addRange(range);
+ if (aCb) {
+ aCb();
+ }
+}
+
+function selectInputNode(aSelector, aCb) {
+ var dn = document.querySelector(aSelector);
+ synthesizeMouse(dn, 10, 10, {});
+ SimpleTest.executeSoon(function () {
+ synthesizeKey("A", { accelKey: true });
+ // Clear the user activation state which is set from synthesized mouse and
+ // key event.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ SimpleTest.executeSoon(aCb);
+ });
+}
+
+// Callback functions for attaching to the button
+function execCommand(aCommand, aShouldSucceed, aAsync = false) {
+ var cb = function (e) {
+ e.preventDefault();
+ document.removeEventListener("keydown", cb);
+
+ if (aAsync) {
+ setTimeout(() => {
+ is(
+ aShouldSucceed,
+ document.execCommand(aCommand),
+ "Keydown caused " + aCommand + " invocation" + testLoc()
+ );
+ }, 0);
+ } else {
+ is(
+ aShouldSucceed,
+ document.execCommand(aCommand),
+ "Keydown caused " + aCommand + " invocation" + testLoc()
+ );
+ }
+ };
+ return cb;
+}
+
+// The basic test set. Tries to cut/copy everything
+function cutCopyAll(
+ aDoCut,
+ aDoCopy,
+ aDone,
+ aNegate,
+ aClipOverride,
+ aJustClipboardNegate
+) {
+ var execCommandAlwaysSucceed = !!(aClipOverride || aJustClipboardNegate);
+
+ function waitForClipboard(aCond, aSetup, aNext, aNegateOne) {
+ if (aClipOverride) {
+ aCond = aClipOverride;
+ aNegateOne = false;
+ }
+ if (aNegate || aNegateOne || aJustClipboardNegate) {
+ SimpleTest.waitForClipboard(
+ null,
+ aSetup,
+ aNext,
+ aNext,
+ "text/plain",
+ WATCH_TIMEOUT,
+ true
+ );
+ } else {
+ SimpleTest.waitForClipboard(aCond, aSetup, aNext, aNext);
+ }
+ }
+
+ function validateCutCopy(aExpectedCut, aExpectedCopy) {
+ if (aNegate) {
+ aExpectedCut = aExpectedCopy = 0;
+ } // When we are negating - we always expect callbacks not to be run
+
+ is(
+ aExpectedCut,
+ gCutCount,
+ (aExpectedCut > 0
+ ? "Expect cut callback to run"
+ : "Expect cut callback not to run") + testLoc()
+ );
+ is(
+ aExpectedCopy,
+ gCopyCount,
+ (aExpectedCopy > 0
+ ? "Expect copy callback to run"
+ : "Expect copy callback not to run") + testLoc()
+ );
+ gCutCount = gCopyCount = 0;
+ }
+
+ function step(n) {
+ function nextStep() {
+ step(n + 1);
+ }
+
+ // Reset the user activation state before running next test.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ document.querySelector("span").textContent = "span text";
+ document.querySelector("input[type=text]").value = "text text";
+ document.querySelector("input[type=password]").value = "password text";
+ document.querySelector("textarea").value = "textarea text";
+
+ var contentEditableNode = document.querySelector(
+ "div[contentEditable=true]"
+ );
+ if (contentEditableNode) {
+ contentEditableNode.textContent = "contenteditable text";
+ }
+
+ gTestN2 = n;
+ switch (n) {
+ case 0:
+ // copy on readonly selection
+ selectNode("span");
+ waitForClipboard(
+ "span text",
+ function () {
+ aDoCopy(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 1:
+ validateCutCopy(0, 1);
+
+ // cut on readonly selection
+ selectNode("span");
+
+ waitForClipboard(
+ "span text",
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 2:
+ validateCutCopy(1, 0);
+
+ // copy on textbox selection
+ selectInputNode("input[type=text]", nextStep);
+ return;
+
+ case 3:
+ waitForClipboard(
+ "text text",
+ function () {
+ selectInputNode("input[type=text]", function () {
+ aDoCopy(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 4:
+ validateCutCopy(0, 1);
+
+ // cut on textbox selection
+ selectInputNode("input[type=text]", nextStep);
+ return;
+
+ case 5:
+ waitForClipboard(
+ "text text",
+ function () {
+ aDoCut(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 6:
+ validateCutCopy(1, 0);
+
+ // copy on password selection
+ selectInputNode("input[type=password]", nextStep);
+ return;
+
+ case 7:
+ waitForClipboard(
+ null,
+ function () {
+ aDoCopy(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 8:
+ validateCutCopy(0, 1);
+
+ // cut on password selection
+ selectInputNode("input[type=password]", nextStep);
+ return;
+
+ case 9:
+ waitForClipboard(
+ null,
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 10:
+ validateCutCopy(1, 0);
+
+ // copy on textarea selection
+ selectInputNode("textarea", nextStep);
+ return;
+
+ case 11:
+ waitForClipboard(
+ "textarea text",
+ function () {
+ aDoCopy(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 12:
+ validateCutCopy(0, 1);
+
+ // cut on password selection
+ selectInputNode("textarea", nextStep);
+ return;
+
+ case 13:
+ waitForClipboard(
+ "textarea text",
+ function () {
+ aDoCut(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 14:
+ validateCutCopy(1, 0);
+
+ // copy on no selection
+ document.querySelector("textarea").blur();
+
+ waitForClipboard(
+ null,
+ function () {
+ aDoCopy(true);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 15:
+ validateCutCopy(0, 1);
+
+ // cut on no selection
+ waitForClipboard(
+ null,
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 16:
+ validateCutCopy(1, 0);
+
+ if (!document.querySelector("div[contentEditable=true]")) {
+ // We're done! (no contentEditable node!)
+ step(-1);
+ return;
+ }
+ break;
+
+ case 17:
+ // copy on contenteditable selection
+ waitForClipboard(
+ "contenteditable text",
+ function () {
+ selectNode("div[contentEditable=true]", function () {
+ aDoCopy(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 18:
+ validateCutCopy(0, 1);
+ break;
+
+ case 19:
+ // cut on contenteditable selection
+ waitForClipboard(
+ "contenteditable text",
+ function () {
+ selectNode("div[contentEditable=true]", function () {
+ aDoCut(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 20:
+ validateCutCopy(1, 0);
+ break;
+
+ default:
+ aDone();
+ return;
+ }
+
+ SimpleTest.executeSoon(function () {
+ step(n + 1);
+ });
+ }
+
+ step(0);
+}
+
+function allMechanisms(aCb, aClipOverride, aNegateAll) {
+ function testStep(n) {
+ gTestN1 = n;
+ switch (n) {
+ /** Test for Bug 1012662 **/
+ case 0:
+ // Keyboard issued
+ cutCopyAll(
+ function docut(aSucc) {
+ synthesizeKey("x", { accelKey: true });
+ },
+ function docopy(aSucc) {
+ synthesizeKey("c", { accelKey: true });
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ case 1:
+ // Button issued
+ cutCopyAll(
+ function docut(aSucc) {
+ document.addEventListener("keydown", execCommand("cut", aSucc));
+ sendString("Q");
+ },
+ function docopy(aSucc) {
+ document.addEventListener("keydown", execCommand("copy", aSucc));
+ sendString("Q");
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ case 2:
+ // Not triggered by user gesture
+ cutCopyAll(
+ function doCut(aSucc) {
+ is(
+ false,
+ document.execCommand("cut"),
+ "Can't directly execCommand not in a user callback"
+ );
+ },
+ function doCopy(aSucc) {
+ is(
+ false,
+ document.execCommand("copy"),
+ "Can't directly execCommand not in a user callback"
+ );
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ true,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ /** Test for Bug 1597857 **/
+ case 3:
+ // Button issued async
+ cutCopyAll(
+ function docut(aSucc) {
+ document.addEventListener(
+ "keydown",
+ execCommand("cut", aSucc, true)
+ );
+ sendString("Q");
+ },
+ function docopy(aSucc) {
+ document.addEventListener(
+ "keydown",
+ execCommand("copy", aSucc, true)
+ );
+ sendString("Q");
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ default:
+ aCb();
+ }
+ }
+ testStep(0);
+}
+
+// Run the tests
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(5); // On the emulator - this times out occasionally
+SimpleTest.waitForFocus(function () {
+ function justCancel(aEvent) {
+ aEvent.preventDefault();
+ }
+
+ function override(aEvent) {
+ aEvent.clipboardData.setData("text/plain", "overridden");
+ aEvent.preventDefault();
+ }
+
+ allMechanisms(function () {
+ gTestN0 = 1;
+ document.addEventListener("cut", override);
+ document.addEventListener("copy", override);
+
+ allMechanisms(function () {
+ gTestN0 = 2;
+ document.removeEventListener("cut", override);
+ document.removeEventListener("copy", override);
+ document.addEventListener("cut", justCancel);
+ document.addEventListener("copy", justCancel);
+
+ allMechanisms(
+ function () {
+ SimpleTest.finish();
+ },
+ null,
+ true
+ );
+ }, "overridden");
+ });
+});