summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/browser_f7_caret_browsing.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser/browser_f7_caret_browsing.js')
-rw-r--r--toolkit/content/tests/browser/browser_f7_caret_browsing.js367
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);
+});