diff options
Diffstat (limited to '')
49 files changed, 3323 insertions, 0 deletions
diff --git a/editor/spellchecker/tests/bug1200533_subframe.html b/editor/spellchecker/tests/bug1200533_subframe.html new file mode 100644 index 0000000000..f095c0601f --- /dev/null +++ b/editor/spellchecker/tests/bug1200533_subframe.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Language" content="en-US"> +</head> +<body> +<textarea id="none">root en-US</textarea> +<textarea id="en-GB" lang="en-GB">root en-US, but element en-GB</textarea> +<textarea id="en-gb" lang="en-gb">root en-US, but element en-gb (lower case)</textarea> +<textarea id="en-ZA-not-avail" lang="en-ZA">root en-US, but element en-ZA (which is not installed)</textarea> +<textarea id="en-generic" lang="en">root en-US, but element en</textarea> +<textarea id="en" lang="en">root en-US, but element en</textarea> +<textarea id="ko-not-avail" lang="ko">root en-US, but element ko (which is not installed)</textarea> +</body> +</html> diff --git a/editor/spellchecker/tests/bug1204147_subframe.html b/editor/spellchecker/tests/bug1204147_subframe.html new file mode 100644 index 0000000000..a9b1225cd9 --- /dev/null +++ b/editor/spellchecker/tests/bug1204147_subframe.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<body> +<textarea id="en-GB" lang="en-GB">element en-GB</textarea> +<textarea id="en-US" lang="testing-XX">element should default to en-US</textarea> + +<div id="trouble-maker" contenteditable>the presence of this div triggers the faulty code path</div> +</body> +</html> diff --git a/editor/spellchecker/tests/bug1204147_subframe2.html b/editor/spellchecker/tests/bug1204147_subframe2.html new file mode 100644 index 0000000000..935777bd99 --- /dev/null +++ b/editor/spellchecker/tests/bug1204147_subframe2.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<body> +<textarea id="en-GB" lang="en-GB">element en-GB</textarea> +<textarea id="en-US" lang="testing-XX">element should default to en-US</textarea> +</body> +</html> diff --git a/editor/spellchecker/tests/bug678842_subframe.html b/editor/spellchecker/tests/bug678842_subframe.html new file mode 100644 index 0000000000..39d578ee41 --- /dev/null +++ b/editor/spellchecker/tests/bug678842_subframe.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<body> +<textarea id="textarea" lang="testing-XXX"></textarea> +</body> +</html> diff --git a/editor/spellchecker/tests/bug717433_subframe.html b/editor/spellchecker/tests/bug717433_subframe.html new file mode 100644 index 0000000000..3c2927e88f --- /dev/null +++ b/editor/spellchecker/tests/bug717433_subframe.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<body> +<textarea id="textarea" lang="en"></textarea> +</body> +</html> diff --git a/editor/spellchecker/tests/chrome.ini b/editor/spellchecker/tests/chrome.ini new file mode 100644 index 0000000000..76faf04121 --- /dev/null +++ b/editor/spellchecker/tests/chrome.ini @@ -0,0 +1,9 @@ +[DEFAULT] +prefs = + gfx.font_loader.delay=0 + +skip-if = os == 'android' + +[test_nsIEditorSpellCheck_ReplaceWord.html] +support-files = + spellcheck.js diff --git a/editor/spellchecker/tests/de-DE/de_DE.aff b/editor/spellchecker/tests/de-DE/de_DE.aff new file mode 100644 index 0000000000..5dc6896b6d --- /dev/null +++ b/editor/spellchecker/tests/de-DE/de_DE.aff @@ -0,0 +1,2 @@ +# Affix file for German English dictionary +# Fake file, nothing here. diff --git a/editor/spellchecker/tests/de-DE/de_DE.dic b/editor/spellchecker/tests/de-DE/de_DE.dic new file mode 100644 index 0000000000..415c216861 --- /dev/null +++ b/editor/spellchecker/tests/de-DE/de_DE.dic @@ -0,0 +1,6 @@ +5 +ein +guter +heute +ist +Tag diff --git a/editor/spellchecker/tests/en-AU/en_AU.aff b/editor/spellchecker/tests/en-AU/en_AU.aff new file mode 100644 index 0000000000..e0c467248d --- /dev/null +++ b/editor/spellchecker/tests/en-AU/en_AU.aff @@ -0,0 +1,2 @@ +# Affix file for British English dictionary +# Fake file, nothing here. diff --git a/editor/spellchecker/tests/en-AU/en_AU.dic b/editor/spellchecker/tests/en-AU/en_AU.dic new file mode 100644 index 0000000000..0a1be725d4 --- /dev/null +++ b/editor/spellchecker/tests/en-AU/en_AU.dic @@ -0,0 +1,4 @@ +3 +Mary +Paul +Peter diff --git a/editor/spellchecker/tests/en-GB/en_GB.aff b/editor/spellchecker/tests/en-GB/en_GB.aff new file mode 100644 index 0000000000..e0c467248d --- /dev/null +++ b/editor/spellchecker/tests/en-GB/en_GB.aff @@ -0,0 +1,2 @@ +# Affix file for British English dictionary +# Fake file, nothing here. diff --git a/editor/spellchecker/tests/en-GB/en_GB.dic b/editor/spellchecker/tests/en-GB/en_GB.dic new file mode 100644 index 0000000000..0a1be725d4 --- /dev/null +++ b/editor/spellchecker/tests/en-GB/en_GB.dic @@ -0,0 +1,4 @@ +3 +Mary +Paul +Peter diff --git a/editor/spellchecker/tests/mochitest.ini b/editor/spellchecker/tests/mochitest.ini new file mode 100644 index 0000000000..6d3c53d71b --- /dev/null +++ b/editor/spellchecker/tests/mochitest.ini @@ -0,0 +1,68 @@ +[DEFAULT] +prefs = + gfx.font_loader.delay=0 + +skip-if = os == 'android' +support-files = + en-GB/en_GB.dic + en-GB/en_GB.aff + en-AU/en_AU.dic + en-AU/en_AU.aff + de-DE/de_DE.dic + de-DE/de_DE.aff + ru-RU/ru_RU.dic + ru-RU/ru_RU.aff + spellcheck.js + +[test_async_UpdateCurrentDictionary.html] +[test_bug1100966.html] +[test_bug1154791.html] +[test_bug1200533.html] +skip-if = + http3 +support-files = + bug1200533_subframe.html +[test_bug1204147.html] +skip-if = + http3 +support-files = + bug1204147_subframe.html + bug1204147_subframe2.html +[test_bug1205983.html] +[test_bug1209414.html] +[test_bug1219928.html] +skip-if = true +[test_bug1365383.html] +[test_bug1368544.html] +[test_bug1402822.html] +[test_bug1418629.html] +[test_bug1497480.html] +[test_bug1602526.html] +[test_bug1761273.html] +[test_bug1773802.html] +[test_bug1837268.html] +[test_bug366682.html] +[test_bug432225.html] +[test_bug484181.html] +[test_bug596333.html] +[test_bug636465.html] +[test_bug678842.html] +skip-if = + http3 +support-files = + bug678842_subframe.html +[test_bug697981.html] +[test_bug717433.html] +skip-if = + http3 +support-files = + bug717433_subframe.html +[test_multiple_content_languages.html] +skip-if = + http3 +support-files = + multiple_content_languages_subframe.html +[test_spellcheck_after_edit.html] +[test_spellcheck_after_pressing_navigation_key.html] +[test_spellcheck_selection.html] +[test_suggest.html] diff --git a/editor/spellchecker/tests/multiple_content_languages_subframe.html b/editor/spellchecker/tests/multiple_content_languages_subframe.html new file mode 100644 index 0000000000..da6a4ed664 --- /dev/null +++ b/editor/spellchecker/tests/multiple_content_languages_subframe.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Language" content="en-US, en-GB, ko, en-CA"> +</head> +<body> +<textarea id="none">root en-US and en-GB</textarea> +<textarea id="en-GB" lang="en-GB">root multiple, but element only en-GB</textarea> +<textarea id="en-ZA-not-avail" lang="en-ZA">root multiple en, but element en-ZA (which is not installed)</textarea> +<textarea id="en" lang="en">root multiple en, but element en</textarea> +<textarea id="ko-not-avail" lang="ko">root multiple en, but element ko (which is not installed)</textarea> +</body> +</html> diff --git a/editor/spellchecker/tests/ru-RU/ru_RU.aff b/editor/spellchecker/tests/ru-RU/ru_RU.aff new file mode 100644 index 0000000000..c6cf721484 --- /dev/null +++ b/editor/spellchecker/tests/ru-RU/ru_RU.aff @@ -0,0 +1 @@ +SET KOI8-R diff --git a/editor/spellchecker/tests/ru-RU/ru_RU.dic b/editor/spellchecker/tests/ru-RU/ru_RU.dic new file mode 100644 index 0000000000..dbfe3a9f23 --- /dev/null +++ b/editor/spellchecker/tests/ru-RU/ru_RU.dic @@ -0,0 +1,2 @@ +1 +правильный diff --git a/editor/spellchecker/tests/spellcheck.js b/editor/spellchecker/tests/spellcheck.js new file mode 100644 index 0000000000..b6a1586628 --- /dev/null +++ b/editor/spellchecker/tests/spellcheck.js @@ -0,0 +1,36 @@ +function isSpellingCheckOk(aEditor, aMisspelledWords, aTodo = false) { + var selcon = aEditor.selectionController; + var sel = selcon.getSelection(selcon.SELECTION_SPELLCHECK); + var numWords = sel.rangeCount; + + if (aTodo) { + todo_is( + numWords, + aMisspelledWords.length, + "Correct number of misspellings and words." + ); + } else { + is( + numWords, + aMisspelledWords.length, + "Correct number of misspellings and words." + ); + } + + if (numWords !== aMisspelledWords.length) { + return false; + } + + for (var i = 0; i < numWords; ++i) { + var word = String(sel.getRangeAt(i)); + if (aTodo) { + todo_is(word, aMisspelledWords[i], "Misspelling is what we think it is."); + } else { + is(word, aMisspelledWords[i], "Misspelling is what we think it is."); + } + if (word !== aMisspelledWords[i]) { + return false; + } + } + return true; +} diff --git a/editor/spellchecker/tests/test_async_UpdateCurrentDictionary.html b/editor/spellchecker/tests/test_async_UpdateCurrentDictionary.html new file mode 100644 index 0000000000..6f8371d2cd --- /dev/null +++ b/editor/spellchecker/tests/test_async_UpdateCurrentDictionary.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=856270 +--> +<head> + <title>Test for Bug 856270 - Async UpdateCurrentDictionary</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=856270">Mozilla Bug 856270</a> +<p id="display"></p> +<div id="content"> +<textarea id="editor" spellcheck="true"></textarea> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(start); + +function start() { + var textarea = document.getElementById("editor"); + textarea.focus(); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ) + onSpellCheck(textarea, function() { + var isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(false); + ok(isc, "Inline spell checker should exist after focus and spell check"); + var sc = isc.spellChecker; + + sc.setCurrentDictionaries(["testing-XX"]).then(() => { + is(true, false, "Setting a non-existent dictionary should fail"); + }, () => { + let currentDictionaries = sc.getCurrentDictionaries(); + + is(currentDictionaries.length, 0, "expected no dictionaries"); + // First, set the lang attribute on the textarea, call Update, and make + // sure the spell checker's language was updated appropriately. + var lang = "en-US"; + textarea.setAttribute("lang", lang); + sc.UpdateCurrentDictionary(function() { + currentDictionaries = sc.getCurrentDictionaries(); + is(currentDictionaries.length, 1, "expected one dictionary"); + is(sc.getCurrentDictionaries()[0], lang, + "UpdateCurrentDictionary should set the current dictionary."); + sc.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + }); + }); + }); +} +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1100966.html b/editor/spellchecker/tests/test_bug1100966.html new file mode 100644 index 0000000000..4ed52968a0 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1100966.html @@ -0,0 +1,74 @@ +<!DOCTYPE> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1100966 +--> +<head> + <title>Test for Bug 1100966</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<body> +<div id="display"> +</div> +<div id="content" contenteditable> +=====<br> +correct<br> +fivee sixx<br> +==== +</div> +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> + +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +/** Test for Bug 1100966 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var div = document.getElementById("content"); + div.focus(); + synthesizeMouseAtCenter(div, {}); + + getSpellChecker().UpdateCurrentDictionary(() => { + sendString(" "); + SimpleTest.executeSoon(function() { + sendString("a"); + SimpleTest.executeSoon(function() { + synthesizeKey("KEY_Backspace"); + + maybeOnSpellCheck(div, function() { + var sel = getSpellCheckSelection(); + is(sel.rangeCount, 2, "We should have two misspelled words"); + is(String(sel.getRangeAt(0)), "fivee", "Correct misspelled word"); + is(String(sel.getRangeAt(1)), "sixx", "Correct misspelled word"); + + SimpleTest.finish(); + }); + }); + }); + }); +}); + +function getEditor() { + var editingSession = SpecialPowers.wrap(window).docShell.editingSession; + return editingSession.getEditorForWindow(window); +} + +function getSpellChecker() { + return getEditor().getInlineSpellChecker(false).spellChecker; +} + +function getSpellCheckSelection() { + var selcon = getEditor().selectionController; + return selcon.getSelection(selcon.SELECTION_SPELLCHECK); +} + +</script> +</body> + +</html> diff --git a/editor/spellchecker/tests/test_bug1154791.html b/editor/spellchecker/tests/test_bug1154791.html new file mode 100644 index 0000000000..7ed6c53e35 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1154791.html @@ -0,0 +1,74 @@ +<!DOCTYPE> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1154791 +--> +<head> + <title>Test for Bug 1154791</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<body> +<div id="display"> +</div> + +<div id="content" contenteditable> +<tt>thiss onee is stilll a</tt> +</div> + +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> + +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +/** Test for Bug 1154791 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var div = document.getElementById("content"); + div.focus(); + getSpellChecker().UpdateCurrentDictionary(() => { + synthesizeMouseAtCenter(div, {}); + synthesizeKey("KEY_ArrowLeft"); + synthesizeKey("KEY_ArrowLeft"); + + SimpleTest.executeSoon(function() { + synthesizeKey("KEY_Backspace"); + SimpleTest.executeSoon(function() { + sendString(" "); + + maybeOnSpellCheck(div, function() { + var sel = getSpellCheckSelection(); + is(sel.rangeCount, 2, "We should have two misspelled words"); + is(String(sel.getRangeAt(0)), "thiss", "Correct misspelled word"); + is(String(sel.getRangeAt(1)), "onee", "Correct misspelled word"); + + SimpleTest.finish(); + }); + }); + }); + }); +}); + +function getEditor() { + var editingSession = SpecialPowers.wrap(window).docShell.editingSession; + return editingSession.getEditorForWindow(window); +} + +function getSpellChecker() { + return getEditor().getInlineSpellChecker(false).spellChecker; +} + +function getSpellCheckSelection() { + var selcon = getEditor().selectionController; + return selcon.getSelection(selcon.SELECTION_SPELLCHECK); +} + +</script> +</body> + +</html> diff --git a/editor/spellchecker/tests/test_bug1200533.html b/editor/spellchecker/tests/test_bug1200533.html new file mode 100644 index 0000000000..d97dea8ccd --- /dev/null +++ b/editor/spellchecker/tests/test_bug1200533.html @@ -0,0 +1,163 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1200533 +--> +<head> + <title>Test for Bug 1200533</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1200533">Mozilla Bug 1200533</a> +<p id="display"></p> +<iframe id="content"></iframe> + +</div> +<pre id="test"> +<script class="testbody" ttype="application/javascript"> + +/** Test for Bug 1200533 **/ +/** Visit the elements defined above and check the dictionary we got **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); + +var tests = [ + // text area, value of spellchecker.dictionary, result. + // Result: Document language. + [ "none", "", "en-US" ], + // Result: Element language. + [ "en-GB", "", "en-GB" ], + [ "en-gb", "", "en-GB" ], + // Result: Random en-* or en-US (if application locale is en-US). + [ "en-ZA-not-avail", "", "*" ], + [ "en-generic", "", "*" ], + [ "en", "", "*" ], + // Result: Locale. + [ "ko-not-avail", "", "en-US" ], + + // Result: Preference value in all cases. + [ "en-ZA-not-avail", "en-AU", "en-AU" ], + [ "en-generic", "en-AU", "en-AU" ], + [ "ko-not-avail", "en-AU", "en-AU" ], + + // Result: Random en-*. + [ "en-ZA-not-avail", "de-DE", "*" ], + [ "en-generic", "de-DE", "*" ], + // Result: Preference value. + [ "ko-not-avail", "de-DE", "de-DE" ], + ]; + +var loadCount = 0; +var retrying = false; +var script; + +var loadListener = async function(evt) { + if (loadCount == 0) { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install en-GB, en-AU and de-DE dictionaries. + var en_GB = dir.clone(); + var en_AU = dir.clone(); + var de_DE = dir.clone(); + en_GB.append("en-GB"); + en_AU.append("en-AU"); + de_DE.append("de-DE"); + hunspell.addDirectory(en_GB); + hunspell.addDirectory(en_AU); + hunspell.addDirectory(de_DE); + + addMessageListener("check-existence", + () => [en_GB.exists(), en_AU.exists(), + de_DE.exists()]); + addMessageListener("destroy", () => { + hunspell.removeDirectory(en_GB); + hunspell.removeDirectory(en_AU); + hunspell.removeDirectory(de_DE); + }); + }); + var existenceChecks = await script.sendQuery("check-existence"); + is(existenceChecks[0], true, "true expected (en-GB directory should exist)"); + is(existenceChecks[1], true, "true expected (en-AU directory should exist)"); + is(existenceChecks[2], true, "true expected (de-DE directory should exist)"); + } + + SpecialPowers.pushPrefEnv({set: [["spellchecker.dictionary", tests[loadCount][1]]]}, + function() { continueTest(evt); }); +}; + +function continueTest(evt) { + var doc = evt.target.contentDocument; + var elem = doc.getElementById(tests[loadCount][0]); + var editor = SpecialPowers.wrap(elem).editor; + editor.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor.getInlineSpellChecker(true); + const is_en_US = SpecialPowers.Services.locale.appLocaleAsBCP47 == "en-US"; + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(elem, async function() { + var spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries; + try { + currentDictionaries = spellchecker.getCurrentDictionaries(); + } catch (e) {} + + if (!currentDictionaries && !retrying) { + // It's possible for an asynchronous font-list update to cause a reflow + // that disrupts the async spell-check and results in not getting a + // current dictionary here; if that happens, we retry the same testcase + // by reloading the iframe without bumping loadCount. + info(`No current dictionary: retrying testcase ${loadCount}`); + retrying = true; + } else { + is(currentDictionaries.length, 1, "expected one dictionary"); + let dict = currentDictionaries[0]; + if (tests[loadCount][2] != "*") { + is(dict, tests[loadCount][2], "expected " + tests[loadCount][2]); + } else if (is_en_US && tests[loadCount][0].startsWith("en")) { + // Current application locale is en-US and content lang is en or + // en-unknown, so we should use en-US dictionary as default. + is(dict, "en-US", "expected en-US that is application locale"); + } else { + var gotEn = (dict == "en-GB" || dict == "en-AU" || dict == "en-US"); + is(gotEn, true, "expected en-AU or en-GB or en-US"); + } + + loadCount++; + retrying = false; + } + + if (loadCount < tests.length) { + // Load the iframe again. + content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug1200533_subframe.html?firstload=false"; + } else { + // Remove the fake dictionaries again, since it's otherwise picked up by later tests. + await script.sendQuery("destroy"); + + SimpleTest.finish(); + } + }); +} + +content.addEventListener("load", loadListener); + +content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug1200533_subframe.html?firstload=true"; + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1204147.html b/editor/spellchecker/tests/test_bug1204147.html new file mode 100644 index 0000000000..3d5f0e120f --- /dev/null +++ b/editor/spellchecker/tests/test_bug1204147.html @@ -0,0 +1,115 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1204147 +--> +<head> + <title>Test for Bug 1204147</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1204147">Mozilla Bug 1204147</a> +<p id="display"></p> +<iframe id="content"></iframe> +</div> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1204147 **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); +// Load a subframe containing an editor with using "en-GB". At first +// load, it will set the dictionary to "en-GB". The bug was that a content preference +// was also created. At second load, we check the dictionary for another element, +// one that should use "en-US". With the bug corrected, we get "en-US", before +// we got "en-GB" from the content preference. + +var firstLoad = true; +var script; + +var loadListener = async function(evt) { + if (firstLoad) { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install en-GB dictionary. + let en_GB = dir.clone(); + en_GB.append("en-GB"); + hunspell.addDirectory(en_GB); + + addMessageListener("en_GB-exists", () => en_GB.exists()); + addMessageListener("destroy", () => hunspell.removeDirectory(en_GB)); + }); + is(await script.sendQuery("en_GB-exists"), true, + "true expected (en-GB directory should exist)"); + } + + var doc = evt.target.contentDocument; + var elem; + if (firstLoad) { + elem = doc.getElementById("en-GB"); + } else { + elem = doc.getElementById("en-US"); + } + + var editor = SpecialPowers.wrap(elem).editor; + editor.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor.getInlineSpellChecker(true); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(elem, async function() { + let spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + is(currentDictionaries.length, 1, "expected one dictionary"); + let currentDictionary = currentDictionaries[0]; + if (firstLoad) { + firstLoad = false; + + // First time around, the element's language should be used. + is(currentDictionary, "en-GB", "unexpected lang " + currentDictionary + " instead of en-GB"); + + // Note that on second load, we load a different page, which does NOT have the trouble-causing + // contenteditable in it. Sadly, loading the same page with the trouble-maker in it + // doesn't allow the retrieval of the spell check dictionary used for the element, + // because the trouble-maker causes the 'global' spell check dictionary to be set to "en-GB" + // (since it picks the first one from the list) before we have the chance to retrieve + // the dictionary for the element (which happens asynchonously after the spell check has completed). + content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug1204147_subframe2.html?firstload=false"; + } else { + // Second time around, the element should default to en-US. + // Without the fix, the first run sets the content preference to en-GB for the whole site. + is(currentDictionary, "en-US", "unexpected lang " + currentDictionary + " instead of en-US"); + content.removeEventListener("load", loadListener); + + // Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests. + await script.sendQuery("destroy"); + + // Reset the preference, so the last value we set doesn't collide with the next test. + SimpleTest.finish(); + } + }); +}; + +content.addEventListener("load", loadListener); + +content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug1204147_subframe.html?firstload=true"; + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1205983.html b/editor/spellchecker/tests/test_bug1205983.html new file mode 100644 index 0000000000..3de5e196bf --- /dev/null +++ b/editor/spellchecker/tests/test_bug1205983.html @@ -0,0 +1,134 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1205983 +--> +<head> + <title>Test for Bug 1205983</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205983">Mozilla Bug 1205983</a> +<p id="display"></p> +</div> + +<div contenteditable id="de-DE" lang="de-DE" onfocus="deFocus()">German heute ist ein guter Tag</div> +<textarea id="en-US" lang="en-US" onfocus="enFocus()">Nogoodword today is a nice day</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +function getMisspelledWords(editor) { + return editor.selectionController.getSelection(SpecialPowers.Ci.nsISelectionController.SELECTION_SPELLCHECK).toString(); +} + +var elem_de; +var editor_de; +var selcon_de; +var script; + +var { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +/** Test for Bug 1205983 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async function() { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install de-DE dictionary. + var de_DE = dir.clone(); + de_DE.append("de-DE"); + hunspell.addDirectory(de_DE); + + addMessageListener("de_DE-exists", () => de_DE.exists()); + addMessageListener("destroy", () => hunspell.removeDirectory(de_DE)); + }); + is(await script.sendQuery("de_DE-exists"), true, + "true expected (de_DE directory should exist)"); + + document.getElementById("de-DE").focus(); +}); + +function deFocus() { + elem_de = document.getElementById("de-DE"); + + maybeOnSpellCheck(elem_de, function() { + var editingSession = SpecialPowers.wrap(window).docShell.editingSession; + editor_de = editingSession.getEditorForWindow(window); + selcon_de = editor_de.selectionController; + var sel = selcon_de.getSelection(selcon_de.SELECTION_SPELLCHECK); + + // Check that we spelled in German, so there is only one misspelled word. + is(sel.toString(), "German", "one misspelled word expected: German"); + + // Now focus the textarea, which requires English spelling. + document.getElementById("en-US").focus(); + }); +} + +function enFocus() { + var elem_en = document.getElementById("en-US"); + var editor_en = + SpecialPowers.wrap(elem_en) + .editor; + editor_en.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor_en.getInlineSpellChecker(true); + + maybeOnSpellCheck(elem_en, async function() { + var spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + is(currentDictionaries.length, 1, "expected one dictionary"); + let currentDictionary = currentDictionaries[0]; + + // Check that the English dictionary is loaded and that the spell check has worked. + is(currentDictionary, "en-US", "expected en-US"); + is(getMisspelledWords(editor_en), "Nogoodword", "one misspelled word expected: Nogoodword"); + + // So far all was boring. The important thing is whether the spell check result + // in the de-DE editor is still the same. After losing focus, no spell check + // updates should take place there. + var sel = selcon_de.getSelection(selcon_de.SELECTION_SPELLCHECK); + is(sel.toString(), "German", "one misspelled word expected: German"); + + // Remove the fake de_DE dictionary again. + await script.sendQuery("destroy"); + + // Focus again, so the spelling gets updated, but before we need to kill the focus handler. + elem_de.onfocus = null; + elem_de.blur(); + elem_de.focus(); + + // After removal, the de_DE editor should refresh the spelling with en-US. + maybeOnSpellCheck(elem_de, function() { + var endSel = selcon_de.getSelection(selcon_de.SELECTION_SPELLCHECK); + // eslint-disable-next-line no-useless-concat + is(endSel.toString(), "heute" + "ist" + "ein" + "guter", + "some misspelled words expected: heute ist ein guter"); + + // If we don't reset this, we cause massive leaks. + selcon_de = null; + editor_de = null; + + SimpleTest.finish(); + }); + }); +} + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1209414.html b/editor/spellchecker/tests/test_bug1209414.html new file mode 100644 index 0000000000..b4b0cae947 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1209414.html @@ -0,0 +1,144 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1209414 +--> +<head> + <title>Test for Bug 1209414</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209414">Mozilla Bug 1209414</a> +<p id="display"></p> +</div> + +<textarea id="de-DE" lang="de-DE">heute ist ein guter Tag - today is a good day</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +const Ci = SpecialPowers.Ci; + +function getMisspelledWords(editor) { + return editor.selectionController.getSelection(Ci.nsISelectionController.SELECTION_SPELLCHECK).toString(); +} + +var elem_de; +var editor_de; +var script; + +/** Test for Bug 1209414 **/ +/* + * All we want to do in this test is change the spelling using a right-click and selection from the menu. + * This is necessary since all the other tests use setCurrentDictionaries() which doesn't reflect + * user behaviour. + */ + +let { maybeOnSpellCheck, onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async function() { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + var chromeWin = actorParent.rootFrameLoader + .ownerElement.ownerGlobal.browsingContext.topChromeWindow; + var contextMenu = chromeWin.document.getElementById("contentAreaContextMenu"); + contextMenu.addEventListener("popupshown", + () => sendAsyncMessage("popupshown")); + + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install de-DE dictionary. + let de_DE = dir.clone(); + de_DE.append("de-DE"); + hunspell.addDirectory(de_DE); + + addMessageListener("hidepopup", function() { + var state = contextMenu.state; + + // Select Language from the menu. Take a look at + // toolkit/modules/InlineSpellChecker.sys.mjs to see how the menu works. + contextMenu.ownerDocument.getElementById("spell-check-dictionary-en-US") + .doCommand(); + contextMenu.hidePopup(); + return state; + }); + addMessageListener("destroy", () => hunspell.removeDirectory(de_DE)); + addMessageListener("contextMenu-not-null", () => contextMenu != null); + addMessageListener("de_DE-exists", () => de_DE.exists()); + }); + is(await script.sendQuery("contextMenu-not-null"), true, + "Got context menu XUL"); + is(await script.sendQuery("de_DE-exists"), true, + "true expected (de_DE directory should exist)"); + script.addMessageListener("popupshown", handlePopup); + + elem_de = document.getElementById("de-DE"); + editor_de = SpecialPowers.wrap(elem_de).editor; + editor_de.setSpellcheckUserOverride(true); + + maybeOnSpellCheck(elem_de, function() { + var inlineSpellChecker = editor_de.getInlineSpellChecker(true); + var spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + // Check that the German dictionary is loaded and that the spell check has worked. + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "de-DE", "expected de-DE"); + // eslint-disable-next-line no-useless-concat + is(getMisspelledWords(editor_de), "today" + "is" + "a" + "good" + "day", "some misspelled words expected: today is a good day"); + + // Focus again, just to be sure that the context-click won't trigger another spell check. + elem_de.focus(); + + // Make sure all spell checking action is done before right-click to select the en-US dictionary. + maybeOnSpellCheck(elem_de, function() { + synthesizeMouse(elem_de, 2, 2, { type: "contextmenu", button: 2 }, window); + }); + }); +}); + +async function handlePopup() { + var state = await script.sendQuery("hidepopup"); + is(state, "open", "checking if popup is open"); + + onSpellCheck(elem_de, async function() { + var inlineSpellChecker = editor_de.getInlineSpellChecker(true); + var spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + // Check that the English dictionary is loaded and that the spell check has worked. + is(currentDictionaries.length, 2, "expected two dictionaries"); + let dictionaryArray = Array.from(currentDictionaries); + ok(dictionaryArray.includes("de-DE"), "expected de-DE"); + ok(dictionaryArray.includes("en-US"), "expected en-US"); + is(getMisspelledWords(editor_de), "", "No misspelled words expected"); + + // Remove the fake de_DE dictionary again. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + }); +} + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1219928.html b/editor/spellchecker/tests/test_bug1219928.html new file mode 100644 index 0000000000..83ae8de908 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1219928.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1219928 +--> +<head> + <title>Test for Bug 1219928</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1219928">Mozilla Bug 1219928</a> +<p id="display"></p> + +<div contenteditable id="en-US" lang="en-US"> +<p>And here a missspelled word</p> +<style> +<!-- and here another onnee in a style comment --> +</style> +</div> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1219928 **/ +/* Very simple test to check that <style> blocks are skipped in the spell check */ + +var spellchecker; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + + var elem = document.getElementById("en-US"); + elem.focus(); + + maybeOnSpellCheck(elem, function() { + var editingSession = SpecialPowers.wrap(window).docShell.editingSession; + var editor = editingSession.getEditorForWindow(window); + var selcon = editor.selectionController; + var sel = selcon.getSelection(selcon.SELECTION_SPELLCHECK); + + is(sel.toString(), "missspelled", "one misspelled word expected: missspelled"); + + spellchecker = SpecialPowers.Cu.createSpellChecker(); + spellchecker.setFilterType(spellchecker.FILTERTYPE_NORMAL); + spellchecker.InitSpellChecker(editor, false, spellCheckStarted); + }); +}); + +function spellCheckStarted() { + var misspelledWord = spellchecker.GetNextMisspelledWord(); + is(misspelledWord, "missspelled", "first misspelled word expected: missspelled"); + + // Without the fix, the next misspelled word was 'onnee', so we check that we don't get it. + misspelledWord = spellchecker.GetNextMisspelledWord(); + isnot(misspelledWord, "onnee", "second misspelled word should not be: onnee"); + + spellchecker = ""; + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1365383.html b/editor/spellchecker/tests/test_bug1365383.html new file mode 100644 index 0000000000..d4333b4eb0 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1365383.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1365383 +--> +<head> + <title>Test for Bug 1365383</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> + +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1365383">Mozilla Bug 1365383</a> +<p id="display"></p> +<div id="content"> +<textarea id="editor" spellcheck="true"></textarea> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(() => { + let textarea = document.getElementById("editor"); + let editor = SpecialPowers.wrap(textarea).editor; + + let spellChecker = SpecialPowers.Cu.createSpellChecker(); + + // Callback parameter isn't set + spellChecker.InitSpellChecker(editor, false); + + textarea.focus(); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(textarea, () => { + // Callback parameter isn't set + spellChecker.UpdateCurrentDictionary(); + + var canSpellCheck = spellChecker.canSpellCheck(); + ok(canSpellCheck, "spellCheck is enabled"); + SimpleTest.finish(); + }); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1368544.html b/editor/spellchecker/tests/test_bug1368544.html new file mode 100644 index 0000000000..4a182615a8 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1368544.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi=id=1368544 +--> +<html> +<head> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1368544">Mozilla Bug 1368544</a> +<div id="display"></div> +<textarea id=textarea></textarea> +<pre id="test"> +</pre> + +<script class="testbody"> +function hasEmptyTextNode(div) { + return div.firstChild.nodeType === Node.TEXT_NODE && div.firstChild.length === 0; +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(() => { + let textarea = document.getElementById("textarea"); + let editor = SpecialPowers.wrap(textarea).editor; + + let spellChecker = SpecialPowers.Cu.createSpellChecker(); + spellChecker.InitSpellChecker(editor, false); + + textarea.focus(); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(textarea, () => { + spellChecker.UpdateCurrentDictionary(() => { + textarea.value = "ABC"; + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child nodes"); + sendString("D"); + is(textarea.value, "ABCD", "D is last character"); + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child nodes"); + textarea.value = ""; + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child node even if value is empty"); + + sendString("AAA"); + synthesizeKey("KEY_Backspace", {repeat: 3}); + is(textarea.value, "", "value is empty"); + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child node even if value is empty"); + + textarea.value = "ABC"; + SpecialPowers.wrap(textarea).setUserInput(""); + is(textarea.value, "", + "textarea should become empty when setUserInput() is called with empty string"); + ok(hasEmptyTextNode(editor.rootElement), + "editor of textarea should only have an empty text node when user input emulation set the value to empty"); + todo(editor.rootElement.childNodes.length === 1, "editor of textarea should only have a single child"); + if (editor.rootElement.childNodes.length > 1) { + is(editor.rootElement.childNodes.length, 2, "There should be only one additional <br> node"); + is(editor.rootElement.lastChild.tagName.toLowerCase(), "br", "The node should be a <br> element node"); + ok(!SpecialPowers.wrap(editor.rootElement.lastChild).isPaddingForEmptyEditor, + "The <br> should not be a padding <br> element"); + } + textarea.value = "ABC"; + synthesizeKey("KEY_Enter", {repeat: 2}); + textarea.value = ""; + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child node even if value is empty"); + + sendString("AAA"); + is(textarea.value, "AAA", "value is AAA"); + textarea.addEventListener("keyup", (e) => { + if (e.key == "Enter") { + textarea.value = ""; + ok(editor.rootElement.hasChildNodes(), + "editor of textarea has child node even if value is empty"); + SimpleTest.finish(); + } + }); + + synthesizeKey("KEY_Enter"); + }); + }); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1402822.html b/editor/spellchecker/tests/test_bug1402822.html new file mode 100644 index 0000000000..6380060001 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1402822.html @@ -0,0 +1,114 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1402822 +--> +<head> + <title>Test for Bug 1402822</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1402822">Mozilla Bug 1402822</a> +<p id="display"></p> +</div> + +<textarea id="editor">heute ist ein guter Tag - today is a good day</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +const Ci = SpecialPowers.Ci; + +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +function getMisspelledWords(editor) { + return editor.selectionController.getSelection(Ci.nsISelectionController.SELECTION_SPELLCHECK).toString(); +} + +/** Test for Bug 1402822 **/ +SimpleTest.waitForExplicitFinish(); +addLoadEvent(start); +async function start() { + let script = SpecialPowers.loadChromeScript(() => { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + let dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + let hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install de-DE dictionary. + let de_DE = dir.clone(); + de_DE.append("de-DE"); + hunspell.addDirectory(de_DE); + + addMessageListener("destroy", () => hunspell.removeDirectory(de_DE)); + addMessageListener("de_DE-exists", () => de_DE.exists()); + }); + is(await script.sendQuery("de_DE-exists"), true, + "true expected (de_DE directory should exist)"); + + let textarea = document.getElementById("editor"); + let editor = SpecialPowers.wrap(textarea).editor; + textarea.focus(); + + maybeOnSpellCheck(textarea, () => { + let isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(false); + ok(isc, "Inline spell checker should exist after focus and spell check"); + let spellchecker = isc.spellChecker; + + spellchecker.setCurrentDictionaries(["en-US"]).then(() => { + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "en-US", "expected en-US"); + is(getMisspelledWords(editor), "heuteisteinguter", "some misspelled words expected: heuteisteinguter"); + spellchecker.setCurrentDictionaries(["en-US", "de-DE"]).then(() => { + textarea.blur(); + textarea.focus(); + maybeOnSpellCheck(textarea, () => { + currentDictionaries = spellchecker.getCurrentDictionaries(); + + is(currentDictionaries.length, 2, "expected two dictionaries"); + is(currentDictionaries[0], "en-US", "expected en-US"); + is(currentDictionaries[1], "de-DE", "expected de-DE"); + is(getMisspelledWords(editor), "", "No misspelled words expected"); + + spellchecker.setCurrentDictionaries(["de-DE"]).then(() => { + textarea.blur(); + textarea.focus(); + maybeOnSpellCheck(textarea, async function() { + currentDictionaries = spellchecker.getCurrentDictionaries(); + + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "de-DE", "expected de-DE"); + is(getMisspelledWords(editor), "todayisagoodday", "some misspelled words expected: todayisagoodday"); + + // Remove the fake de_DE dictionary again. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + }); + }); + }); + }); + }); + }); +} +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1418629.html b/editor/spellchecker/tests/test_bug1418629.html new file mode 100644 index 0000000000..442663f0c2 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1418629.html @@ -0,0 +1,210 @@ +<!DOCTYPE html> +<html> +<head> + <title>Mozilla bug 1418629</title> + <link rel=stylesheet href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/editor/spellchecker/tests/spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1418629">Mozilla Bug 1418629</a> +<p id="display"></p> +<div id="content" style="display: none;"> + +</div> + +<input id="input1" spellcheck="true"> +<textarea id="textarea1"></textarea> +<div id="edit1" contenteditable=true></div> + +<script> +const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +SimpleTest.waitForExplicitFinish(); + +function getEditor(input) { + if (input instanceof HTMLInputElement || + input instanceof HTMLTextAreaElement) { + return SpecialPowers.wrap(input).editor; + } + + return SpecialPowers.wrap(window).docShell.editor; +} + +function resetEditableContent(input) { + if (input instanceof HTMLInputElement || + input instanceof HTMLTextAreaElement) { + input.value = ""; + return; + } + input.innerHTML = ""; +} + +async function test_with_single_quote(input) { + let misspeltWords = []; + + input.focus(); + resetEditableContent(input); + + synthesizeKey("d"); + synthesizeKey("o"); + synthesizeKey("e"); + synthesizeKey("s"); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + let editor = getEditor(input); + // isSpellingCheckOk is defined in spellcheck.js + ok(isSpellingCheckOk(editor, misspeltWords), "no misspelt words"); + + synthesizeKey("n"); + synthesizeKey("\'"); + is(input.value || input.textContent, "doesn\'", ""); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + // XXX This won't work since mozInlineSpellWordUtil::SplitDOM removes + // last single quote unfortunately that is during inputting. + // isSpellingCheckOk is defined in spellcheck.js + todo_is(isSpellingCheckOk(editor, misspeltWords, true), true, + "don't run spellchecker during inputting word"); + + synthesizeKey(" "); + is(input.value || input.textContent, "doesn\' ", ""); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + misspeltWords.push("doesn"); + // isSpellingCheckOk is defined in spellcheck.js + ok(isSpellingCheckOk(editor, misspeltWords), "should run spellchecker"); +} + +async function test_with_twice_characters(input, ch) { + let misspeltWords = []; + + input.focus(); + resetEditableContent(input); + + synthesizeKey("d"); + synthesizeKey("o"); + synthesizeKey("e"); + synthesizeKey("s"); + synthesizeKey("n"); + synthesizeKey(ch); + synthesizeKey(ch); + is(input.value || input.textContent, "doesn" + ch + ch, ""); + + // trigger spellchecker + synthesizeKey(" "); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + misspeltWords.push("doesn"); + let editor = getEditor(input); + // isSpellingCheckOk is defined in spellcheck.js + ok(isSpellingCheckOk(editor, misspeltWords), "should run spellchecker"); +} + +async function test_between_single_quote(input) { + let misspeltWords = []; + + input.focus(); + resetEditableContent(input); + + synthesizeKey("\'"); + synthesizeKey("t"); + synthesizeKey("e"); + synthesizeKey("s"); + synthesizeKey("t"); + synthesizeKey("\'"); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + let editor = getEditor(input); + ok(isSpellingCheckOk(editor, misspeltWords), + "don't run spellchecker between single qoute"); +} + +async function test_with_email(input) { + let misspeltWords = []; + + input.focus(); + resetEditableContent(input); + + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("@"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("."); + synthesizeKey("c"); + synthesizeKey("o"); + synthesizeKey("m"); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + let editor = getEditor(input); + ok(isSpellingCheckOk(editor, misspeltWords), + "don't run spellchecker for email address"); + + synthesizeKey(" "); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + ok(isSpellingCheckOk(editor, misspeltWords), + "no misspelt words due to email address"); +} + +async function test_with_url(input) { + let misspeltWords = []; + + input.focus(); + resetEditableContent(input); + + synthesizeKey("h"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("p"); + synthesizeKey(":"); + synthesizeKey("/"); + synthesizeKey("/"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("t"); + synthesizeKey("."); + synthesizeKey("c"); + synthesizeKey("o"); + synthesizeKey("m"); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + let editor = getEditor(input); + ok(isSpellingCheckOk(editor, misspeltWords), + "don't run spellchecker for URL"); + + synthesizeKey(" "); + + await new Promise((resolve) => { maybeOnSpellCheck(input, resolve); }); + ok(isSpellingCheckOk(editor, misspeltWords), + "no misspelt words due to URL"); +} + +SimpleTest.waitForFocus(() => { + for (let n of ["input1", "textarea1", "edit1"]) { + add_task(test_with_single_quote.bind(null, + document.getElementById(n))); + add_task(test_with_twice_characters.bind(null, + document.getElementById(n), + "\'")); + add_task(test_with_twice_characters.bind(null, + document.getElementById(n), + String.fromCharCode(0x2019))); + add_task(test_between_single_quote.bind(null, + document.getElementById(n))); + add_task(test_with_email.bind(null, document.getElementById(n))); + add_task(test_with_url.bind(null, document.getElementById(n))); + } +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1497480.html b/editor/spellchecker/tests/test_bug1497480.html new file mode 100644 index 0000000000..a7063271f4 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1497480.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1497480 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1497480</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="spellcheck.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1497480">Mozilla Bug 1497480</a> +<p id="display"></p> + +<div id="outOfTarget" contenteditable>Bug 1497480</div> +<div id="light"></div> + +<script> + +/** Test for Bug 1497480 **/ +let gMisspeltWords = []; +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +const template = document.createElement("template"); +template.innerHTML = `<div id="target" contenteditable>Test</div>`; + +let shadow = document.getElementById("light").attachShadow({mode: "closed"}); +shadow.appendChild(template.content.cloneNode(true)); + +let target = shadow.getElementById("target"); +let outOfTarget = document.getElementById("outOfTarget"); + +function getEditor() { + var win = window; + var editingSession = SpecialPowers.wrap(win).docShell.editingSession; + return editingSession.getEditorForWindow(win); +} + +// Wait for the page to be ready for testing +add_task(async function() { + await new Promise((resolve) => { + SimpleTest.waitForFocus(() => { + SimpleTest.executeSoon(resolve); + }, window); + }); + + // Wait for first full spell-checking. + synthesizeMouseAtCenter(outOfTarget, {}, window); + await new Promise((resolve) => { + maybeOnSpellCheck(outOfTarget, function() { + resolve(); + }); + }); +}); + +// Should perform spell-checking when anchor navigates away from ShadowDOM. +add_task(async function() { + synthesizeMouseAtCenter(target, {}, window); + sendString(" spellechek"); + gMisspeltWords.push("spellechek"); + synthesizeMouseAtCenter(outOfTarget, {}, window); + await new Promise((resolve) => { + maybeOnSpellCheck(target, function() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "Spell-checking should be performed when anchor navigates away from ShadowDOM"); + SimpleTest.executeSoon(resolve); + }); + }); +}); + +// Should perform spell-checking when pressing enter in contenteditable in ShadowDOM. +add_task(async function() { + synthesizeMouseAtCenter(target, {}, window); + sendString(" spellechck"); + gMisspeltWords.push("spellechck"); + synthesizeKey("KEY_Enter", {}, window); + await new Promise((resolve) => { + maybeOnSpellCheck(target, function() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "Spell-checking should be performed when pressing enter in contenteditable in ShadowDOM"); + SimpleTest.executeSoon(resolve); + }); + }); +}); + +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1602526.html b/editor/spellchecker/tests/test_bug1602526.html new file mode 100644 index 0000000000..e8c2886d9d --- /dev/null +++ b/editor/spellchecker/tests/test_bug1602526.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<head> + <title>Mozilla bug 1602526</title> + <link rel=stylesheet href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/editor/spellchecker/tests/spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1602526">Mozilla Bug 1602526</a> +<p id="display"></p> +<div id="content" style="display: none;"> + +</div> + +<div id="contenteditable" contenteditable=true>kkkkökkkk</div> + +<script> +const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +SimpleTest.waitForExplicitFinish(); + +function getEditor() { + return SpecialPowers.wrap(window).docShell.editor; +} + +SimpleTest.waitForFocus(async () => { + let contenteditable = document.getElementById("contenteditable"); + let misspeltWords = []; + misspeltWords.push("kkkk\u00f6kkkk"); + + contenteditable.focus(); + window.getSelection().collapse(contenteditable.firstChild, contenteditable.firstChild.length); + + synthesizeKey(" "); + + // Run spell checker + await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); }); + + synthesizeKey("a"); + synthesizeKey("a"); + synthesizeKey("a"); + + await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); }); + let editor = getEditor(); + // isSpellingCheckOk is defined in spellcheck.js + // eslint-disable-next-line no-undef + ok(isSpellingCheckOk(editor, misspeltWords), "correct word is seleced as misspell"); + + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1761273.html b/editor/spellchecker/tests/test_bug1761273.html new file mode 100644 index 0000000000..543e56e810 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1761273.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1761273 +--> +<head> + <title>Test for Bug 1761273</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1761273">Mozilla Bug 1761273</a> +<p id="display"></p> +</div> + +<textarea id="editor" lang="en-US">heute ist ein guter Tag - today is a good day</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +const Ci = SpecialPowers.Ci; + +let { + getDictionaryContentPref, + onSpellCheck, +} = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +/** Test for Bug 1402822 **/ +SimpleTest.waitForExplicitFinish(); +addLoadEvent(start); +async function start() { + let script = SpecialPowers.loadChromeScript(() => { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + let dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + let hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install de-DE dictionary. + let de_DE = dir.clone(); + de_DE.append("de-DE"); + hunspell.addDirectory(de_DE); + + addMessageListener("destroy", () => hunspell.removeDirectory(de_DE)); + addMessageListener("de_DE-exists", () => de_DE.exists()); + }); + is(await script.sendQuery("de_DE-exists"), true, + "true expected (de_DE directory should exist)"); + + let textarea = document.getElementById("editor"); + textarea.focus(); + + onSpellCheck(textarea, async () => { + let isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(true); + ok(isc, "Inline spell checker should exist after focus and spell check"); + let spellchecker = isc.spellChecker; + + // Setting the language to the language of the texteditor should not set the + // content preference. + await spellchecker.setCurrentDictionaries(["en-US"]); + let dictionaryContentPref = await getDictionaryContentPref(); + is(dictionaryContentPref, "", "Content pref should be empty"); + + await spellchecker.setCurrentDictionaries(["en-US", "de-DE"]); + dictionaryContentPref = await getDictionaryContentPref(); + is(dictionaryContentPref, "en-US,de-DE,", "Content pref should be en-US,de-DE,"); + + await spellchecker.setCurrentDictionaries(["de-DE"]); + dictionaryContentPref = await getDictionaryContentPref(); + is(dictionaryContentPref, "de-DE,", "Content pref should be de-DE,"); + + // Remove the fake de_DE dictionary again. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + await spellchecker.setCurrentDictionaries([]); + dictionaryContentPref = await getDictionaryContentPref(); + is(dictionaryContentPref, "", "Content pref should be empty"); + + SimpleTest.finish(); + }); +} +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1773802.html b/editor/spellchecker/tests/test_bug1773802.html new file mode 100644 index 0000000000..e31c819761 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1773802.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1773802 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1773802</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1773802">Mozilla Bug 1773802</a> +<p id="display"></p> +</div> + +<textarea id="editor">correct п©я─п╟п╡п╦п╩я▄п╫я▀п╧, incarrect п╫п╣п©я─п╬п╡п╦п╩я▄п╫я▀п╧</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +const Ci = SpecialPowers.Ci; + +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +function getMisspelledWords(editor) { + return editor.selectionController.getSelection(Ci.nsISelectionController.SELECTION_SPELLCHECK).toString(); +} + +/** Test for Bug 1773802 **/ +SimpleTest.waitForExplicitFinish(); +addLoadEvent(start); +async function start() { + let script = SpecialPowers.loadChromeScript(() => { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + let dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + let hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install ru-RU dictionary. + let ru_RU = dir.clone(); + ru_RU.append("ru-RU"); + hunspell.addDirectory(ru_RU); + + addMessageListener("destroy", () => hunspell.removeDirectory(ru_RU)); + addMessageListener("ru_RU-exists", () => ru_RU.exists()); + }); + is(await script.sendQuery("ru_RU-exists"), true, + "true expected (ru_RU directory should exist)"); + + let textarea = document.getElementById("editor"); + let editor = SpecialPowers.wrap(textarea).editor; + textarea.focus(); + + maybeOnSpellCheck(textarea, () => { + let isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(false); + ok(isc, "Inline spell checker should exist after focus and spell check"); + let spellchecker = isc.spellChecker; + + spellchecker.setCurrentDictionaries(["en-US", "ru-RU"]).then(async () => { + textarea.blur(); + textarea.focus(); + maybeOnSpellCheck(textarea, async function() { + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + is(currentDictionaries.length, 2, "expected two dictionaries"); + is(currentDictionaries[0], "en-US", "expected en-US"); + is(currentDictionaries[1], "ru-RU", "expected ru-RU"); + is(getMisspelledWords(editor), "incarrectп╫п╣п©я─п╬п╡п╦п╩я▄п╫я▀п╧", "some misspelled words expected: incarrect п╫п╣п©я─п╬п╡п╦п╩я▄п╫я▀п╧"); + + // Remove the fake ru_RU dictionary again. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + }); + }); + }); +} +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug1837268.html b/editor/spellchecker/tests/test_bug1837268.html new file mode 100644 index 0000000000..1467a328b5 --- /dev/null +++ b/editor/spellchecker/tests/test_bug1837268.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<html> +<head> + <title>Mozilla bug 1837268</title> + <link rel=stylesheet href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/editor/spellchecker/tests/spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1837268">Mozilla Bug 1837268</a> +<p id="display"></p> +<div id="content" style="display: none;"> + +</div> + +<div id="contenteditable" contenteditable=true>aabbcc</div> + +<script> +const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.importESModule( + "resource://testing-common/AsyncSpellCheckTestHelper.sys.mjs" +); + +SimpleTest.waitForExplicitFinish(); + +function getEditor() { + return SpecialPowers.wrap(window).docShell.editor; +} + +SimpleTest.waitForFocus(async () => { + let contenteditable = document.getElementById("contenteditable"); + contenteditable.addEventListener("beforeinput", (ev) => { + ev.preventDefault(); + let text = contenteditable.textContent; + const sel = window.getSelection(); + let offset = sel.anchorOffset; + switch (ev.inputType) { + case "insertText": + text = text.substring(0, offset) + ev.data + text.substring(offset); + offset += 1; + break; + case "deleteContentBackward": + text = text.substring(0, offset - 1) + text.substring(offset); + offset -= 1; + break; + default: + return; + } + if (contenteditable.firstChild) { + contenteditable.firstChild.nodeValue = text; + } else { + contenteditable.textContent = text; + } + sel.collapse(contenteditable.firstChild ?? contenteditable, offset); + }); + + let misspelledWords = []; + misspelledWords.push("aabbc"); // One c removed. + + contenteditable.focus(); + window.getSelection().collapse(contenteditable.firstChild, contenteditable.firstChild.length); + + // Run spell checker + await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); }); + + synthesizeKey("KEY_Backspace"); + synthesizeKey(" "); + + await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); }); + let editor = getEditor(); + // isSpellingCheckOk is defined in spellcheck.js + // eslint-disable-next-line no-undef + ok(isSpellingCheckOk(editor, misspelledWords), "correct word is selected as misspelled"); + + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug338427.html b/editor/spellchecker/tests/test_bug338427.html new file mode 100644 index 0000000000..dd869ffc11 --- /dev/null +++ b/editor/spellchecker/tests/test_bug338427.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=338427 +--> +<head> + <title>Test for Bug 338427</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=338427">Mozilla Bug 338427</a> +<p id="display"></p> +<div id="content"> +<textarea id="editor" lang="testing-XX" spellcheck="true"></textarea> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 338427 **/ +function init() { + var { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + var textarea = document.getElementById("editor"); + var editor = SpecialPowers.wrap(textarea).editor; + var spellchecker = editor.getInlineSpellChecker(true); + spellchecker.enableRealTimeSpell = true; + textarea.focus(); + + onSpellCheck(textarea, function() { + var list = spellchecker.spellChecker.GetDictionaryList(); + ok(!!list.length, "At least one dictionary should be present"); + + var lang = list[0]; + spellchecker.spellChecker.setCurrentDictionaries([lang]).then(() => { + onSpellCheck(textarea, function() { + try { + var dictionaries = + spellchecker.spellChecker.getCurrentDictionaries(); + } catch (e) {} + is(dictionaries.length, 1, "Expected one dictionary"); + is(dictionaries[0], lang, "Unexpected spell check dictionary"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.spellChecker.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + }); + }); + }); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(init); + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug366682.html b/editor/spellchecker/tests/test_bug366682.html new file mode 100644 index 0000000000..ac38bcf9d2 --- /dev/null +++ b/editor/spellchecker/tests/test_bug366682.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=366682 +--> +<head> + <title>Test for Bug 366682</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=366682">Mozilla Bug 366682</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 366682 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +var gMisspeltWords; + +function getEdit() { + return document.getElementById("edit"); +} + +function editDoc() { + return getEdit().contentDocument; +} + +function getEditor() { + var win = editDoc().defaultView; + var editingSession = SpecialPowers.wrap(win).docShell.editingSession; + return editingSession.getEditorForWindow(win); +} + +function runTest() { + editDoc().body.innerHTML = "<div>errror and an other errror</div>"; + gMisspeltWords = ["errror", "errror"]; + editDoc().designMode = "on"; + editDoc().defaultView.focus(); + + const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + maybeOnSpellCheck(editDoc().documentElement, evalTest); +} + +function evalTest() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings accounted for."); + SimpleTest.finish(); +} +</script> +</pre> + +<iframe id="edit" width="200" height="100" src="about:blank"></iframe> + +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug432225.html b/editor/spellchecker/tests/test_bug432225.html new file mode 100644 index 0000000000..2168429613 --- /dev/null +++ b/editor/spellchecker/tests/test_bug432225.html @@ -0,0 +1,72 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=432225 +--> +<head> + <title>Test for Bug 432225</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=432225">Mozilla Bug 432225</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 432225 **/ + +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +var gMisspeltWords = []; + +function getEdit() { + return document.getElementById("edit"); +} + +function editDoc() { + return getEdit().contentDocument; +} + +function getEditor() { + var win = editDoc().defaultView; + var editingSession = SpecialPowers.wrap(win).docShell.editingSession; + return editingSession.getEditorForWindow(win); +} + +function runTest() { + editDoc().designMode = "on"; + setTimeout(function() { addWords(100); }, 0); +} + +function addWords(aLimit) { + if (aLimit == 0) { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings accounted for."); + SimpleTest.finish(); + return; + } + getEdit().focus(); + sendString("aa OK "); + gMisspeltWords.push("aa"); + maybeOnSpellCheck(editDoc(), function() { + addWords(aLimit - 1); + }); +} +</script> +</pre> + +<iframe id="edit" width="200" height="100" src="about:blank"></iframe> + +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug484181.html b/editor/spellchecker/tests/test_bug484181.html new file mode 100644 index 0000000000..30f0b359c8 --- /dev/null +++ b/editor/spellchecker/tests/test_bug484181.html @@ -0,0 +1,73 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=484181 +--> +<head> + <title>Test for Bug 484181</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=484181">Mozilla Bug 484181</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 484181 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +var gMisspeltWords; + +function getEditor() { + var win = window; + var editingSession = SpecialPowers.wrap(win).docShell.editingSession; + return editingSession.getEditorForWindow(win); +} + +function append(str) { + var edit = document.getElementById("edit"); + var editor = getEditor(); + var sel = editor.selection; + sel.selectAllChildren(edit); + sel.collapseToEnd(); + sendString(str); +} + +function runTest() { + gMisspeltWords = ["haz", "cheezburger"]; + var edit = document.getElementById("edit"); + edit.focus(); + + const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + maybeOnSpellCheck(edit, function() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings before editing are accounted for."); + + append(" becaz I'm a lulcat!"); + maybeOnSpellCheck(edit, function() { + gMisspeltWords.push("becaz"); + gMisspeltWords.push("lulcat"); + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings after typing are accounted for."); + + SimpleTest.finish(); + }); + }); +} +</script> +</pre> + +<div><div></div><div id="edit" contenteditable="true">I can haz cheezburger</div></div> + +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug596333.html b/editor/spellchecker/tests/test_bug596333.html new file mode 100644 index 0000000000..ce6714565b --- /dev/null +++ b/editor/spellchecker/tests/test_bug596333.html @@ -0,0 +1,135 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=596333 +--> +<head> + <title>Test for Bug 596333</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="spellcheck.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596333">Mozilla Bug 596333</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 596333 **/ +const Ci = SpecialPowers.Ci; + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +var gMisspeltWords; +var onSpellCheck; + +function getEditor() { + return SpecialPowers.wrap(document.getElementById("edit")).editor; +} + +function append(str) { + var edit = document.getElementById("edit"); + edit.focus(); + edit.selectionStart = edit.selectionEnd = edit.value.length; + sendString(str); +} + +function getLoadContext() { + return SpecialPowers.wrap(window).docShell.QueryInterface(Ci.nsILoadContext); +} + +function paste(str) { + var Cc = SpecialPowers.Cc; + var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); + trans.init(getLoadContext()); + var s = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + s.data = str; + trans.setTransferData("text/plain", s); + + let beforeInputEvent = null; + let inputEvent = null; + window.addEventListener("beforeinput", aEvent => { beforeInputEvent = aEvent; }, {once: true}); + window.addEventListener("input", aEvent => { inputEvent = aEvent; }, {once: true}); + getEditor().pasteTransferable(trans); + isnot(beforeInputEvent, null, '"beforeinput" event should be fired'); + if (beforeInputEvent) { + is(beforeInputEvent.cancelable, true, '"beforeinput" event for "insertFromPaste" should be cancelable'); + is(beforeInputEvent.inputType, "insertFromPaste", 'inputType of "beforeinput" event should be "insertFromPaste"'); + is(beforeInputEvent.data, str, `data of "beforeinput" event should be "${str}"`); + is(beforeInputEvent.dataTransfer, null, 'dataTransfer of "beforeinput" event should be null on <textarea>'); + is(beforeInputEvent.getTargetRanges().length, 0, 'getTargetRanges() of "beforeinput" event should return empty array on <textarea>'); + } + is(inputEvent.type, "input", '"input" event should be fired'); + is(inputEvent.inputType, "insertFromPaste", '"inputType of "input" event should be "insertFromPaste"'); + is(inputEvent.data, str, `data of "input" event should be "${str}"`); + is(inputEvent.dataTransfer, null, 'dataTransfer of "input" event should be null on <textarea>'); + is(inputEvent.getTargetRanges().length, 0, 'getTargetRanges() of "input" event should return empty array on <textarea>'); +} + +function runOnFocus() { + var edit = document.getElementById("edit"); + + gMisspeltWords = ["haz", "cheezburger"]; + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings before editing are accounted for."); + append(" becaz I'm a lulcat!"); + onSpellCheck(edit, function() { + gMisspeltWords.push("becaz"); + gMisspeltWords.push("lulcat"); + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings after typing are accounted for."); + + // Now, type an invalid word, and instead of hitting "space" at the end, just blur + // the textarea and see if the spell check after the blur event catches it. + append(" workd"); + edit.blur(); + onSpellCheck(edit, function() { + gMisspeltWords.push("workd"); + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "All misspellings after blur are accounted for."); + + // Also, test the case when we're entering the first word in a textarea + gMisspeltWords = ["workd"]; + edit.value = ""; + append("workd "); + onSpellCheck(edit, function() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "Misspelling in the first entered word is accounted for."); + + // Make sure that pasting would also trigger spell checking for the previous word + gMisspeltWords = ["workd"]; + edit.value = ""; + append("workd"); + paste(" x"); + onSpellCheck(edit, function() { + ok(isSpellingCheckOk(getEditor(), gMisspeltWords), + "Misspelling is accounted for after pasting."); + + SimpleTest.finish(); + }); + }); + }); + }); +} + +function runTest() { + var edit = document.getElementById("edit"); + edit.focus(); + + onSpellCheck = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ).onSpellCheck; + onSpellCheck(edit, runOnFocus); +} +</script> +</pre> + +<textarea id="edit">I can haz cheezburger</textarea> + +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug636465.html b/editor/spellchecker/tests/test_bug636465.html new file mode 100644 index 0000000000..97252d92df --- /dev/null +++ b/editor/spellchecker/tests/test_bug636465.html @@ -0,0 +1,54 @@ +<!doctype html> +<title>Mozilla bug 636465</title> +<link rel=stylesheet href="/tests/SimpleTest/test.css"> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/WindowSnapshot.js"></script> +<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=636465" + target="_blank">Mozilla Bug 636465</a> +<input id="x" value="foobarbaz" spellcheck="true" style="background-color: transparent; border: transparent;"> +<script> +SimpleTest.waitForExplicitFinish(); + +function runTest() { + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + var x = document.getElementById("x"); + x.focus(); + onSpellCheck(x, function() { + x.blur(); + var spellCheckTrue = snapshotWindow(window); + x.setAttribute("spellcheck", "false"); + var spellCheckFalse = snapshotWindow(window); + x.setAttribute("spellcheck", "true"); + x.focus(); + onSpellCheck(x, function() { + x.blur(); + var spellCheckTrueAgain = snapshotWindow(window); + x.removeAttribute("spellcheck"); + var spellCheckNone = snapshotWindow(window); + var ret = compareSnapshots(spellCheckTrue, spellCheckFalse, false)[0]; + ok(ret, + "Setting the spellcheck attribute to false should work"); + if (!ret) { + ok(false, "\nspellCheckTrue: " + spellCheckTrue.toDataURL() + "\nspellCheckFalse: " + spellCheckFalse.toDataURL()); + } + ret = compareSnapshots(spellCheckTrue, spellCheckTrueAgain, true)[0]; + ok(ret, + "Setting the spellcheck attribute back to true should work"); + if (!ret) { + ok(false, "\nspellCheckTrue: " + spellCheckTrue.toDataURL() + "\nspellCheckTrueAgain: " + spellCheckTrueAgain.toDataURL()); + } + ret = compareSnapshots(spellCheckNone, spellCheckFalse, true)[0]; + ok(ret, + "Unsetting the spellcheck attribute should work"); + if (!ret) { + ok(false, "\spellCheckNone: " + spellCheckNone.toDataURL() + "\nspellCheckFalse: " + spellCheckFalse.toDataURL()); + } + SimpleTest.finish(); + }); + }); +} +addLoadEvent(runTest); +</script> diff --git a/editor/spellchecker/tests/test_bug678842.html b/editor/spellchecker/tests/test_bug678842.html new file mode 100644 index 0000000000..f5f190ab0f --- /dev/null +++ b/editor/spellchecker/tests/test_bug678842.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=678842 +--> +<head> + <title>Test for Bug 678842</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678842">Mozilla Bug 678842</a> +<p id="display"></p> +<iframe id="content"></iframe> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 678842 **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); +// load a subframe containing an editor with a defined unknown lang. At first +// load, it will set dictionary to en-US. At second load, it will return current +// dictionary. So, we can check, dictionary is correctly remembered between +// loads. + +var firstLoad = true; +var script; + +var loadListener = async function(evt) { + if (firstLoad) { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install en-GB dictionary. + let en_GB = dir.clone(); + en_GB.append("en-GB"); + hunspell.addDirectory(en_GB); + + addMessageListener("en_GB-exists", () => en_GB.exists()); + addMessageListener("destroy", () => hunspell.removeDirectory(en_GB)); + }); + is(await script.sendQuery("en_GB-exists"), true, + "true expected (en-GB directory should exist)"); + } + + var doc = evt.target.contentDocument; + var elem = doc.getElementById("textarea"); + var editor = SpecialPowers.wrap(elem).editor; + editor.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor.getInlineSpellChecker(true); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(elem, async function() { + let spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + is(currentDictionaries.length, 1, "expected one dictionary"); + let currentDictionary = currentDictionaries[0]; + + if (firstLoad) { + firstLoad = false; + + // First time around, the dictionary defaults to the locale. + is(currentDictionary, "en-US", "unexpected lang " + currentDictionary + " instead of en-US"); + + // Select en-GB. + spellchecker.setCurrentDictionaries(["en-GB"]).then(() => { + content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug678842_subframe.html?firstload=false"; + }); + } else { + is(currentDictionary, "en-GB", "unexpected lang " + currentDictionary + " instead of en-GB"); + content.removeEventListener("load", loadListener); + + // Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.setCurrentDictionaries([]).then( () => { + SimpleTest.finish(); + }); + } + }); +}; + +content.addEventListener("load", loadListener); + +content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug678842_subframe.html?firstload=true"; + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug697981.html b/editor/spellchecker/tests/test_bug697981.html new file mode 100644 index 0000000000..044f82048b --- /dev/null +++ b/editor/spellchecker/tests/test_bug697981.html @@ -0,0 +1,137 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=697981 +--> +<head> + <title>Test for Bug 697981</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697981">Mozilla Bug 697981</a> +<p id="display"></p> +</div> + +<textarea id="de-DE" lang="de-DE" onfocus="deFocus()">German heute ist ein guter Tag</textarea> +<textarea id="en-US" lang="en-US" onfocus="enFocus()">Nogoodword today is a nice day</textarea> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +function getMisspelledWords(editor) { + return editor.selectionController.getSelection(SpecialPowers.Ci.nsISelectionController.SELECTION_SPELLCHECK).toString(); +} + +var elem_de; +var editor_de; +var script; + +var { maybeOnSpellCheck, onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +/** Test for Bug 697981 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async function() { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install de-DE dictionary. + var de_DE = dir.clone(); + de_DE.append("de-DE"); + hunspell.addDirectory(de_DE); + + addMessageListener("de_DE-exists", () => de_DE.exists()); + addMessageListener("destroy", () => hunspell.removeDirectory(de_DE)); + }); + is(await script.sendQuery("de_DE-exists"), true, + "true expected (de_DE directory should exist)"); + + document.getElementById("de-DE").focus(); +}); + +function deFocus() { + elem_de = document.getElementById("de-DE"); + editor_de = SpecialPowers.wrap(elem_de).editor; + editor_de.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor_de.getInlineSpellChecker(true); + + maybeOnSpellCheck(elem_de, function() { + var spellchecker = inlineSpellChecker.spellChecker; + try { + var currentDictionaries = spellchecker.getCurrentDictionaries(); + } catch (e) {} + + // Check that the German dictionary is loaded and that the spell check has worked. + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "de-DE", "expected de-DE"); + is(getMisspelledWords(editor_de), "German", "one misspelled word expected: German"); + + // Now focus the other textarea, which requires English spelling. + document.getElementById("en-US").focus(); + }); +} + +function enFocus() { + var elem_en = document.getElementById("en-US"); + var editor_en = SpecialPowers.wrap(elem_en).editor; + editor_en.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor_en.getInlineSpellChecker(true); + + onSpellCheck(elem_en, async function() { + let spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + // Check that the English dictionary is loaded and that the spell check has worked. + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "en-US", "expected en-US"); + is(getMisspelledWords(editor_en), "Nogoodword", "one misspelled word expected: Nogoodword"); + + // So far all was boring. The important thing is whether the spell check result + // in the de-DE editor is still the same. After losing focus, no spell check + // updates should take place there. + is(getMisspelledWords(editor_de), "German", "one misspelled word expected: German"); + + // Remove the fake de_DE dictionary again. + await script.sendQuery("destroy"); + + // Focus again, so the spelling gets updated, but before we need to kill the focus handler. + elem_de.onfocus = null; + elem_de.blur(); + elem_de.focus(); + + // After removal, the de_DE editor should refresh the spelling with en-US. + maybeOnSpellCheck(elem_de, function() { + spellchecker = inlineSpellChecker.spellChecker; + try { + currentDictionaries = spellchecker.getCurrentDictionaries(); + } catch (e) {} + + // Check that the default English dictionary is loaded and that the spell check has worked. + is(currentDictionaries.length, 1, "expected one dictionary"); + is(currentDictionaries[0], "en-US", "expected en-US"); + // eslint-disable-next-line no-useless-concat + is(getMisspelledWords(editor_de), "heute" + "ist" + "ein" + "guter", + "some misspelled words expected: heute ist ein guter"); + + SimpleTest.finish(); + }); + }); +} + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_bug717433.html b/editor/spellchecker/tests/test_bug717433.html new file mode 100644 index 0000000000..2f09cb70fd --- /dev/null +++ b/editor/spellchecker/tests/test_bug717433.html @@ -0,0 +1,111 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=717433 +--> +<head> + <title>Test for Bug 717433</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717433">Mozilla Bug 717433</a> +<p id="display"></p> +<iframe id="content"></iframe> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 717433 **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); +// Load a subframe containing an editor with language "en". At first +// load, it will set the dictionary to en-GB or en-US. We set the other one. +// At second load, it will return the current dictionary. We can check that the +// dictionary is correctly remembered between loads. + +var firstLoad = true; +var expected = ""; +var script; + +var loadListener = async function(evt) { + if (firstLoad) { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install en-GB dictionary. + var en_GB = dir.clone(); + en_GB.append("en-GB"); + hunspell.addDirectory(en_GB); + + addMessageListener("en_GB-exists", () => en_GB.exists()); + addMessageListener("destroy", () => hunspell.removeDirectory(en_GB)); + }); + is(await script.sendQuery("en_GB-exists"), true, + "true expected (en-GB directory should exist)"); + } + + var doc = evt.target.contentDocument; + var elem = doc.getElementById("textarea"); + var editor = SpecialPowers.wrap(elem).editor; + editor.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor.getInlineSpellChecker(true); + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(elem, async function() { + let spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries = spellchecker.getCurrentDictionaries(); + + is(currentDictionaries.length, 1, "expected one dictionary"); + let currentDictionary = currentDictionaries[0]; + + if (firstLoad) { + firstLoad = false; + + // First time around, we get a random dictionary based on the language "en". + if (currentDictionary == "en-GB") { + expected = "en-US"; + } else if (currentDictionary == "en-US") { + expected = "en-GB"; + } else { + is(true, false, "Neither en-US nor en-GB are current"); + } + spellchecker.setCurrentDictionaries([expected]).then(() => { + content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug717433_subframe.html?firstload=false";}); + } else { + is(currentDictionary, expected, expected + " expected"); + content.removeEventListener("load", loadListener); + + // Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests. + await script.sendQuery("destroy"); + + // This will clear the content preferences and reset "spellchecker.dictionary". + spellchecker.setCurrentDictionaries([]).then(() => { + SimpleTest.finish(); + }); + } + }); +}; + +content.addEventListener("load", loadListener); + +content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/bug717433_subframe.html?firstload=true"; + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_multiple_content_languages.html b/editor/spellchecker/tests/test_multiple_content_languages.html new file mode 100644 index 0000000000..c3357dec91 --- /dev/null +++ b/editor/spellchecker/tests/test_multiple_content_languages.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for multiple Content-Language values</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<p id="display"></p> +<iframe id="content"></iframe> + +<pre id="test"> +<script class="testbody"> + +/** Test for multiple Content-Language values **/ +/** Visit the elements defined above and check the dictionaries we got **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); + +var tests = [ + // text area, value of spellchecker.dictionary, result. + // Result: Document language. + [ "none", "", ["en-US", "en-GB"] ], + + // Result: Element language. + [ "en-GB", "", ["en-GB"] ], + // Result: Random en-* or en-US (if application locale is en-US). + [ "en-ZA-not-avail", "", ["*"] ], + [ "en", "", ["*"] ], + // Result: Locale. + [ "ko-not-avail", "", ["en-US"] ], + + // Result: Document language, plus preference value in all cases. + [ "none", "en-AU", ["en-US", "en-GB", "en-AU"] ], + [ "en-ZA-not-avail", "en-AU", ["en-AU"] ], + [ "ko-not-avail", "en-AU", ["en-AU"] ], + + // Result: Document language, plus first matching preference language. + [ "none", "en-AU,en-US", ["en-US", "en-GB", "en-AU"] ], + // Result: First matching preference language. + [ "en-ZA-not-avail", "en-AU,en-US", ["en-AU"] ], + // Result: Fall back to preference languages. + [ "ko-not-avail", "en-AU,en-US", ["en-AU", "en-US"] ], + + // Result: Random en-*. + [ "en-ZA-not-avail", "de-DE", ["*"] ], + // Result: Preference value. + [ "ko-not-avail", "de-DE", ["de-DE"] ], + ]; + +var loadCount = 0; +var retrying = false; +var script; + +var loadListener = async function(evt) { + if (loadCount == 0) { + script = SpecialPowers.loadChromeScript(function() { + /* eslint-env mozilla/chrome-script */ + // eslint-disable-next-line mozilla/use-services + var dir = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("CurWorkD", Ci.nsIFile); + dir.append("tests"); + dir.append("editor"); + dir.append("spellchecker"); + dir.append("tests"); + + var hunspell = Cc["@mozilla.org/spellchecker/engine;1"] + .getService(Ci.mozISpellCheckingEngine); + + // Install en-GB, en-AU and de-DE dictionaries. + var en_GB = dir.clone(); + var en_AU = dir.clone(); + var de_DE = dir.clone(); + en_GB.append("en-GB"); + en_AU.append("en-AU"); + de_DE.append("de-DE"); + hunspell.addDirectory(en_GB); + hunspell.addDirectory(en_AU); + hunspell.addDirectory(de_DE); + + addMessageListener("check-existence", + () => [en_GB.exists(), en_AU.exists(), + de_DE.exists()]); + addMessageListener("destroy", () => { + hunspell.removeDirectory(en_GB); + hunspell.removeDirectory(en_AU); + hunspell.removeDirectory(de_DE); + }); + }); + var existenceChecks = await script.sendQuery("check-existence"); + is(existenceChecks[0], true, "true expected (en-GB directory should exist)"); + is(existenceChecks[1], true, "true expected (en-AU directory should exist)"); + is(existenceChecks[2], true, "true expected (de-DE directory should exist)"); + } + + SpecialPowers.pushPrefEnv({set: [["spellchecker.dictionary", tests[loadCount][1]]]}, + function() { continueTest(evt); }); +}; + +function continueTest(evt) { + var doc = evt.target.contentDocument; + var elem = doc.getElementById(tests[loadCount][0]); + var editor = SpecialPowers.wrap(elem).editor; + editor.setSpellcheckUserOverride(true); + var inlineSpellChecker = editor.getInlineSpellChecker(true); + const is_en_US = SpecialPowers.Services.locale.appLocaleAsBCP47 == "en-US"; + + const { onSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + onSpellCheck(elem, async function() { + var spellchecker = inlineSpellChecker.spellChecker; + let currentDictionaries; + try { + currentDictionaries = spellchecker.getCurrentDictionaries(); + } catch (e) {} + + if (!currentDictionaries && !retrying) { + // It's possible for an asynchronous font-list update to cause a reflow + // that disrupts the async spell-check and results in not getting a + // current dictionary here; if that happens, we retry the same testcase + // by reloading the iframe without bumping loadCount. + info(`No current dictionary: retrying testcase ${loadCount}`); + retrying = true; + } else { + let expectedDictionaries = tests[loadCount][2]; + let dictionaryArray = Array.from(currentDictionaries); + is( + dictionaryArray.length, + expectedDictionaries.length, + "Expected matching dictionary count" + ); + if (expectedDictionaries[0] != "*") { + ok( + dictionaryArray.every(dict => expectedDictionaries.includes(dict)), + "active dictionaries should match expectation" + ); + } else if (is_en_US && tests[loadCount][0].startsWith("en")) { + // Current application locale is en-US and content lang is en or + // en-unknown, so we should use en-US dictionary as default. + is( + dictionaryArray[0], + "en-US", + "expected en-US that is application locale" + ); + } else { + let dict = dictionaryArray[0]; + var gotEn = (dict == "en-GB" || dict == "en-AU" || dict == "en-US"); + is(gotEn, true, "expected en-AU or en-GB or en-US"); + } + + loadCount++; + retrying = false; + } + + if (loadCount < tests.length) { + // Load the iframe again. + content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/multiple_content_languages_subframe.html?firstload=false"; + } else { + // Remove the fake dictionaries again, since it's otherwise picked up by later tests. + await script.sendQuery("destroy"); + + SimpleTest.finish(); + } + }); +} + +content.addEventListener("load", loadListener); + +content.src = "http://mochi.test:8888/tests/editor/spellchecker/tests/multiple_content_languages_subframe.html?firstload=true"; + +</script> +</pre> +</body> +</html> diff --git a/editor/spellchecker/tests/test_nsIEditorSpellCheck_ReplaceWord.html b/editor/spellchecker/tests/test_nsIEditorSpellCheck_ReplaceWord.html new file mode 100644 index 0000000000..6088b97e3e --- /dev/null +++ b/editor/spellchecker/tests/test_nsIEditorSpellCheck_ReplaceWord.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for nsIEditorSpellCheck.ReplaceWord()</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> +</head> +<body> +<div contenteditable spellcheck="true" lang="en-US"></div> +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async () => { + const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + const editor = document.querySelector("div[contenteditable]"); + async function replaceWord(aMisspelledWord, aCorrectWord, aReplaceAll) { + const editorObj = SpecialPowers.wrap(window).docShell.editingSession.getEditorForWindow(window); + const inlineSpellChecker = editorObj.getInlineSpellChecker(true); + await new Promise(resolve => maybeOnSpellCheck(editor, resolve)); + const editorSpellCheck = inlineSpellChecker.spellChecker; + editorObj.beginTransaction(); + try { + editorSpellCheck.ReplaceWord(aMisspelledWord, aCorrectWord, aReplaceAll); + } catch (e) { + ok(false, `Unexpected exception: ${e.message}`); + } + editorObj.endTransaction(); + editorSpellCheck.GetNextMisspelledWord(); + } + + async function testReplaceAllMisspelledWords(aCorrectWord) { + editor.innerHTML = "<p>def abc def<br>abc def abc</p><p>abc def abc<br>def abc def</p>"; + editor.focus(); + editor.getBoundingClientRect(); + await replaceWord("abc", aCorrectWord, true); + is( + editor.innerHTML, + `<p>def ${aCorrectWord} def<br>${aCorrectWord} def ${aCorrectWord}</p><p>${aCorrectWord} def ${aCorrectWord}<br>def ${aCorrectWord} def</p>`, + `nsIEditorSpellCheck.ReplaceWord(..., true) should replace all misspelled words with ${ + (() => { + if (aCorrectWord.length > "abc".length) { + return "longer"; + } + return aCorrectWord.length < "abc".length ? "shorter" : "same length" + })() + } correct word` + ); + editor.blur(); + editor.getBoundingClientRect(); + } + await testReplaceAllMisspelledWords("ABC"); + await testReplaceAllMisspelledWords("ABC!"); + await testReplaceAllMisspelledWords("AB"); + + // TODO: Add tests for not all replacing cases. + + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_spellcheck_after_edit.html b/editor/spellchecker/tests/test_spellcheck_after_edit.html new file mode 100644 index 0000000000..e4fa76d2e4 --- /dev/null +++ b/editor/spellchecker/tests/test_spellcheck_after_edit.html @@ -0,0 +1,198 @@ +<!doctype html> +<html> +<head> + <meta charset="utf-8"> + <title>Spellcheck result after edit</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<script> +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +function waitForTick() { + return new Promise(resolve => + SimpleTest.executeSoon( + () => requestAnimationFrame( + () => requestAnimationFrame(resolve) + ) + ) + ); +} + +async function waitForOnSpellCheck( + aSpellCheckSelection, + aEditingHost, + aWaitForNumberOfMisspelledWords, + aWhen +) { + info(`Waiting for onSpellCheck (${aWhen})...`); + for (let retry = 0; retry < 100; retry++) { + await waitForTick(); + await new Promise(resolve => maybeOnSpellCheck(aEditingHost, resolve)); + if (aWaitForNumberOfMisspelledWords === 0) { + if (aSpellCheckSelection.rangeCount === 0) { + break; + } + } else if (aSpellCheckSelection.rangeCount >= aWaitForNumberOfMisspelledWords) { + break; + } + } +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async () => { + /** + * test object should have: + * init function + * @param normalSel The normal selection for the editing host + * @param editingHost The editing host of the editor + * @return Number of misspelled word in the editor + * + * run function + * @param editingHost The editing host of the editor + * @return Expected number of misspelled word in the editor + * + * check function + * @param spellCheckSel The spellcheck selection for the editing host + * @param editingHost The editing host of the editor + */ + for (const test of [ + { + init: (normalSel, editingHost) => { + info("Staring to test spellcheck of misspelled word after joining paragraphs"); + // eslint-disable-next-line no-unsanitized/property + editingHost.innerHTML = "<p>It is</p><p>what I want</p>"; + normalSel.collapse(editingHost.querySelector("p + p").firstChild, 0); + return 0; + }, + run: (editingHost) => { + document.execCommand("delete"); + return 0; + }, + check: (spellCheckSel, editingHost) => { + is( + spellCheckSel.rangeCount, + 0, + "The joined misspelled word shouldn't be marked as misspelled word because caret is in the word" + ); + }, + }, + { + init: (normalSel, editingHost) => { + info("Staring to test spellcheck of correct word after joining paragraphs"); + // eslint-disable-next-line no-unsanitized/property + editingHost.innerHTML = "<p>It's beco</p><p>ming nicer</p>"; + normalSel.collapse(editingHost.querySelector("p + p").firstChild, 0); + return 2; + }, + run: (editingHost) => { + document.execCommand("delete"); + return 0; + }, + check: (spellCheckSel, editingHost) => { + is( + spellCheckSel.rangeCount, + 0, + "There shouldn't be misspelled word after joining separated word anyway" + ); + }, + }, + { + init: (normalSel, editingHost) => { + info("Staring to test spellcheck of correct words after splitting a paragraph"); + // eslint-disable-next-line no-unsanitized/property + editingHost.innerHTML = "<p>It iswhat I want</p>"; + normalSel.collapse(editingHost.querySelector("p").firstChild, "It is".length); + return 1; + }, + run: (editingHost) => { + document.execCommand("insertParagraph"); + return 0; + }, + check: (spellCheckSel, editingHost) => { + is( + spellCheckSel.rangeCount, + 0, + "No word should be marked as misspelled after split" + ); + }, + }, + { + init: (normalSel, editingHost) => { + info("Staring to test spellcheck of misspelled words after splitting a paragraph"); + // eslint-disable-next-line no-unsanitized/property + editingHost.innerHTML = "<p>It's becoming nicer</p>"; + normalSel.collapse(editingHost.querySelector("p").firstChild, "It's beco".length); + return 0; + }, + run: (editingHost) => { + document.execCommand("insertParagraph"); + return 1; + }, + check: (spellCheckSel, editingHost) => { + is( + spellCheckSel.rangeCount, + 1, + "The split word in the first paragraph should be marked as misspelled, but the second paragraph's should be so because of caret is in it" + ); + if (!spellCheckSel.rangeCount) { + return; + } + is( + SpecialPowers.unwrap(spellCheckSel.getRangeAt(0).startContainer), + editingHost.querySelector("p").firstChild, + "First misspelled word should start in the first child of the first <p>" + ); + is( + SpecialPowers.unwrap(spellCheckSel.getRangeAt(0).endContainer), + editingHost.querySelector("p").firstChild, + "First misspelled word should end in the first child of the first <p>" + ); + is( + spellCheckSel.getRangeAt(0).startOffset, + "It's ".length, + "First misspelled word should start after 'It '" + ); + is( + spellCheckSel.getRangeAt(0).endOffset, + "It's beco".length, + "First misspelled word should end by after 'bec'" + ); + }, + }, + ]) { + const editingHost = document.createElement("div"); + editingHost.setAttribute("contenteditable", ""); + editingHost.setAttribute("spellcheck", "true"); + document.body.appendChild(editingHost); + editingHost.focus(); + const editor = + SpecialPowers.wrap(window).docShell.editingSession.getEditorForWindow(window); + const nsISelectionController = SpecialPowers.Ci.nsISelectionController; + const normalSel = editor.selectionController.getSelection( + nsISelectionController.SELECTION_NORMAL + ); + const spellCheckSel = editor.selectionController.getSelection( + nsISelectionController.SELECTION_SPELLCHECK + ); + const initialMisspelledWords = test.init(normalSel, editingHost); + await waitForOnSpellCheck( + spellCheckSel, editingHost, initialMisspelledWords, "before edit" + ); + await waitForTick(); + const expectedMisspelledWords = test.run(editingHost); + await waitForOnSpellCheck( + spellCheckSel, editingHost, expectedMisspelledWords, "after edit" + ); + test.check(spellCheckSel, editingHost); + editingHost.remove(); + await waitForTick(); + } + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_spellcheck_after_pressing_navigation_key.html b/editor/spellchecker/tests/test_spellcheck_after_pressing_navigation_key.html new file mode 100644 index 0000000000..2f0c3bed7d --- /dev/null +++ b/editor/spellchecker/tests/test_spellcheck_after_pressing_navigation_key.html @@ -0,0 +1,77 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1729653 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1729653</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<textarea rows="20" cols="50">That undfgdfg seems OK.</textarea> +<script> +let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" +); + +function waitForTick() { + return new Promise(resolve => SimpleTest.executeSoon(resolve)); +} + +function waitForOnSpellCheck(aTextArea) { + info("Waiting for onSpellCheck..."); + return new Promise(resolve => maybeOnSpellCheck(aTextArea, resolve)); +} + +/** Test for Bug 1729653 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async () => { + const textarea = document.querySelector("textarea"); + textarea.focus(); + textarea.selectionStart = textarea.selectionEnd = "That undfgdfg".length; + const editor = SpecialPowers.wrap(textarea).editor; + const nsISelectionController = SpecialPowers.Ci.nsISelectionController; + const selection = editor.selectionController.getSelection(nsISelectionController.SELECTION_SPELLCHECK); + const spellChecker = SpecialPowers.Cu.createSpellChecker(); + spellChecker.InitSpellChecker(editor, false); + info("Waiting for current dictionary update..."); + await new Promise(resolve => spellChecker.UpdateCurrentDictionary(resolve)); + if (selection.rangeCount === 0) { + await waitForOnSpellCheck(textarea); + } + if (selection.rangeCount == 1) { + is( + selection.getRangeAt(0).toString(), + "undfgdfg", + "\"undfgdfg\" should be marked as misspelled word at start" + ); + } else { + is(selection.rangeCount, 1, "We should have a misspelled word at start"); + } + synthesizeKey(" "); + synthesizeKey("KEY_Backspace"); + textarea.addEventListener("keydown", event => { + event.stopImmediatePropagation(); // This shouldn't block spellchecker to handle it. + }, {once: true}); + synthesizeKey("KEY_End"); + await waitForTick(); + if (selection.rangeCount === 0) { + await waitForOnSpellCheck(textarea); + } + if (selection.rangeCount == 1) { + is( + selection.getRangeAt(0).toString(), + "undfgdfg", + "\"undfgdfg\" should be marked as misspelled word at end" + ); + } else { + is(selection.rangeCount, 1, "We should have a misspelled word at end"); + } + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/editor/spellchecker/tests/test_spellcheck_selection.html b/editor/spellchecker/tests/test_spellcheck_selection.html new file mode 100644 index 0000000000..0d0887a8f3 --- /dev/null +++ b/editor/spellchecker/tests/test_spellcheck_selection.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Bug 1779846: Test enableSelectionChecking=true on nsIEditorSpellCheck.InitSpellChecker</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css" /> + +<div contenteditable lang="en-US">missspelled</div> + +<script> +add_task(async function() { + await new Promise(resolve => SimpleTest.waitForFocus(resolve)); + + let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + + let editingHost = document.querySelector("div[contenteditable][lang=en-US]"); + editingHost.focus(); + + await new Promise(resolve => maybeOnSpellCheck(editingHost, resolve)); + + let editingSession = SpecialPowers.wrap(window).docShell.editingSession; + let editor = editingSession.getEditorForWindow(window); + let spellchecker = SpecialPowers.Cu.createSpellChecker(); + spellchecker.setFilterType(spellchecker.FILTERTYPE_NORMAL); + + /* Select "missspelled" in the <div>. */ + window.getSelection().selectAllChildren(editingHost); + + /* Pass true to InitSpellChecker to spellcheck the current selection of the editor.*/ + await new Promise(resolve => spellchecker.InitSpellChecker(editor, true, resolve)); + + /* InitSpellChecker with enableSelectionChecking=true shouldn't throw any errors. */ + ok(spellchecker.canSpellCheck()); +}); +</script> diff --git a/editor/spellchecker/tests/test_suggest.html b/editor/spellchecker/tests/test_suggest.html new file mode 100644 index 0000000000..2bdee93c1d --- /dev/null +++ b/editor/spellchecker/tests/test_suggest.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for nsIEditorSpellChecfker.sugget</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<p id="display"></p> + +<div contenteditable id="en-US" lang="en-US">missspelled</div> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +add_task(async function() { + await new Promise(resolve => SimpleTest.waitForFocus(resolve)); + + let { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm" + ); + + let element = document.getElementById("en-US"); + element.focus(); + + await new Promise(resolve => maybeOnSpellCheck(element, resolve)); + + let editingSession = SpecialPowers.wrap(window).docShell.editingSession; + let editor = editingSession.getEditorForWindow(window); + let spellchecker = SpecialPowers.Cu.createSpellChecker(); + spellchecker.setFilterType(spellchecker.FILTERTYPE_NORMAL); + await new Promise(resolve => spellchecker.InitSpellChecker(editor, false, resolve)); + + let suggestions = await spellchecker.suggest("misspelled", 5); + is(suggestions.length, 0, "\"misspelled\" is correct word"); + + suggestions = await spellchecker.suggest("missspelled", 5); + is(suggestions.length, 5, "\"missspelled\" isn't correct word"); +}); +</script> +</pre> +</body> +</html> |