diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/content/tests/browser/browser_f7_caret_browsing.js | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/browser_f7_caret_browsing.js b/toolkit/content/tests/browser/browser_f7_caret_browsing.js new file mode 100644 index 0000000000..be6ae7d1f7 --- /dev/null +++ b/toolkit/content/tests/browser/browser_f7_caret_browsing.js @@ -0,0 +1,367 @@ +var gListener = null; +const kURL = + "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>"; + +const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled"; +const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret"; +const kPrefCaretBrowsingOn = "accessibility.browsewithcaret"; + +var oldPrefs = {}; +for (let pref of [ + kPrefShortcutEnabled, + kPrefWarnOnEnable, + kPrefCaretBrowsingOn, +]) { + oldPrefs[pref] = Services.prefs.getBoolPref(pref); +} + +Services.prefs.setBoolPref(kPrefShortcutEnabled, true); +Services.prefs.setBoolPref(kPrefWarnOnEnable, true); +Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false); + +registerCleanupFunction(function () { + for (let pref of [ + kPrefShortcutEnabled, + kPrefWarnOnEnable, + kPrefCaretBrowsingOn, + ]) { + Services.prefs.setBoolPref(pref, oldPrefs[pref]); + } +}); + +// NB: not using BrowserTestUtils.promiseAlertDialog here because there's no way to +// undo waiting for a dialog. If we don't want the window to be opened, and +// wait for it to verify that it indeed does not open, we need to be able to +// then "stop" waiting so that when we next *do* want it to open, our "old" +// listener doesn't fire and do things we don't want (like close the window...). +let gCaretPromptOpeningObserver; +function promiseCaretPromptOpened() { + return new Promise(resolve => { + function observer(subject, topic, data) { + info("Dialog opened."); + resolve(subject); + gCaretPromptOpeningObserver(); + } + Services.obs.addObserver(observer, "common-dialog-loaded"); + gCaretPromptOpeningObserver = () => { + Services.obs.removeObserver(observer, "common-dialog-loaded"); + gCaretPromptOpeningObserver = () => {}; + }; + }); +} + +function hitF7() { + SimpleTest.executeSoon(() => EventUtils.synthesizeKey("KEY_F7")); +} + +async function toggleCaretNoDialog(expected) { + let openedDialog = false; + promiseCaretPromptOpened().then(function (win) { + openedDialog = true; + win.close(); // This will eventually return focus here and allow the test to continue... + }); + // Cause the dialog to appear synchronously when focused element is in chrome, + // otherwise, i.e., when focused element is in remote content, it appears + // asynchronously. + const focusedElementInChrome = Services.focus.focusedElement; + const isAsync = focusedElementInChrome?.isRemoteBrowser; + const waitForF7KeyHandled = new Promise(resolve => { + let eventCount = 0; + const expectedEventCount = isAsync ? 2 : 1; + let listener = async event => { + if (event.key == "F7") { + info("F7 keypress is fired"); + if (++eventCount == expectedEventCount) { + window.removeEventListener("keypress", listener, { + capture: true, + mozSystemGroup: true, + }); + // Wait for the event handled in chrome. + await TestUtils.waitForTick(); + resolve(); + return; + } + info( + "Waiting for next F7 keypress which is a reply event from the remote content" + ); + } + }; + info( + `Synthesizing "F7" key press and wait ${expectedEventCount} keypress events...` + ); + window.addEventListener("keypress", listener, { + capture: true, + mozSystemGroup: true, + }); + }); + hitF7(); + await waitForF7KeyHandled; + + let expectedStr = expected ? "on." : "off."; + ok( + !openedDialog, + "Shouldn't open a dialog to turn caret browsing " + expectedStr + ); + // Need to clean up if the dialog wasn't opened, so the observer doesn't get + // re-triggered later on causing "issues". + if (!openedDialog) { + gCaretPromptOpeningObserver(); + } + let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn); + is(prefVal, expected, "Caret browsing should now be " + expectedStr); +} + +function waitForFocusOnInput(browser) { + return SpecialPowers.spawn(browser, [], async function () { + let textEl = content.document.getElementById("in"); + return ContentTaskUtils.waitForCondition(() => { + return content.document.activeElement == textEl; + }, "Input should get focused."); + }); +} + +function focusInput(browser) { + return SpecialPowers.spawn(browser, [], async function () { + let textEl = content.document.getElementById("in"); + textEl.focus(); + }); +} + +add_task(async function checkTogglingCaretBrowsing() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kURL); + await focusInput(tab.linkedBrowser); + + let promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + let prompt = await promiseGotKey; + let doc = prompt.document; + let dialog = doc.getElementById("commonDialog"); + is(dialog.defaultButton, "cancel", "No button should be the default"); + ok( + !doc.getElementById("checkbox").checked, + "Checkbox shouldn't be checked by default." + ); + let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + + dialog.cancelDialog(); + await promiseDialogUnloaded; + info("Dialog unloaded"); + await waitForFocusOnInput(tab.linkedBrowser); + ok( + !Services.prefs.getBoolPref(kPrefCaretBrowsingOn), + "Caret browsing should still be off after cancelling the dialog." + ); + + promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + prompt = await promiseGotKey; + + doc = prompt.document; + dialog = doc.getElementById("commonDialog"); + is(dialog.defaultButton, "cancel", "No button should be the default"); + ok( + !doc.getElementById("checkbox").checked, + "Checkbox shouldn't be checked by default." + ); + promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + + dialog.acceptDialog(); + await promiseDialogUnloaded; + info("Dialog unloaded"); + await waitForFocusOnInput(tab.linkedBrowser); + ok( + Services.prefs.getBoolPref(kPrefCaretBrowsingOn), + "Caret browsing should be on after accepting the dialog." + ); + + await toggleCaretNoDialog(false); + + promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + prompt = await promiseGotKey; + doc = prompt.document; + dialog = doc.getElementById("commonDialog"); + + is(dialog.defaultButton, "cancel", "No button should be the default"); + ok( + !doc.getElementById("checkbox").checked, + "Checkbox shouldn't be checked by default." + ); + + promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + dialog.cancelDialog(); + await promiseDialogUnloaded; + info("Dialog unloaded"); + await waitForFocusOnInput(tab.linkedBrowser); + + ok( + !Services.prefs.getBoolPref(kPrefCaretBrowsingOn), + "Caret browsing should still be off after cancelling the dialog." + ); + + Services.prefs.setBoolPref(kPrefShortcutEnabled, true); + Services.prefs.setBoolPref(kPrefWarnOnEnable, true); + Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function toggleCheckboxNoCaretBrowsing() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kURL); + await focusInput(tab.linkedBrowser); + + let promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + let prompt = await promiseGotKey; + let doc = prompt.document; + let dialog = doc.getElementById("commonDialog"); + is(dialog.defaultButton, "cancel", "No button should be the default"); + let checkbox = doc.getElementById("checkbox"); + ok(!checkbox.checked, "Checkbox shouldn't be checked by default."); + + // Check the box: + checkbox.click(); + + let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + + // Say no: + dialog.getButton("cancel").click(); + + await promiseDialogUnloaded; + info("Dialog unloaded"); + await waitForFocusOnInput(tab.linkedBrowser); + ok( + !Services.prefs.getBoolPref(kPrefCaretBrowsingOn), + "Caret browsing should still be off." + ); + ok( + !Services.prefs.getBoolPref(kPrefShortcutEnabled), + "Shortcut should now be disabled." + ); + + await toggleCaretNoDialog(false); + ok( + !Services.prefs.getBoolPref(kPrefShortcutEnabled), + "Shortcut should still be disabled." + ); + + Services.prefs.setBoolPref(kPrefShortcutEnabled, true); + Services.prefs.setBoolPref(kPrefWarnOnEnable, true); + Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function toggleCheckboxWantCaretBrowsing() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kURL); + await focusInput(tab.linkedBrowser); + + let promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + let prompt = await promiseGotKey; + let doc = prompt.document; + let dialog = doc.getElementById("commonDialog"); + is(dialog.defaultButton, "cancel", "No button should be the default"); + let checkbox = doc.getElementById("checkbox"); + ok(!checkbox.checked, "Checkbox shouldn't be checked by default."); + + // Check the box: + checkbox.click(); + + let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + + // Say yes: + dialog.acceptDialog(); + await promiseDialogUnloaded; + info("Dialog unloaded"); + await waitForFocusOnInput(tab.linkedBrowser); + ok( + Services.prefs.getBoolPref(kPrefCaretBrowsingOn), + "Caret browsing should now be on." + ); + ok( + Services.prefs.getBoolPref(kPrefShortcutEnabled), + "Shortcut should still be enabled." + ); + ok( + !Services.prefs.getBoolPref(kPrefWarnOnEnable), + "Should no longer warn when enabling." + ); + + await toggleCaretNoDialog(false); + await toggleCaretNoDialog(true); + await toggleCaretNoDialog(false); + + Services.prefs.setBoolPref(kPrefShortcutEnabled, true); + Services.prefs.setBoolPref(kPrefWarnOnEnable, true); + Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false); + + BrowserTestUtils.removeTab(tab); +}); + +// Test for bug 1743878: Many repeated modal caret-browsing dialogs, if you +// accidentally hold down F7 for a few seconds +add_task(async function testF7SpamDoesNotOpenDialogs() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + registerCleanupFunction(() => BrowserTestUtils.removeTab(tab)); + + let promiseGotKey = promiseCaretPromptOpened(); + hitF7(); + let prompt = await promiseGotKey; + let doc = prompt.document; + let dialog = doc.getElementById("commonDialog"); + + let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload"); + + // Listen for an additional prompt to open, which should not happen. + let promiseDialogOrTimeout = () => + Promise.race([ + promiseCaretPromptOpened(), + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + new Promise(resolve => setTimeout(resolve, 100)), + ]); + + let openedPromise = promiseDialogOrTimeout(); + + // Hit F7 two more times: once to test that _awaitingToggleCaretBrowsingPrompt + // is applied, and again to test that its value isn't somehow reset by + // pressing F7 while the dialog is open. + for (let i = 0; i < 2; i++) { + await new Promise(resolve => + SimpleTest.executeSoon(() => { + hitF7(); + resolve(); + }) + ); + } + + // Say no: + dialog.cancelDialog(); + await promiseDialogUnloaded; + info("Dialog unloaded"); + + let openedDialog = await openedPromise; + ok(!openedDialog, "No additional dialog should have opened."); + + // If the test fails, clean up any dialogs we erroneously opened so they don't + // interfere with other tests. + let extraDialogs = 0; + while (openedDialog) { + extraDialogs += 1; + let doc = openedDialog.document; + let dialog = doc.getElementById("commonDialog"); + openedPromise = promiseDialogOrTimeout(); + dialog.cancelDialog(); + openedDialog = await openedPromise; + } + if (extraDialogs) { + info(`Closed ${extraDialogs} extra dialogs.`); + } + + // Either way, we now have an extra observer, so clean it up. + gCaretPromptOpeningObserver(); + + Services.prefs.setBoolPref(kPrefShortcutEnabled, true); + Services.prefs.setBoolPref(kPrefWarnOnEnable, true); + Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false); +}); |