summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/alerts
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--browser/base/content/test/alerts/browser.ini22
-rw-r--r--browser/base/content/test/alerts/browser_notification_close.js108
-rw-r--r--browser/base/content/test/alerts/browser_notification_do_not_disturb.js159
-rw-r--r--browser/base/content/test/alerts/browser_notification_open_settings.js79
-rw-r--r--browser/base/content/test/alerts/browser_notification_remove_permission.js85
-rw-r--r--browser/base/content/test/alerts/browser_notification_replace.js65
-rw-r--r--browser/base/content/test/alerts/browser_notification_tab_switching.js112
-rw-r--r--browser/base/content/test/alerts/file_dom_notifications.html39
-rw-r--r--browser/base/content/test/alerts/head.js72
9 files changed, 741 insertions, 0 deletions
diff --git a/browser/base/content/test/alerts/browser.ini b/browser/base/content/test/alerts/browser.ini
new file mode 100644
index 0000000000..c06f0d03d9
--- /dev/null
+++ b/browser/base/content/test/alerts/browser.ini
@@ -0,0 +1,22 @@
+[DEFAULT]
+support-files =
+ head.js
+ file_dom_notifications.html
+
+[browser_notification_close.js]
+https_first_disabled = true
+skip-if = os == 'win' # Bug 1227785
+[browser_notification_do_not_disturb.js]
+https_first_disabled = true
+[browser_notification_open_settings.js]
+https_first_disabled = true
+skip-if = os == 'win' # Bug 1411118
+[browser_notification_remove_permission.js]
+https_first_disabled = true
+skip-if = os == 'win' # Bug 1411118
+[browser_notification_replace.js]
+https_first_disabled = true
+skip-if = os == 'win' # Bug 1422928
+[browser_notification_tab_switching.js]
+https_first_disabled = true
+skip-if = os == 'win' # Bug 1243263
diff --git a/browser/base/content/test/alerts/browser_notification_close.js b/browser/base/content/test/alerts/browser_notification_close.js
new file mode 100644
index 0000000000..4b74a7ed4a
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_close.js
@@ -0,0 +1,108 @@
+"use strict";
+
+const { PlacesTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PlacesTestUtils.sys.mjs"
+);
+
+const { PermissionTestUtils } = ChromeUtils.import(
+ "resource://testing-common/PermissionTestUtils.jsm"
+);
+
+let notificationURL =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+let oldShowFavicons;
+
+add_task(async function test_notificationClose() {
+ let notificationURI = makeURI(notificationURL);
+ await addNotificationPermission(notificationURL);
+
+ oldShowFavicons = Services.prefs.getBoolPref("alerts.showFavicons");
+ Services.prefs.setBoolPref("alerts.showFavicons", true);
+
+ await PlacesTestUtils.addVisits(notificationURI);
+ let faviconURI = await new Promise(resolve => {
+ let uri = makeURI(
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC"
+ );
+ PlacesUtils.favicons.setAndFetchFaviconForPage(
+ notificationURI,
+ uri,
+ true,
+ PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
+ uriResult => resolve(uriResult),
+ Services.scriptSecurityManager.getSystemPrincipal()
+ );
+ });
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: notificationURL,
+ },
+ async function dummyTabTask(aBrowser) {
+ await openNotification(aBrowser, "showNotification2");
+
+ info("Notification alert showing");
+
+ let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+ if (!alertWindow) {
+ ok(true, "Notifications don't use XUL windows on all platforms.");
+ await closeNotification(aBrowser);
+ return;
+ }
+
+ let alertTitleLabel = alertWindow.document.getElementById(
+ "alertTitleLabel"
+ );
+ is(
+ alertTitleLabel.value,
+ "Test title",
+ "Title text of notification should be present"
+ );
+ let alertTextLabel = alertWindow.document.getElementById(
+ "alertTextLabel"
+ );
+ is(
+ alertTextLabel.textContent,
+ "Test body 2",
+ "Body text of notification should be present"
+ );
+ let alertIcon = alertWindow.document.getElementById("alertIcon");
+ is(
+ alertIcon.src,
+ faviconURI.spec,
+ "Icon of notification should be present"
+ );
+
+ let alertCloseButton = alertWindow.document.querySelector(".close-icon");
+ is(alertCloseButton.localName, "toolbarbutton", "close button found");
+ let promiseBeforeUnloadEvent = BrowserTestUtils.waitForEvent(
+ alertWindow,
+ "beforeunload"
+ );
+ let closedTime = alertWindow.Date.now();
+ alertCloseButton.click();
+ info("Clicked on close button");
+ await promiseBeforeUnloadEvent;
+
+ ok(true, "Alert should close when the close button is clicked");
+ let currentTime = alertWindow.Date.now();
+ // The notification will self-close at 12 seconds, so this checks
+ // that the notification closed before the timeout.
+ ok(
+ currentTime - closedTime < 5000,
+ "Close requested at " +
+ closedTime +
+ ", actually closed at " +
+ currentTime
+ );
+ }
+ );
+});
+
+add_task(async function cleanup() {
+ PermissionTestUtils.remove(notificationURL, "desktop-notification");
+ if (typeof oldShowFavicons == "boolean") {
+ Services.prefs.setBoolPref("alerts.showFavicons", oldShowFavicons);
+ }
+});
diff --git a/browser/base/content/test/alerts/browser_notification_do_not_disturb.js b/browser/base/content/test/alerts/browser_notification_do_not_disturb.js
new file mode 100644
index 0000000000..0cee558562
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_do_not_disturb.js
@@ -0,0 +1,159 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests that notifications can be silenced using nsIAlertsDoNotDisturb
+ * on systems where that interface and its methods are implemented for
+ * the nsIAlertService.
+ */
+
+const ALERT_SERVICE = Cc["@mozilla.org/alerts-service;1"]
+ .getService(Ci.nsIAlertsService)
+ .QueryInterface(Ci.nsIAlertsDoNotDisturb);
+
+const PAGE =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+
+// The amount of time in seconds that we will wait for a notification
+// to show up before we decide that it's not coming.
+const NOTIFICATION_TIMEOUT_SECS = 2000;
+
+add_setup(async function() {
+ await addNotificationPermission(PAGE);
+});
+
+/**
+ * Test that the manualDoNotDisturb attribute can prevent
+ * notifications from appearing.
+ */
+add_task(async function test_manualDoNotDisturb() {
+ try {
+ // Only run the test if the do-not-disturb
+ // interface has been implemented.
+ ALERT_SERVICE.manualDoNotDisturb;
+ ok(true, "Alert service implements do-not-disturb interface");
+ } catch (e) {
+ ok(
+ true,
+ "Alert service doesn't implement do-not-disturb interface, exiting test"
+ );
+ return;
+ }
+
+ // In the event that something goes wrong during this test, make sure
+ // we put the attribute back to the default setting when this test file
+ // exits.
+ registerCleanupFunction(() => {
+ ALERT_SERVICE.manualDoNotDisturb = false;
+ });
+
+ // Make sure that do-not-disturb is not enabled before we start.
+ ok(
+ !ALERT_SERVICE.manualDoNotDisturb,
+ "Alert service should not be disabled when test starts"
+ );
+
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await openNotification(browser, "showNotification2");
+
+ info("Notification alert showing");
+
+ let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+
+ // For now, only the XUL alert backend implements the manualDoNotDisturb
+ // method for nsIAlertsDoNotDisturb, so we expect there to be a XUL alert
+ // window. If the method gets implemented by native backends in the future,
+ // we'll probably want to branch here and set the manualDoNotDisturb
+ // attribute manually.
+ ok(alertWindow, "Expected a XUL alert window.");
+
+ // We're using the XUL notification backend. This means that there's
+ // a menuitem for enabling manualDoNotDisturb. We exercise that
+ // menuitem here.
+ let doNotDisturbMenuItem = alertWindow.document.getElementById(
+ "doNotDisturbMenuItem"
+ );
+ is(doNotDisturbMenuItem.localName, "menuitem", "menuitem found");
+
+ let unloadPromise = BrowserTestUtils.waitForEvent(
+ alertWindow,
+ "beforeunload"
+ );
+
+ doNotDisturbMenuItem.click();
+ info("Clicked on do-not-disturb menuitem");
+ await unloadPromise;
+
+ // At this point, we should be configured to not display notifications
+ // to the user.
+ ok(
+ ALERT_SERVICE.manualDoNotDisturb,
+ "Alert service should be disabled after clicking menuitem"
+ );
+
+ // The notification should not appear, but there is no way from the
+ // client-side to know that it was blocked, except for waiting some time
+ // and realizing that the "onshow" event never fired.
+ await Assert.rejects(
+ openNotification(browser, "showNotification2", NOTIFICATION_TIMEOUT_SECS),
+ /timed out/,
+ "The notification should never display."
+ );
+
+ ALERT_SERVICE.manualDoNotDisturb = false;
+ });
+});
+
+/**
+ * Test that the suppressForScreenSharing attribute can prevent
+ * notifications from appearing.
+ */
+add_task(async function test_suppressForScreenSharing() {
+ try {
+ // Only run the test if the do-not-disturb
+ // interface has been implemented.
+ ALERT_SERVICE.suppressForScreenSharing;
+ ok(true, "Alert service implements do-not-disturb interface");
+ } catch (e) {
+ ok(
+ true,
+ "Alert service doesn't implement do-not-disturb interface, exiting test"
+ );
+ return;
+ }
+
+ // In the event that something goes wrong during this test, make sure
+ // we put the attribute back to the default setting when this test file
+ // exits.
+ registerCleanupFunction(() => {
+ ALERT_SERVICE.suppressForScreenSharing = false;
+ });
+
+ // Make sure that do-not-disturb is not enabled before we start.
+ ok(
+ !ALERT_SERVICE.suppressForScreenSharing,
+ "Alert service should not be suppressing for screen sharing when test " +
+ "starts"
+ );
+
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await openNotification(browser, "showNotification2");
+
+ info("Notification alert showing");
+ await closeNotification(browser);
+ ALERT_SERVICE.suppressForScreenSharing = true;
+
+ // The notification should not appear, but there is no way from the
+ // client-side to know that it was blocked, except for waiting some time
+ // and realizing that the "onshow" event never fired.
+ await Assert.rejects(
+ openNotification(browser, "showNotification2", NOTIFICATION_TIMEOUT_SECS),
+ /timed out/,
+ "The notification should never display."
+ );
+ });
+
+ ALERT_SERVICE.suppressForScreenSharing = false;
+});
diff --git a/browser/base/content/test/alerts/browser_notification_open_settings.js b/browser/base/content/test/alerts/browser_notification_open_settings.js
new file mode 100644
index 0000000000..c8cd7add8c
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_open_settings.js
@@ -0,0 +1,79 @@
+"use strict";
+
+var notificationURL =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+var expectedURL = "about:preferences#privacy";
+
+add_task(async function test_settingsOpen_observer() {
+ info(
+ "Opening a dummy tab so openPreferences=>switchToTabHavingURI doesn't use the blank tab."
+ );
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "about:robots",
+ },
+ async function dummyTabTask(aBrowser) {
+ // Ensure preferences is loaded before removing the tab.
+ let syncPaneLoadedPromise = TestUtils.topicObserved(
+ "sync-pane-loaded",
+ () => true
+ );
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
+ info("simulate a notifications-open-settings notification");
+ let uri = NetUtil.newURI("https://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ Services.obs.notifyObservers(principal, "notifications-open-settings");
+ let tab = await tabPromise;
+ ok(tab, "The notification settings tab opened");
+ await syncPaneLoadedPromise;
+ BrowserTestUtils.removeTab(tab);
+ }
+ );
+});
+
+add_task(async function test_settingsOpen_button() {
+ info("Adding notification permission");
+ await addNotificationPermission(notificationURL);
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: notificationURL,
+ },
+ async function tabTask(aBrowser) {
+ info("Waiting for notification");
+ await openNotification(aBrowser, "showNotification2");
+
+ let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+ if (!alertWindow) {
+ ok(true, "Notifications don't use XUL windows on all platforms.");
+ await closeNotification(aBrowser);
+ return;
+ }
+
+ // Ensure preferences is loaded before removing the tab.
+ let syncPaneLoadedPromise = TestUtils.topicObserved(
+ "sync-pane-loaded",
+ () => true
+ );
+ let closePromise = promiseWindowClosed(alertWindow);
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
+ let openSettingsMenuItem = alertWindow.document.getElementById(
+ "openSettingsMenuItem"
+ );
+ openSettingsMenuItem.click();
+
+ info("Waiting for notification settings tab");
+ let tab = await tabPromise;
+ ok(tab, "The notification settings tab opened");
+
+ await syncPaneLoadedPromise;
+ await closePromise;
+ BrowserTestUtils.removeTab(tab);
+ }
+ );
+});
diff --git a/browser/base/content/test/alerts/browser_notification_remove_permission.js b/browser/base/content/test/alerts/browser_notification_remove_permission.js
new file mode 100644
index 0000000000..679b72debf
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_remove_permission.js
@@ -0,0 +1,85 @@
+"use strict";
+
+const { PermissionTestUtils } = ChromeUtils.import(
+ "resource://testing-common/PermissionTestUtils.jsm"
+);
+
+var tab;
+var notificationURL =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+var alertWindowClosed = false;
+var permRemoved = false;
+
+function test() {
+ waitForExplicitFinish();
+
+ registerCleanupFunction(function() {
+ gBrowser.removeTab(tab);
+ window.restore();
+ });
+
+ addNotificationPermission(notificationURL).then(function openTab() {
+ tab = BrowserTestUtils.addTab(gBrowser, notificationURL);
+ gBrowser.selectedTab = tab;
+ BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(() => onLoad());
+ });
+}
+
+function onLoad() {
+ openNotification(tab.linkedBrowser, "showNotification2").then(onAlertShowing);
+}
+
+function onAlertShowing() {
+ info("Notification alert showing");
+
+ let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+ if (!alertWindow) {
+ ok(true, "Notifications don't use XUL windows on all platforms.");
+ closeNotification(tab.linkedBrowser).then(finish);
+ return;
+ }
+ ok(
+ PermissionTestUtils.testExactPermission(
+ notificationURL,
+ "desktop-notification"
+ ),
+ "Permission should exist prior to removal"
+ );
+ let disableForOriginMenuItem = alertWindow.document.getElementById(
+ "disableForOriginMenuItem"
+ );
+ is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
+ Services.obs.addObserver(permObserver, "perm-changed");
+ alertWindow.addEventListener("beforeunload", onAlertClosing);
+ disableForOriginMenuItem.click();
+ info("Clicked on disable-for-origin menuitem");
+}
+
+function permObserver(subject, topic, data) {
+ if (topic != "perm-changed") {
+ return;
+ }
+
+ let permission = subject.QueryInterface(Ci.nsIPermission);
+ is(
+ permission.type,
+ "desktop-notification",
+ "desktop-notification permission changed"
+ );
+ is(data, "deleted", "desktop-notification permission deleted");
+
+ Services.obs.removeObserver(permObserver, "perm-changed");
+ permRemoved = true;
+ if (alertWindowClosed) {
+ finish();
+ }
+}
+
+function onAlertClosing(event) {
+ event.target.removeEventListener("beforeunload", onAlertClosing);
+
+ alertWindowClosed = true;
+ if (permRemoved) {
+ finish();
+ }
+}
diff --git a/browser/base/content/test/alerts/browser_notification_replace.js b/browser/base/content/test/alerts/browser_notification_replace.js
new file mode 100644
index 0000000000..c92777f515
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_replace.js
@@ -0,0 +1,65 @@
+"use strict";
+
+let notificationURL =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+
+add_task(async function test_notificationReplace() {
+ await addNotificationPermission(notificationURL);
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: notificationURL,
+ },
+ async function dummyTabTask(aBrowser) {
+ await SpecialPowers.spawn(aBrowser, [], async function() {
+ let win = content.window.wrappedJSObject;
+ let notification = win.showNotification1();
+ let promiseCloseEvent = ContentTaskUtils.waitForEvent(
+ notification,
+ "close"
+ );
+
+ let showEvent = await ContentTaskUtils.waitForEvent(
+ notification,
+ "show"
+ );
+ Assert.equal(
+ showEvent.target.body,
+ "Test body 1",
+ "Showed tagged notification"
+ );
+
+ let newNotification = win.showNotification2();
+ let newShowEvent = await ContentTaskUtils.waitForEvent(
+ newNotification,
+ "show"
+ );
+ Assert.equal(
+ newShowEvent.target.body,
+ "Test body 2",
+ "Showed new notification with same tag"
+ );
+
+ let closeEvent = await promiseCloseEvent;
+ Assert.equal(
+ closeEvent.target.body,
+ "Test body 1",
+ "Closed previous tagged notification"
+ );
+
+ let promiseNewCloseEvent = ContentTaskUtils.waitForEvent(
+ newNotification,
+ "close"
+ );
+ newNotification.close();
+ let newCloseEvent = await promiseNewCloseEvent;
+ Assert.equal(
+ newCloseEvent.target.body,
+ "Test body 2",
+ "Closed new notification"
+ );
+ });
+ }
+ );
+});
diff --git a/browser/base/content/test/alerts/browser_notification_tab_switching.js b/browser/base/content/test/alerts/browser_notification_tab_switching.js
new file mode 100644
index 0000000000..cc9e57c1c7
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_tab_switching.js
@@ -0,0 +1,112 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const { PermissionTestUtils } = ChromeUtils.import(
+ "resource://testing-common/PermissionTestUtils.jsm"
+);
+
+var tab;
+var notification;
+var notificationURL =
+ "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+var newWindowOpenedFromTab;
+
+add_task(async function test_notificationPreventDefaultAndSwitchTabs() {
+ await addNotificationPermission(notificationURL);
+
+ let originalTab = gBrowser.selectedTab;
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: notificationURL,
+ },
+ async function dummyTabTask(aBrowser) {
+ // Put new tab in background so it is obvious when it is re-focused.
+ await BrowserTestUtils.switchTab(gBrowser, originalTab);
+ isnot(
+ gBrowser.selectedBrowser,
+ aBrowser,
+ "Notification page loaded as a background tab"
+ );
+
+ // First, show a notification that will be have the tab-switching prevented.
+ function promiseNotificationEvent(evt) {
+ return SpecialPowers.spawn(aBrowser, [evt], async function(contentEvt) {
+ return new Promise(resolve => {
+ let contentNotification = content.wrappedJSObject._notification;
+ contentNotification.addEventListener(
+ contentEvt,
+ function(event) {
+ resolve({ defaultPrevented: event.defaultPrevented });
+ },
+ { once: true }
+ );
+ });
+ });
+ }
+ await openNotification(aBrowser, "showNotification1");
+ info("Notification alert showing");
+ let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+ if (!alertWindow) {
+ ok(true, "Notifications don't use XUL windows on all platforms.");
+ await closeNotification(aBrowser);
+ return;
+ }
+ info("Clicking on notification");
+ let promiseClickEvent = promiseNotificationEvent("click");
+
+ // NB: This executeSoon is needed to allow the non-e10s runs of this test
+ // a chance to set the event listener on the page. Otherwise, we
+ // synchronously fire the click event before we listen for the event.
+ executeSoon(() => {
+ EventUtils.synthesizeMouseAtCenter(
+ alertWindow.document.getElementById("alertTitleLabel"),
+ {},
+ alertWindow
+ );
+ });
+ let clickEvent = await promiseClickEvent;
+ ok(
+ clickEvent.defaultPrevented,
+ "The event handler for the first notification cancels the event"
+ );
+ isnot(
+ gBrowser.selectedBrowser,
+ aBrowser,
+ "Notification page still a background tab"
+ );
+ let notificationClosed = promiseNotificationEvent("close");
+ await closeNotification(aBrowser);
+ await notificationClosed;
+
+ // Second, show a notification that will cause the tab to get switched.
+ await openNotification(aBrowser, "showNotification2");
+ alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+ let promiseTabSelect = BrowserTestUtils.waitForEvent(
+ gBrowser.tabContainer,
+ "TabSelect"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ alertWindow.document.getElementById("alertTitleLabel"),
+ {},
+ alertWindow
+ );
+ await promiseTabSelect;
+ is(
+ gBrowser.selectedBrowser.currentURI.spec,
+ notificationURL,
+ "Clicking on the second notification should select its originating tab"
+ );
+ notificationClosed = promiseNotificationEvent("close");
+ await closeNotification(aBrowser);
+ await notificationClosed;
+ }
+ );
+});
+
+add_task(async function cleanup() {
+ PermissionTestUtils.remove(notificationURL, "desktop-notification");
+});
diff --git a/browser/base/content/test/alerts/file_dom_notifications.html b/browser/base/content/test/alerts/file_dom_notifications.html
new file mode 100644
index 0000000000..6deede8fcf
--- /dev/null
+++ b/browser/base/content/test/alerts/file_dom_notifications.html
@@ -0,0 +1,39 @@
+<html>
+<head>
+<meta charset="utf-8">
+<script>
+"use strict";
+
+function showNotification1() {
+ var options = {
+ dir: undefined,
+ lang: undefined,
+ body: "Test body 1",
+ tag: "Test tag",
+ icon: undefined,
+ };
+ var n = new Notification("Test title", options);
+ n.addEventListener("click", function(event) {
+ event.preventDefault();
+ });
+ return n;
+}
+
+function showNotification2() {
+ var options = {
+ dir: undefined,
+ lang: undefined,
+ body: "Test body 2",
+ tag: "Test tag",
+ icon: undefined,
+ };
+ return new Notification("Test title", options);
+}
+</script>
+</head>
+<body>
+<form id="notificationForm" onsubmit="showNotification();">
+ <input type="submit" value="Show notification" id="submit"/>
+</form>
+</body>
+</html>
diff --git a/browser/base/content/test/alerts/head.js b/browser/base/content/test/alerts/head.js
new file mode 100644
index 0000000000..2c2e04f98d
--- /dev/null
+++ b/browser/base/content/test/alerts/head.js
@@ -0,0 +1,72 @@
+// Platforms may default to reducing motion. We override this to ensure the
+// alert slide animation is enabled in tests.
+SpecialPowers.pushPrefEnv({
+ set: [["ui.prefersReducedMotion", 0]],
+});
+
+async function addNotificationPermission(originString) {
+ return SpecialPowers.pushPermissions([
+ {
+ type: "desktop-notification",
+ allow: true,
+ context: originString,
+ },
+ ]);
+}
+
+/**
+ * Similar to `BrowserTestUtils.closeWindow`, but
+ * doesn't call `window.close()`.
+ */
+function promiseWindowClosed(window) {
+ return new Promise(function(resolve) {
+ Services.ww.registerNotification(function observer(subject, topic, data) {
+ if (topic == "domwindowclosed" && subject == window) {
+ Services.ww.unregisterNotification(observer);
+ resolve();
+ }
+ });
+ });
+}
+
+/**
+ * These two functions work with file_dom_notifications.html to open the
+ * notification and close it.
+ *
+ * |fn| can be showNotification1 or showNotification2.
+ * if |timeout| is passed, then the promise returned from this function is
+ * rejected after the requested number of miliseconds.
+ */
+function openNotification(aBrowser, fn, timeout) {
+ info(`openNotification: ${fn}`);
+ return SpecialPowers.spawn(aBrowser, [[fn, timeout]], async function([
+ contentFn,
+ contentTimeout,
+ ]) {
+ await new Promise((resolve, reject) => {
+ let win = content.wrappedJSObject;
+ let notification = win[contentFn]();
+ win._notification = notification;
+
+ function listener() {
+ notification.removeEventListener("show", listener);
+ resolve();
+ }
+
+ notification.addEventListener("show", listener);
+
+ if (contentTimeout) {
+ content.setTimeout(() => {
+ notification.removeEventListener("show", listener);
+ reject("timed out");
+ }, contentTimeout);
+ }
+ });
+ });
+}
+
+function closeNotification(aBrowser) {
+ return SpecialPowers.spawn(aBrowser, [], function() {
+ content.wrappedJSObject._notification.close();
+ });
+}