summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/plugins')
-rw-r--r--browser/base/content/test/plugins/BlocklistTestProxy.jsm78
-rw-r--r--browser/base/content/test/plugins/browser.ini14
-rw-r--r--browser/base/content/test/plugins/browser_bug797677.js45
-rw-r--r--browser/base/content/test/plugins/browser_enable_DRM_prompt.js232
-rw-r--r--browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js63
-rw-r--r--browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js59
-rw-r--r--browser/base/content/test/plugins/empty_file.html9
-rw-r--r--browser/base/content/test/plugins/head.js210
-rw-r--r--browser/base/content/test/plugins/plugin_bug797677.html5
-rw-r--r--browser/base/content/test/plugins/plugin_test.html9
10 files changed, 724 insertions, 0 deletions
diff --git a/browser/base/content/test/plugins/BlocklistTestProxy.jsm b/browser/base/content/test/plugins/BlocklistTestProxy.jsm
new file mode 100644
index 0000000000..80e02e1e37
--- /dev/null
+++ b/browser/base/content/test/plugins/BlocklistTestProxy.jsm
@@ -0,0 +1,78 @@
+var EXPORTED_SYMBOLS = ["BlocklistTestProxyChild"];
+
+var Cm = Components.manager;
+
+const kBlocklistServiceUUID = "{66354bc9-7ed1-4692-ae1d-8da97d6b205e}";
+const kBlocklistServiceContractID = "@mozilla.org/extensions/blocklist;1";
+
+let existingBlocklistFactory = null;
+try {
+ existingBlocklistFactory = Cm.getClassObject(
+ Cc[kBlocklistServiceContractID],
+ Ci.nsIFactory
+ );
+} catch (ex) {}
+
+const { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+/*
+ * A lightweight blocklist proxy for testing purposes.
+ */
+var BlocklistProxy = {
+ _uuid: null,
+
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIObserver",
+ "nsIBlocklistService",
+ "nsITimerCallback",
+ ]),
+
+ init() {
+ if (!this._uuid) {
+ this._uuid = Services.uuid.generateUUID();
+ Cm.nsIComponentRegistrar.registerFactory(
+ this._uuid,
+ "",
+ "@mozilla.org/extensions/blocklist;1",
+ this
+ );
+ }
+ },
+
+ uninit() {
+ if (this._uuid) {
+ Cm.nsIComponentRegistrar.unregisterFactory(this._uuid, this);
+ if (existingBlocklistFactory) {
+ Cm.nsIComponentRegistrar.registerFactory(
+ Components.ID(kBlocklistServiceUUID),
+ "Blocklist Service",
+ "@mozilla.org/extensions/blocklist;1",
+ existingBlocklistFactory
+ );
+ }
+ this._uuid = null;
+ }
+ },
+
+ notify(aTimer) {},
+
+ async getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) {
+ await new Promise(r => setTimeout(r, 150));
+ return 0; // STATE_NOT_BLOCKED
+ },
+};
+
+class BlocklistTestProxyChild extends JSProcessActorChild {
+ constructor() {
+ super();
+ BlocklistProxy.init();
+ }
+
+ receiveMessage(message) {
+ if (message.name == "unload") {
+ BlocklistProxy.uninit();
+ }
+ }
+}
diff --git a/browser/base/content/test/plugins/browser.ini b/browser/base/content/test/plugins/browser.ini
new file mode 100644
index 0000000000..df3c5b4d6b
--- /dev/null
+++ b/browser/base/content/test/plugins/browser.ini
@@ -0,0 +1,14 @@
+[DEFAULT]
+support-files =
+ BlocklistTestProxy.jsm
+ empty_file.html
+ head.js
+ plugin_bug797677.html
+ plugin_test.html
+
+[browser_bug797677.js]
+[browser_enable_DRM_prompt.js]
+skip-if = (os == 'win' && processor == 'aarch64') # bug 1533164
+[browser_private_browsing_eme_persistent_state.js]
+[browser_globalplugin_crashinfobar.js]
+skip-if = !crashreporter
diff --git a/browser/base/content/test/plugins/browser_bug797677.js b/browser/base/content/test/plugins/browser_bug797677.js
new file mode 100644
index 0000000000..bcb35d161e
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug797677.js
@@ -0,0 +1,45 @@
+var gTestRoot = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "http://127.0.0.1:8888/"
+);
+var gTestBrowser = null;
+var gConsoleErrors = 0;
+
+add_task(async function() {
+ registerCleanupFunction(function() {
+ Services.console.unregisterListener(errorListener);
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ let errorListener = {
+ observe(aMessage) {
+ if (aMessage.message.includes("NS_ERROR_FAILURE")) {
+ gConsoleErrors++;
+ }
+ },
+ };
+ Services.console.registerListener(errorListener);
+
+ await promiseTabLoadEvent(
+ gBrowser.selectedTab,
+ gTestRoot + "plugin_bug797677.html"
+ );
+
+ let pluginInfo = await promiseForPluginInfo("plugin");
+ is(
+ pluginInfo.displayedType,
+ Ci.nsIObjectLoadingContent.TYPE_NULL,
+ "plugin should not have been found."
+ );
+
+ await SpecialPowers.spawn(gTestBrowser, [], function() {
+ let plugin = content.document.getElementById("plugin");
+ ok(plugin, "plugin should be in the page");
+ });
+ is(gConsoleErrors, 0, "should have no console errors");
+});
diff --git a/browser/base/content/test/plugins/browser_enable_DRM_prompt.js b/browser/base/content/test/plugins/browser_enable_DRM_prompt.js
new file mode 100644
index 0000000000..8698c07a6c
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_enable_DRM_prompt.js
@@ -0,0 +1,232 @@
+const TEST_URL =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+ ) + "empty_file.html";
+
+/*
+ * Register cleanup function to reset prefs after other tasks have run.
+ */
+
+add_task(async function() {
+ // Note: SpecialPowers.pushPrefEnv has problems with the "Enable DRM"
+ // button on the notification box toggling the prefs. So manually
+ // set/unset the prefs the UI we're testing toggles.
+ let emeWasEnabled = Services.prefs.getBoolPref("media.eme.enabled", false);
+ let cdmWasEnabled = Services.prefs.getBoolPref(
+ "media.gmp-widevinecdm.enabled",
+ false
+ );
+
+ // Restore the preferences to their pre-test state on test finish.
+ registerCleanupFunction(function() {
+ // Unlock incase lock test threw and didn't unlock.
+ Services.prefs.unlockPref("media.eme.enabled");
+ Services.prefs.setBoolPref("media.eme.enabled", emeWasEnabled);
+ Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", cdmWasEnabled);
+ });
+});
+
+/*
+ * Bug 1366167 - Tests that the "Enable DRM" prompt shows if EME is requested while EME is disabled.
+ */
+
+add_task(async function test_drm_prompt_shows_for_toplevel() {
+ await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+ // Turn off EME and Widevine CDM.
+ Services.prefs.setBoolPref("media.eme.enabled", false);
+ Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false);
+
+ // Have content request access to Widevine, UI should drop down to
+ // prompt user to enable DRM.
+ let result = await SpecialPowers.spawn(browser, [], async function() {
+ try {
+ let config = [
+ {
+ initDataTypes: ["webm"],
+ videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
+ },
+ ];
+ await content.navigator.requestMediaKeySystemAccess(
+ "com.widevine.alpha",
+ config
+ );
+ } catch (ex) {
+ return { rejected: true };
+ }
+ return { rejected: false };
+ });
+ is(
+ result.rejected,
+ true,
+ "EME request should be denied because EME disabled."
+ );
+
+ // Verify the UI prompt showed.
+ let box = gBrowser.getNotificationBox(browser);
+ let notification = box.currentNotification;
+
+ ok(notification, "Notification should be visible");
+ is(
+ notification.getAttribute("value"),
+ "drmContentDisabled",
+ "Should be showing the right notification"
+ );
+
+ // Verify the "Enable DRM" button is there.
+ let buttons = notification.buttonContainer.querySelectorAll(
+ ".notification-button"
+ );
+ is(buttons.length, 1, "Should have one button.");
+
+ // Prepare a Promise that should resolve when the "Enable DRM" button's
+ // page reload completes.
+ let refreshPromise = BrowserTestUtils.browserLoaded(browser);
+ buttons[0].click();
+
+ // Wait for the reload to complete.
+ await refreshPromise;
+
+ // Verify clicking the "Enable DRM" button enabled DRM.
+ let enabled = Services.prefs.getBoolPref("media.eme.enabled", true);
+ is(
+ enabled,
+ true,
+ "EME should be enabled after click on 'Enable DRM' button"
+ );
+ });
+});
+
+add_task(async function test_eme_locked() {
+ await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+ // Turn off EME and Widevine CDM.
+ Services.prefs.setBoolPref("media.eme.enabled", false);
+ Services.prefs.lockPref("media.eme.enabled");
+
+ // Have content request access to Widevine, UI should drop down to
+ // prompt user to enable DRM.
+ let result = await SpecialPowers.spawn(browser, [], async function() {
+ try {
+ let config = [
+ {
+ initDataTypes: ["webm"],
+ videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
+ },
+ ];
+ await content.navigator.requestMediaKeySystemAccess(
+ "com.widevine.alpha",
+ config
+ );
+ } catch (ex) {
+ return { rejected: true };
+ }
+ return { rejected: false };
+ });
+ is(
+ result.rejected,
+ true,
+ "EME request should be denied because EME disabled."
+ );
+
+ // Verify the UI prompt did not show.
+ let box = gBrowser.getNotificationBox(browser);
+ let notification = box.currentNotification;
+
+ is(
+ notification,
+ null,
+ "Notification should not be displayed since pref is locked"
+ );
+
+ // Unlock the pref for any tests that follow.
+ Services.prefs.unlockPref("media.eme.enabled");
+ });
+});
+
+/*
+ * Bug 1642465 - Ensure cross origin frames requesting access prompt in the same way as same origin.
+ */
+
+add_task(async function test_drm_prompt_shows_for_cross_origin_iframe() {
+ await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+ // Turn off EME and Widevine CDM.
+ Services.prefs.setBoolPref("media.eme.enabled", false);
+ Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false);
+
+ // Have content request access to Widevine, UI should drop down to
+ // prompt user to enable DRM.
+ const CROSS_ORIGIN_URL = TEST_URL.replace("example.com", "example.org");
+ let result = await SpecialPowers.spawn(
+ browser,
+ [CROSS_ORIGIN_URL],
+ async function(crossOriginUrl) {
+ let frame = content.document.createElement("iframe");
+ frame.src = crossOriginUrl;
+ await new Promise(resolve => {
+ frame.addEventListener("load", () => {
+ resolve();
+ });
+ content.document.body.appendChild(frame);
+ });
+
+ return content.SpecialPowers.spawn(frame, [], async function() {
+ try {
+ let config = [
+ {
+ initDataTypes: ["webm"],
+ videoCapabilities: [
+ { contentType: 'video/webm; codecs="vp9"' },
+ ],
+ },
+ ];
+ await content.navigator.requestMediaKeySystemAccess(
+ "com.widevine.alpha",
+ config
+ );
+ } catch (ex) {
+ return { rejected: true };
+ }
+ return { rejected: false };
+ });
+ }
+ );
+ is(
+ result.rejected,
+ true,
+ "EME request should be denied because EME disabled."
+ );
+
+ // Verify the UI prompt showed.
+ let box = gBrowser.getNotificationBox(browser);
+ let notification = box.currentNotification;
+
+ ok(notification, "Notification should be visible");
+ is(
+ notification.getAttribute("value"),
+ "drmContentDisabled",
+ "Should be showing the right notification"
+ );
+
+ // Verify the "Enable DRM" button is there.
+ let buttons = notification.buttonContainer.querySelectorAll(
+ ".notification-button"
+ );
+ is(buttons.length, 1, "Should have one button.");
+
+ // Prepare a Promise that should resolve when the "Enable DRM" button's
+ // page reload completes.
+ let refreshPromise = BrowserTestUtils.browserLoaded(browser);
+ buttons[0].click();
+
+ // Wait for the reload to complete.
+ await refreshPromise;
+
+ // Verify clicking the "Enable DRM" button enabled DRM.
+ let enabled = Services.prefs.getBoolPref("media.eme.enabled", true);
+ is(
+ enabled,
+ true,
+ "EME should be enabled after click on 'Enable DRM' button"
+ );
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js b/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js
new file mode 100644
index 0000000000..97cb9db618
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js
@@ -0,0 +1,63 @@
+"use strict";
+
+let { PluginManager } = ChromeUtils.import(
+ "resource:///actors/PluginParent.jsm"
+);
+
+/**
+ * Test that the notification bar for crashed GMPs works.
+ */
+add_task(async function() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "about:blank",
+ },
+ async function(browser) {
+ // Ensure the parent has heard before the client.
+ // In practice, this is always true for GMP crashes (but not for NPAPI ones!)
+ let props = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
+ Ci.nsIWritablePropertyBag2
+ );
+ props.setPropertyAsUint32("pluginID", 1);
+ props.setPropertyAsACString("pluginName", "GlobalTestPlugin");
+ props.setPropertyAsACString("pluginDumpID", "1234");
+ Services.obs.notifyObservers(props, "gmp-plugin-crash");
+
+ await SpecialPowers.spawn(browser, [], async function() {
+ const GMP_CRASH_EVENT = {
+ pluginID: 1,
+ pluginName: "GlobalTestPlugin",
+ submittedCrashReport: false,
+ bubbles: true,
+ cancelable: true,
+ gmpPlugin: true,
+ };
+
+ let crashEvent = new content.PluginCrashedEvent(
+ "PluginCrashed",
+ GMP_CRASH_EVENT
+ );
+ content.dispatchEvent(crashEvent);
+ });
+
+ let notification = await waitForNotificationBar(
+ "plugin-crashed",
+ browser
+ );
+
+ let notificationBox = gBrowser.getNotificationBox(browser);
+ ok(notification, "Infobar was shown.");
+ is(
+ notification.priority,
+ notificationBox.PRIORITY_WARNING_MEDIUM,
+ "Correct priority."
+ );
+ is(
+ notification.messageText.textContent,
+ "The GlobalTestPlugin plugin has crashed.",
+ "Correct message."
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js b/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js
new file mode 100644
index 0000000000..9a0b91119b
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test ensures that navigator.requestMediaKeySystemAccess() requests
+ * to run EME with persistent state are rejected in private browsing windows.
+ * Bug 1334111.
+ */
+
+const TEST_URL =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+ ) + "empty_file.html";
+
+async function isEmePersistentStateSupported(mode) {
+ let win = await BrowserTestUtils.openNewBrowserWindow(mode);
+ let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL);
+ let persistentStateSupported = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async function() {
+ try {
+ let config = [
+ {
+ initDataTypes: ["webm"],
+ videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
+ persistentState: "required",
+ },
+ ];
+ await content.navigator.requestMediaKeySystemAccess(
+ "org.w3.clearkey",
+ config
+ );
+ } catch (ex) {
+ return false;
+ }
+ return true;
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+
+ return persistentStateSupported;
+}
+
+add_task(async function test() {
+ is(
+ await isEmePersistentStateSupported({ private: true }),
+ false,
+ "EME persistentState should *NOT* be supported in private browsing window."
+ );
+ is(
+ await isEmePersistentStateSupported({ private: false }),
+ true,
+ "EME persistentState *SHOULD* be supported in non private browsing window."
+ );
+});
diff --git a/browser/base/content/test/plugins/empty_file.html b/browser/base/content/test/plugins/empty_file.html
new file mode 100644
index 0000000000..af8440ac16
--- /dev/null
+++ b/browser/base/content/test/plugins/empty_file.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ </head>
+ <body>
+ This page is intentionally left blank.
+ </body>
+</html>
diff --git a/browser/base/content/test/plugins/head.js b/browser/base/content/test/plugins/head.js
new file mode 100644
index 0000000000..c02af8b281
--- /dev/null
+++ b/browser/base/content/test/plugins/head.js
@@ -0,0 +1,210 @@
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+});
+
+// Various tests in this directory may define gTestBrowser, to use as the
+// default browser under test in some of the functions below.
+/* global gTestBrowser:true */
+
+/**
+ * Waits a specified number of miliseconds.
+ *
+ * Usage:
+ * let wait = yield waitForMs(2000);
+ * ok(wait, "2 seconds should now have elapsed");
+ *
+ * @param aMs the number of miliseconds to wait for
+ * @returns a Promise that resolves to true after the time has elapsed
+ */
+function waitForMs(aMs) {
+ return new Promise(resolve => {
+ setTimeout(done, aMs);
+ function done() {
+ resolve(true);
+ }
+ });
+}
+
+/**
+ * Waits for a load (or custom) event to finish in a given tab. If provided
+ * load an uri into the tab.
+ *
+ * @param tab
+ * The tab to load into.
+ * @param [optional] url
+ * The url to load, or the current url.
+ * @return {Promise} resolved when the event is handled.
+ * @resolves to the received event
+ * @rejects if a valid load event is not received within a meaningful interval
+ */
+function promiseTabLoadEvent(tab, url) {
+ info("Wait tab event: load");
+
+ function handle(loadedUrl) {
+ if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
+ info(`Skipping spurious load event for ${loadedUrl}`);
+ return false;
+ }
+
+ info("Tab event received: load");
+ return true;
+ }
+
+ let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
+
+ if (url) {
+ BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+ }
+
+ return loaded;
+}
+
+function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
+ let tries = 0;
+ let maxTries = aTries || 100; // 100 tries
+ let maxWait = aWait || 100; // 100 msec x 100 tries = ten seconds
+ let interval = setInterval(function() {
+ if (tries >= maxTries) {
+ ok(false, errorMsg);
+ moveOn();
+ }
+ let conditionPassed;
+ try {
+ conditionPassed = condition();
+ } catch (e) {
+ ok(false, e + "\n" + e.stack);
+ conditionPassed = false;
+ }
+ if (conditionPassed) {
+ moveOn();
+ }
+ tries++;
+ }, maxWait);
+ let moveOn = function() {
+ clearInterval(interval);
+ nextTest();
+ };
+}
+
+// Waits for a conditional function defined by the caller to return true.
+function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
+ return new Promise(resolve => {
+ waitForCondition(
+ aConditionFn,
+ resolve,
+ aMessage || "Condition didn't pass.",
+ aTries,
+ aWait
+ );
+ });
+}
+
+// Returns a promise for nsIObjectLoadingContent props data.
+function promiseForPluginInfo(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return SpecialPowers.spawn(browser, [aId], async function(contentId) {
+ let plugin = content.document.getElementById(contentId);
+ if (!(plugin instanceof Ci.nsIObjectLoadingContent)) {
+ throw new Error("no plugin found");
+ }
+ return {
+ activated: plugin.activated,
+ hasRunningPlugin: plugin.hasRunningPlugin,
+ displayedType: plugin.displayedType,
+ };
+ });
+}
+
+/**
+ * Allows setting focus on a window, and waiting for that window to achieve
+ * focus.
+ *
+ * @param aWindow
+ * The window to focus and wait for.
+ *
+ * @return {Promise}
+ * @resolves When the window is focused.
+ * @rejects Never.
+ */
+function promiseWaitForFocus(aWindow) {
+ return new Promise(resolve => {
+ waitForFocus(resolve, aWindow);
+ });
+}
+
+/**
+ * Returns a Promise that resolves when a notification bar
+ * for a browser is shown. Alternatively, for old-style callers,
+ * can automatically call a callback before it resolves.
+ *
+ * @param notificationID
+ * The ID of the notification to look for.
+ * @param browser
+ * The browser to check for the notification bar.
+ * @param callback (optional)
+ * A function to be called just before the Promise resolves.
+ *
+ * @return Promise
+ */
+function waitForNotificationBar(notificationID, browser, callback) {
+ return new Promise((resolve, reject) => {
+ let notification;
+ let notificationBox = gBrowser.getNotificationBox(browser);
+ waitForCondition(
+ () =>
+ (notification = notificationBox.getNotificationWithValue(
+ notificationID
+ )),
+ () => {
+ ok(
+ notification,
+ `Successfully got the ${notificationID} notification bar`
+ );
+ if (callback) {
+ callback(notification);
+ }
+ resolve(notification);
+ },
+ `Waited too long for the ${notificationID} notification bar`
+ );
+ });
+}
+
+function promiseForNotificationBar(notificationID, browser) {
+ return new Promise(resolve => {
+ waitForNotificationBar(notificationID, browser, resolve);
+ });
+}
+
+/**
+ * Reshow a notification and call a callback when it is reshown.
+ * @param notification
+ * The notification to reshow
+ * @param callback
+ * A function to be called when the notification has been reshown
+ */
+function waitForNotificationShown(notification, callback) {
+ if (PopupNotifications.panel.state == "open") {
+ executeSoon(callback);
+ return;
+ }
+ PopupNotifications.panel.addEventListener(
+ "popupshown",
+ function(e) {
+ callback();
+ },
+ { once: true }
+ );
+ notification.reshow();
+}
+
+function promiseForNotificationShown(notification) {
+ return new Promise(resolve => {
+ waitForNotificationShown(notification, resolve);
+ });
+}
diff --git a/browser/base/content/test/plugins/plugin_bug797677.html b/browser/base/content/test/plugins/plugin_bug797677.html
new file mode 100644
index 0000000000..1545f36475
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_bug797677.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body><embed id="plugin" type="9000"></embed></body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_test.html b/browser/base/content/test/plugins/plugin_test.html
new file mode 100644
index 0000000000..3d4f43e6a5
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_test.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 300px; height: 300px" type="application/x-test">
+</body>
+</html>