diff options
Diffstat (limited to 'accessible/tests/mochitest/editabletext')
-rw-r--r-- | accessible/tests/mochitest/editabletext/a11y.ini | 7 | ||||
-rw-r--r-- | accessible/tests/mochitest/editabletext/editabletext.js | 409 | ||||
-rw-r--r-- | accessible/tests/mochitest/editabletext/test_1.html | 140 | ||||
-rw-r--r-- | accessible/tests/mochitest/editabletext/test_2.html | 61 |
4 files changed, 617 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/editabletext/a11y.ini b/accessible/tests/mochitest/editabletext/a11y.ini new file mode 100644 index 0000000000..68466fdf23 --- /dev/null +++ b/accessible/tests/mochitest/editabletext/a11y.ini @@ -0,0 +1,7 @@ +[DEFAULT] +support-files = + editabletext.js + !/accessible/tests/mochitest/*.js + +[test_1.html] +[test_2.html] diff --git a/accessible/tests/mochitest/editabletext/editabletext.js b/accessible/tests/mochitest/editabletext/editabletext.js new file mode 100644 index 0000000000..ef305c7842 --- /dev/null +++ b/accessible/tests/mochitest/editabletext/editabletext.js @@ -0,0 +1,409 @@ +/* import-globals-from ../common.js */ +/* import-globals-from ../events.js */ + +/** + * Perform all editable text tests. + */ +function editableTextTestRun() { + this.add = function add(aTest) { + this.seq.push(aTest); + }; + + this.run = function run() { + this.iterate(); + }; + + this.index = 0; + this.seq = []; + + this.iterate = function iterate() { + if (this.index < this.seq.length) { + this.seq[this.index++].startTest(this); + return; + } + + this.seq = null; + SimpleTest.finish(); + }; +} + +/** + * Used to test nsIEditableTextAccessible methods. + */ +function editableTextTest(aID) { + /** + * Schedule a test, the given function with its arguments will be executed + * when preceding test is complete. + */ + this.scheduleTest = function scheduleTest(aFunc, ...aFuncArgs) { + // A data container acts like a dummy invoker, it's never invoked but + // it's used to generate real invoker when previous invoker was handled. + var dataContainer = { + func: aFunc, + funcArgs: aFuncArgs, + }; + this.mEventQueue.push(dataContainer); + + if (!this.mEventQueueReady) { + this.unwrapNextTest(); + this.mEventQueueReady = true; + } + }; + + /** + * setTextContents test. + */ + this.setTextContents = function setTextContents(aValue, aSkipStartOffset) { + var testID = "setTextContents '" + aValue + "' for " + prettyName(aID); + + function setTextContentsInvoke() { + dump(`\nsetTextContents '${aValue}'\n`); + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.setTextContents(aValue); + } + + aSkipStartOffset = aSkipStartOffset || 0; + var insertTripple = aValue + ? [aSkipStartOffset, aSkipStartOffset + aValue.length, aValue] + : null; + var oldValue = getValue(); + var removeTripple = oldValue + ? [aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue] + : null; + + this.generateTest( + removeTripple, + insertTripple, + setTextContentsInvoke, + getValueChecker(aValue), + testID + ); + }; + + /** + * insertText test. + */ + this.insertText = function insertText(aStr, aPos, aResStr, aResPos) { + var testID = + "insertText '" + aStr + "' at " + aPos + " for " + prettyName(aID); + + function insertTextInvoke() { + dump(`\ninsertText '${aStr}' at ${aPos} pos\n`); + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.insertText(aStr, aPos); + } + + var resPos = aResPos != undefined ? aResPos : aPos; + this.generateTest( + null, + [resPos, resPos + aStr.length, aStr], + insertTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + /** + * copyText test. + */ + this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) { + var testID = + "copyText from " + + aStartPos + + " to " + + aEndPos + + " for " + + prettyName(aID); + + function copyTextInvoke() { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.copyText(aStartPos, aEndPos); + } + + this.generateTest( + null, + null, + copyTextInvoke, + getClipboardChecker(aClipboardStr), + testID + ); + }; + + /** + * copyText and pasteText test. + */ + this.copyNPasteText = function copyNPasteText( + aStartPos, + aEndPos, + aPos, + aResStr + ) { + var testID = + "copyText from " + + aStartPos + + " to " + + aEndPos + + "and pasteText at " + + aPos + + " for " + + prettyName(aID); + + function copyNPasteTextInvoke() { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.copyText(aStartPos, aEndPos); + acc.pasteText(aPos); + } + + this.generateTest( + null, + [aStartPos, aEndPos, getTextFromClipboard], + copyNPasteTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + /** + * cutText test. + */ + this.cutText = function cutText( + aStartPos, + aEndPos, + aResStr, + aResStartPos, + aResEndPos + ) { + var testID = + "cutText from " + + aStartPos + + " to " + + aEndPos + + " for " + + prettyName(aID); + + function cutTextInvoke() { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.cutText(aStartPos, aEndPos); + } + + var resStartPos = aResStartPos != undefined ? aResStartPos : aStartPos; + var resEndPos = aResEndPos != undefined ? aResEndPos : aEndPos; + this.generateTest( + [resStartPos, resEndPos, getTextFromClipboard], + null, + cutTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + /** + * cutText and pasteText test. + */ + this.cutNPasteText = function copyNPasteText( + aStartPos, + aEndPos, + aPos, + aResStr + ) { + var testID = + "cutText from " + + aStartPos + + " to " + + aEndPos + + " and pasteText at " + + aPos + + " for " + + prettyName(aID); + + function cutNPasteTextInvoke() { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.cutText(aStartPos, aEndPos); + acc.pasteText(aPos); + } + + this.generateTest( + [aStartPos, aEndPos, getTextFromClipboard], + [aPos, -1, getTextFromClipboard], + cutNPasteTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + /** + * pasteText test. + */ + this.pasteText = function pasteText(aPos, aResStr) { + var testID = "pasteText at " + aPos + " for " + prettyName(aID); + + function pasteTextInvoke() { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.pasteText(aPos); + } + + this.generateTest( + null, + [aPos, -1, getTextFromClipboard], + pasteTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + /** + * deleteText test. + */ + this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) { + var testID = + "deleteText from " + + aStartPos + + " to " + + aEndPos + + " for " + + prettyName(aID); + + var oldValue = getValue().substring(aStartPos, aEndPos); + var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null; + + function deleteTextInvoke() { + var acc = getAccessible(aID, [nsIAccessibleEditableText]); + acc.deleteText(aStartPos, aEndPos); + } + + this.generateTest( + removeTripple, + null, + deleteTextInvoke, + getValueChecker(aResStr), + testID + ); + }; + + // //////////////////////////////////////////////////////////////////////////// + // Implementation details. + + function getValue() { + var elm = getNode(aID); + var elmClass = ChromeUtils.getClassName(elm); + if (elmClass === "HTMLTextAreaElement" || elmClass === "HTMLInputElement") { + return elm.value; + } + + if (elmClass === "HTMLDocument") { + return elm.body.textContent; + } + + return elm.textContent; + } + + /** + * Common checkers. + */ + function getValueChecker(aValue) { + var checker = { + check: function valueChecker_check() { + is(getValue(), aValue, "Wrong value " + aValue); + }, + }; + return checker; + } + + function getClipboardChecker(aText) { + var checker = { + check: function clipboardChecker_check() { + is(getTextFromClipboard(), aText, "Wrong text in clipboard."); + }, + }; + return checker; + } + + /** + * Process next scheduled test. + */ + this.unwrapNextTest = function unwrapNextTest() { + var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1]; + if (data) { + data.func.apply(this, data.funcArgs); + } + }; + + /** + * Used to generate an invoker object for the sheduled test. + */ + this.generateTest = function generateTest( + aRemoveTriple, + aInsertTriple, + aInvokeFunc, + aChecker, + aInvokerID + ) { + var et = this; + var invoker = { + eventSeq: [], + + invoke: aInvokeFunc, + finalCheck: function finalCheck() { + // dumpTree(aID, `'${aID}' tree:`); + + aChecker.check(); + et.unwrapNextTest(); // replace dummy invoker on real invoker object. + }, + getID: function getID() { + return aInvokerID; + }, + }; + + if (aRemoveTriple) { + let checker = new textChangeChecker( + aID, + aRemoveTriple[0], + aRemoveTriple[1], + aRemoveTriple[2], + false + ); + invoker.eventSeq.push(checker); + } + + if (aInsertTriple) { + let checker = new textChangeChecker( + aID, + aInsertTriple[0], + aInsertTriple[1], + aInsertTriple[2], + true + ); + invoker.eventSeq.push(checker); + } + + // Claim that we don't want to fail when no events are expected. + if (!aRemoveTriple && !aInsertTriple) { + invoker.noEventsOnAction = true; + } + + this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker; + }; + + /** + * Run the tests. + */ + this.startTest = function startTest(aTestRun) { + var testRunObj = aTestRun; + var thisObj = this; + this.mEventQueue.onFinish = function finishCallback() { + // Notify textRun object that all tests were finished. + testRunObj.iterate(); + + // Help GC to avoid leaks (refer to aTestRun from local variable, drop + // onFinish function). + thisObj.mEventQueue.onFinish = null; + + return DO_NOT_FINISH_TEST; + }; + + this.mEventQueue.invoke(); + }; + + this.mEventQueue = new eventQueue(); + this.mEventQueueReady = false; +} diff --git a/accessible/tests/mochitest/editabletext/test_1.html b/accessible/tests/mochitest/editabletext/test_1.html new file mode 100644 index 0000000000..693d4c8ee5 --- /dev/null +++ b/accessible/tests/mochitest/editabletext/test_1.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=452161 +--> +<head> + <title>nsIAccessibleEditableText chrome tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../events.js"></script> + <script type="application/javascript" + src="editabletext.js"></script> + + <script type="application/javascript"> + // gA11yEventDumpToConsole = true; + // enableLogging("tree,verbose"); // debug + + function addTestEditable(aID, aTestRun, aBeforeContent, aAfterContent) { + var et = new editableTextTest(aID); + var startOffset = aBeforeContent ? aBeforeContent.length : 0; + // XXX afterContent currently is not used + + // //////////////////////////////////////////////////////////////////////// + // setTextContents + et.scheduleTest(et.setTextContents, "hello", startOffset); + et.scheduleTest(et.setTextContents, "katze", startOffset); + et.scheduleTest(et.setTextContents, "", startOffset); + + // //////////////////////////////////////////////////////////////////////// + // insertText + et.scheduleTest(et.insertText, "hello", startOffset, "hello"); + et.scheduleTest(et.insertText, "ma ", startOffset, "ma hello"); + et.scheduleTest(et.insertText, "ma", startOffset + 2, "mama hello"); + et.scheduleTest(et.insertText, " hello", startOffset + 10, "mama hello hello"); + + // XXX: bug 452584 + + // //////////////////////////////////////////////////////////////////////// + // deleteText +// et.deleteText(0, 5, "hello hello"); +// et.deleteText(5, 6, "hellohello"); +// et.deleteText(5, 10, "hello"); +// et.deleteText(0, 5, ""); + + // //////////////////////////////////////////////////////////////////////// + // copyNPasteText +// et.copyNPasteText(0, 0, 0, ""); +// et.insertText("hello", 0, "hello"); +// et.copyNPasteText(0, 1, 0, "hhello"); +// et.copyNPasteText(5, 6, 6, "hhelloo"); +// et.copyNPasteText(3, 4, 1, "hehelloo"); + + // //////////////////////////////////////////////////////////////////////// +// // cutNPasteText +// et.cutNPasteText(0, 1, 1, "ehhelloo"); +// et.cutNPasteText(1, 2, 0, "hehelloo"); +// et.cutNPasteText(7, 8, 8, "hehelloo"); + + aTestRun.add(et); + } + + // gA11yEventDumpToConsole = true; // debug stuff + + function runTest() { + var testRun = new editableTextTestRun(); + + addTestEditable("input", testRun); + addTestEditable("div", testRun); + addTestEditable("divb", testRun, "pseudo element", ""); + addTestEditable("diva", testRun, "", "pseudo element"); + addTestEditable("divba", testRun, "before", "after"); + addTestEditable(getNode("frame").contentDocument, testRun); + + testRun.run(); // Will call SimpleTest.finish(); + } + + function doTest() { + // Prepare tested elements. + + // Design mode on/off triggers an editable state change event on + // the document accessible. + var frame = getNode("frame"); + waitForEvent(EVENT_STATE_CHANGE, frame.contentDocument, runTest); + frame.contentDocument.designMode = "on"; + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + <style> + #divb::before, + #diva::after { + content: "pseudo element"; + } + #divba::before { + content: "before"; + } + #divba::after { + content: "after"; + } + </style> +</head> +<body> + + <a target="_blank" + title="nsIAccessibleEditableText chrome tests" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=452161"> + Bug 452161 + </a> + <a target="_blank" + title="Cache rendered text on a11y side" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=626660"> + Bug 626660 + </a> + <a target="_blank" + title="Pseudo element support test" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1105611"> + Bug 1105611 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="input"/> + + <div id="div" contenteditable="true"></div> + <div id="divb" contenteditable="true"></div> + <div id="diva" contenteditable="true"></div> + <div id="divba" contenteditable="true"></div> + + <iframe id="frame"/> +</body> +</html> diff --git a/accessible/tests/mochitest/editabletext/test_2.html b/accessible/tests/mochitest/editabletext/test_2.html new file mode 100644 index 0000000000..1d252d836f --- /dev/null +++ b/accessible/tests/mochitest/editabletext/test_2.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleEditableText chrome tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../events.js"></script> + <script type="application/javascript" + src="editabletext.js"></script> + + <script type="application/javascript"> + function doTest() { + var et = new editableTextTest("input"); + + // 'ee' insertion/removal at 1 or 2 offset of 'hello'/'heeello' string + // reports 'ee' text was inserted/removed at 2 offset. + et.scheduleTest(et.insertText, "ee", 1, "heeello", 2); + et.scheduleTest(et.copyText, 1, 3, "ee"); + et.scheduleTest(et.cutText, 1, 3, "hello", 2, 4); + et.scheduleTest(et.insertText, "ee", 2, "heeello", 2); + et.scheduleTest(et.cutText, 2, 4, "hello", 2, 4); + + et.scheduleTest(et.deleteText, 1, 3, "hlo"); + et.scheduleTest(et.pasteText, 1, "heelo"); + + var testRun = new editableTextTestRun(); + testRun.add(et); + testRun.run(); // Will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="HyperText accessible should get focus when the caret is positioned inside of it, text is changed or copied into clipboard by ATs" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=524115"> + Mozilla Bug 524115 + </a> + <a target="_blank" + title="Cache rendered text on a11y side" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=626660"> + Mozilla Bug 626660 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="input" value="hello"/> + +</body> +</html> |