diff options
Diffstat (limited to '')
-rw-r--r-- | widget/tests/browser/browser_test_ContentCache.js | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/widget/tests/browser/browser_test_ContentCache.js b/widget/tests/browser/browser_test_ContentCache.js new file mode 100644 index 0000000000..7b64e00f13 --- /dev/null +++ b/widget/tests/browser/browser_test_ContentCache.js @@ -0,0 +1,296 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function () { + const TIP = Cc["@mozilla.org/text-input-processor;1"].createInstance( + Ci.nsITextInputProcessor + ); + let notifications = []; + const observer = (aTIP, aNotification) => { + switch (aNotification.type) { + case "request-to-commit": + aTIP.commitComposition(); + break; + case "request-to-cancel": + aTIP.cancelComposition(); + break; + case "notify-end-input-transaction": + case "notify-focus": + case "notify-blur": + case "notify-text-change": + case "notify-selection-change": + notifications.push(aNotification); + break; + } + return true; + }; + + function checkNotifications(aExpectedNotifications, aDescription) { + for (const expectedNotification of aExpectedNotifications) { + const notification = notifications.find( + element => element.type == expectedNotification.type + ); + if (expectedNotification.expected) { + isnot( + notification, + undefined, + `"${expectedNotification.type}" should be notified ${aDescription}` + ); + } else { + is( + notification, + undefined, + `"${expectedNotification.type}" should not be notified ${aDescription}` + ); + } + } + } + + ok( + TIP.beginInputTransaction(window, observer), + "nsITextInputProcessor.beingInputTransaction should return true" + ); + ok( + TIP.beginInputTransactionForTests(window, observer), + "nsITextInputProcessor.beginInputTransactionForTests should return true" + ); + + await BrowserTestUtils.withNewTab( + "https://example.com/browser/toolkit/content/tests/browser/file_empty.html", + async function (browser) { + ok(browser.isRemoteBrowser, "This test passes only in e10s mode"); + + // IMEContentObserver flushes pending IME notifications at next vsync + // after something happens. Therefore, after doing something in content + // process, we need to guarantee that IMEContentObserver has a change to + // send IME notifications to the main process with calling this function. + function waitForSendingIMENotificationsInContent() { + return SpecialPowers.spawn(browser, [], async () => { + await new Promise(resolve => + content.requestAnimationFrame(() => + content.requestAnimationFrame(resolve) + ) + ); + }); + } + + /** + * Test when empty editor gets focus + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "<div contenteditable><br></div>"; + const editor = content.document.querySelector("div[contenteditable]"); + editor.focus(); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: true }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: false }, + { type: "notify-selection-change", expected: false }, + ], + "after empty editor gets focus" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after empty editor gets focus" + ); + if (text?.succeeded) { + is( + text.text.replace(/[\r\n]/g, ""), + "", + "text should be only line breaks after empty editor gets focus" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after empty editor gets focus" + ); + if (selection?.succeeded) { + ok( + !selection.notFound, + "query selected text should find a selection range after empty editor gets focus" + ); + if (!selection.notFound) { + is( + selection.text, + "", + "selection should be collapsed after empty editor gets focus" + ); + } + } + })(); + + /** + * Test when there is non-collapsed selection + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + const editor = content.document.querySelector("div[contenteditable]"); + editor.innerHTML = "<p>abc</p><p>def</p>"; + content + .getSelection() + .setBaseAndExtent( + editor.querySelector("p").firstChild, + 2, + editor.querySelector("p + p").firstChild, + 1 + ); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: true }, + { type: "notify-selection-change", expected: true }, + ], + "after modifying focused editor" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after modifying focused editor" + ); + if (text?.succeeded) { + is( + text.text.trim().replace(/\r\n/g, "\n").replace(/\n\n+/g, "\n"), + "abc\ndef", + "text should include the both paragraph's text after modifying focused editor" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after modifying focused editor" + ); + if (selection?.succeeded) { + ok( + !selection.notFound, + "query selected text should find a selection range after modifying focused editor" + ); + if (!selection.notFound) { + is( + selection.text + .trim() + .replace(/\r\n/g, "\n") + .replace(/\n\n+/g, "\n"), + "c\nd", + "selection should have the selected characters in the both paragraphs after modifying focused editor" + ); + } + } + })(); + + /** + * Test when there is no selection ranges + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.getSelection().removeAllRanges(); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: false }, + { type: "notify-selection-change", expected: true }, + ], + "after removing all selection ranges from the focused editor" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after removing all selection ranges from the focused editor" + ); + if (text?.succeeded) { + is( + text.text.trim().replace(/\r\n/g, "\n").replace(/\n\n+/g, "\n"), + "abc\ndef", + "text should include the both paragraph's text after removing all selection ranges from the focused editor" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after removing all selection ranges from the focused editor" + ); + if (selection?.succeeded) { + ok( + selection.notFound, + "query selected text should find no selection range after removing all selection ranges from the focused editor" + ); + } + })(); + + /** + * Test when no editable element has focus. + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "abcdef"; + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: true }, + ], + "removing editor should make ContentCacheInParent not have any data" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + !text?.succeeded, + "query text content should fail because no editable element has focus" + ); + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + !selection?.succeeded, + "query selected text should fail because no editable element has focus" + ); + const caret = EventUtils.synthesizeQueryCaretRect(0); + ok( + !caret?.succeeded, + "query caret rect should fail because no editable element has focus" + ); + const textRect = EventUtils.synthesizeQueryTextRect(0, 5, false); + ok( + !textRect?.succeeded, + "query text rect should fail because no editable element has focus" + ); + const textRectArray = EventUtils.synthesizeQueryTextRectArray(0, 5); + ok( + !textRectArray?.succeeded, + "query text rect array should fail because no editable element has focus" + ); + const editorRect = EventUtils.synthesizeQueryEditorRect(); + todo( + !editorRect?.succeeded, + "query editor rect should fail because no editable element has focus" + ); + })(); + } + ); +}); |