/** Test for Bug 1012662 **/ // This test is called from both test_bug1012662_editor.html and test_bug1012662_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}); SimpleTest.executeSoon(aCb); }); } // Callback functions for attaching to the button function execCut(aShouldSucceed) { var cb = function(e) { e.preventDefault(); document.removeEventListener('keydown', cb); is(aShouldSucceed, document.execCommand('cut'), "Keydown caused cut invocation" + testLoc()); }; return cb; } function execCopy(aShouldSucceed) { var cb = function(e) { e.preventDefault(); document.removeEventListener('keydown', cb); is(aShouldSucceed, document.execCommand('copy'), "Keydown caused copy 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/unicode", 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); } 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) { 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', execCut(aSucc)); synthesizeKey("Q", {}); }, function docopy(aSucc) { document.addEventListener('keydown', execCopy(aSucc)); synthesizeKey("Q", {}); }, function done() { testStep(n + 1); }, false, aClipOverride, aNegateAll); return; case 2: // Button issued 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; default: aCb(); return; } SimpleTest.executeSoon(function() { testStep(n + 1); }); } 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'); }); });