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/.eslintrc.js7
-rw-r--r--browser/base/content/test/plugins/blockNoPlugins.xml7
-rw-r--r--browser/base/content/test/plugins/blockPluginHard.xml11
-rw-r--r--browser/base/content/test/plugins/blockPluginInfoURL.xml12
-rw-r--r--browser/base/content/test/plugins/blockPluginVulnerableNoUpdate.xml11
-rw-r--r--browser/base/content/test/plugins/blockPluginVulnerableUpdatable.xml11
-rw-r--r--browser/base/content/test/plugins/blocklist_proxy.js78
-rw-r--r--browser/base/content/test/plugins/browser.ini78
-rw-r--r--browser/base/content/test/plugins/browser_CTP_context_menu.js69
-rw-r--r--browser/base/content/test/plugins/browser_CTP_crashreporting.js233
-rw-r--r--browser/base/content/test/plugins/browser_CTP_data_urls.js255
-rw-r--r--browser/base/content/test/plugins/browser_CTP_drag_drop.js96
-rw-r--r--browser/base/content/test/plugins/browser_CTP_hide_overlay.js88
-rw-r--r--browser/base/content/test/plugins/browser_CTP_iframe.js48
-rw-r--r--browser/base/content/test/plugins/browser_CTP_multi_allow.js99
-rw-r--r--browser/base/content/test/plugins/browser_CTP_nonplugins.js58
-rw-r--r--browser/base/content/test/plugins/browser_CTP_notificationBar.js151
-rw-r--r--browser/base/content/test/plugins/browser_CTP_outsideScrollArea.js120
-rw-r--r--browser/base/content/test/plugins/browser_CTP_remove_navigate.js79
-rw-r--r--browser/base/content/test/plugins/browser_CTP_resize.js130
-rw-r--r--browser/base/content/test/plugins/browser_CTP_zoom.js62
-rw-r--r--browser/base/content/test/plugins/browser_blocking.js349
-rw-r--r--browser/base/content/test/plugins/browser_blocklist_content.js104
-rw-r--r--browser/base/content/test/plugins/browser_bug743421.js119
-rw-r--r--browser/base/content/test/plugins/browser_bug744745.js50
-rw-r--r--browser/base/content/test/plugins/browser_bug787619.js65
-rw-r--r--browser/base/content/test/plugins/browser_bug797677.js43
-rw-r--r--browser/base/content/test/plugins/browser_bug812562.js80
-rw-r--r--browser/base/content/test/plugins/browser_bug818118.js40
-rw-r--r--browser/base/content/test/plugins/browser_bug820497.js71
-rw-r--r--browser/base/content/test/plugins/browser_clearplugindata.html30
-rw-r--r--browser/base/content/test/plugins/browser_clearplugindata.js127
-rw-r--r--browser/base/content/test/plugins/browser_clearplugindata_noage.html30
-rw-r--r--browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js34
-rw-r--r--browser/base/content/test/plugins/browser_pageInfo_plugins.js191
-rw-r--r--browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js207
-rw-r--r--browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js254
-rw-r--r--browser/base/content/test/plugins/browser_plugin_reloading.js85
-rw-r--r--browser/base/content/test/plugins/browser_pluginnotification.js626
-rw-r--r--browser/base/content/test/plugins/browser_plugins_added_dynamically.js137
-rw-r--r--browser/base/content/test/plugins/browser_private_clicktoplay.js216
-rw-r--r--browser/base/content/test/plugins/head.js396
-rw-r--r--browser/base/content/test/plugins/plugin_add_dynamically.html18
-rw-r--r--browser/base/content/test/plugins/plugin_alternate_content.html9
-rw-r--r--browser/base/content/test/plugins/plugin_big.html9
-rw-r--r--browser/base/content/test/plugins/plugin_both.html10
-rw-r--r--browser/base/content/test/plugins/plugin_both2.html10
-rw-r--r--browser/base/content/test/plugins/plugin_bug744745.html12
-rw-r--r--browser/base/content/test/plugins/plugin_bug749455.html8
-rw-r--r--browser/base/content/test/plugins/plugin_bug787619.html9
-rw-r--r--browser/base/content/test/plugins/plugin_bug797677.html5
-rw-r--r--browser/base/content/test/plugins/plugin_bug820497.html17
-rw-r--r--browser/base/content/test/plugins/plugin_clickToPlayAllow.html9
-rw-r--r--browser/base/content/test/plugins/plugin_clickToPlayDeny.html9
-rw-r--r--browser/base/content/test/plugins/plugin_crashCommentAndURL.html27
-rw-r--r--browser/base/content/test/plugins/plugin_data_url.html11
-rw-r--r--browser/base/content/test/plugins/plugin_hidden_to_visible.html11
-rw-r--r--browser/base/content/test/plugins/plugin_iframe.html9
-rw-r--r--browser/base/content/test/plugins/plugin_outsideScrollArea.html25
-rw-r--r--browser/base/content/test/plugins/plugin_overlayed.html27
-rw-r--r--browser/base/content/test/plugins/plugin_positioned.html12
-rw-r--r--browser/base/content/test/plugins/plugin_small.html9
-rw-r--r--browser/base/content/test/plugins/plugin_small_2.html9
-rw-r--r--browser/base/content/test/plugins/plugin_syncRemoved.html15
-rw-r--r--browser/base/content/test/plugins/plugin_test.html9
-rw-r--r--browser/base/content/test/plugins/plugin_test2.html10
-rw-r--r--browser/base/content/test/plugins/plugin_test3.html9
-rw-r--r--browser/base/content/test/plugins/plugin_two_types.html9
-rw-r--r--browser/base/content/test/plugins/plugin_unknown.html9
-rw-r--r--browser/base/content/test/plugins/plugin_zoom.html10
70 files changed, 5293 insertions, 0 deletions
diff --git a/browser/base/content/test/plugins/.eslintrc.js b/browser/base/content/test/plugins/.eslintrc.js
new file mode 100644
index 000000000..7c8021192
--- /dev/null
+++ b/browser/base/content/test/plugins/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/browser/base/content/test/plugins/blockNoPlugins.xml b/browser/base/content/test/plugins/blockNoPlugins.xml
new file mode 100644
index 000000000..e4e191b37
--- /dev/null
+++ b/browser/base/content/test/plugins/blockNoPlugins.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310001">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ </pluginItems>
+</blocklist>
diff --git a/browser/base/content/test/plugins/blockPluginHard.xml b/browser/base/content/test/plugins/blockPluginHard.xml
new file mode 100644
index 000000000..24eb5bc6f
--- /dev/null
+++ b/browser/base/content/test/plugins/blockPluginHard.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ <pluginItem blockID="p9999">
+ <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" />
+ <versionRange severity="2"></versionRange>
+ </pluginItem>
+ </pluginItems>
+</blocklist>
diff --git a/browser/base/content/test/plugins/blockPluginInfoURL.xml b/browser/base/content/test/plugins/blockPluginInfoURL.xml
new file mode 100644
index 000000000..c16808896
--- /dev/null
+++ b/browser/base/content/test/plugins/blockPluginInfoURL.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ <pluginItem blockID="p9999">
+ <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" />
+ <versionRange severity="2"></versionRange>
+ <infoURL>http://test.url.com/</infoURL>
+ </pluginItem>
+ </pluginItems>
+</blocklist>
diff --git a/browser/base/content/test/plugins/blockPluginVulnerableNoUpdate.xml b/browser/base/content/test/plugins/blockPluginVulnerableNoUpdate.xml
new file mode 100644
index 000000000..bf8545afe
--- /dev/null
+++ b/browser/base/content/test/plugins/blockPluginVulnerableNoUpdate.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ <pluginItem blockID="p9999">
+ <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" />
+ <versionRange severity="0" vulnerabilitystatus="2"></versionRange>
+ </pluginItem>
+ </pluginItems>
+</blocklist>
diff --git a/browser/base/content/test/plugins/blockPluginVulnerableUpdatable.xml b/browser/base/content/test/plugins/blockPluginVulnerableUpdatable.xml
new file mode 100644
index 000000000..5545162b1
--- /dev/null
+++ b/browser/base/content/test/plugins/blockPluginVulnerableUpdatable.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ <pluginItem blockID="p9999">
+ <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" />
+ <versionRange severity="0" vulnerabilitystatus="1"></versionRange>
+ </pluginItem>
+ </pluginItems>
+</blocklist>
diff --git a/browser/base/content/test/plugins/blocklist_proxy.js b/browser/base/content/test/plugins/blocklist_proxy.js
new file mode 100644
index 000000000..1a4ed4726
--- /dev/null
+++ b/browser/base/content/test/plugins/blocklist_proxy.js
@@ -0,0 +1,78 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+var Cm = Components.manager;
+
+const kBlocklistServiceUUID = "{66354bc9-7ed1-4692-ae1d-8da97d6b205e}";
+const kBlocklistServiceContractID = "@mozilla.org/extensions/blocklist;1";
+const kBlocklistServiceFactory = Cm.getClassObject(Cc[kBlocklistServiceContractID], Ci.nsIFactory);
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+/*
+ * A lightweight blocklist proxy for the testing purposes.
+ */
+var BlocklistProxy = {
+ _uuid: null,
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsIBlocklistService,
+ Ci.nsITimerCallback]),
+
+ init: function() {
+ if (!this._uuid) {
+ this._uuid =
+ Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
+ .generateUUID();
+ Cm.nsIComponentRegistrar.registerFactory(this._uuid, "",
+ "@mozilla.org/extensions/blocklist;1",
+ this);
+ }
+ },
+
+ uninit: function() {
+ if (this._uuid) {
+ Cm.nsIComponentRegistrar.unregisterFactory(this._uuid, this);
+ Cm.nsIComponentRegistrar.registerFactory(Components.ID(kBlocklistServiceUUID),
+ "Blocklist Service",
+ "@mozilla.org/extensions/blocklist;1",
+ kBlocklistServiceFactory);
+ this._uuid = null;
+ }
+ },
+
+ notify: function (aTimer) {
+ },
+
+ observe: function (aSubject, aTopic, aData) {
+ },
+
+ isAddonBlocklisted: function (aAddon, aAppVersion, aToolkitVersion) {
+ return false;
+ },
+
+ getAddonBlocklistState: function (aAddon, aAppVersion, aToolkitVersion) {
+ return 0; // STATE_NOT_BLOCKED
+ },
+
+ getPluginBlocklistState: function (aPluginTag, aAppVersion, aToolkitVersion) {
+ return 0; // STATE_NOT_BLOCKED
+ },
+
+ getAddonBlocklistURL: function (aAddon, aAppVersion, aToolkitVersion) {
+ return "";
+ },
+
+ getPluginBlocklistURL: function (aPluginTag) {
+ return "";
+ },
+
+ getPluginInfoURL: function (aPluginTag) {
+ return "";
+ },
+}
+
+BlocklistProxy.init();
+addEventListener("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 000000000..cfc1f769c
--- /dev/null
+++ b/browser/base/content/test/plugins/browser.ini
@@ -0,0 +1,78 @@
+[DEFAULT]
+support-files =
+ blocklist_proxy.js
+ blockNoPlugins.xml
+ blockPluginHard.xml
+ blockPluginInfoURL.xml
+ blockPluginVulnerableNoUpdate.xml
+ blockPluginVulnerableUpdatable.xml
+ browser_clearplugindata.html
+ browser_clearplugindata_noage.html
+ head.js
+ plugin_add_dynamically.html
+ plugin_alternate_content.html
+ plugin_big.html
+ plugin_both.html
+ plugin_both2.html
+ plugin_bug744745.html
+ plugin_bug749455.html
+ plugin_bug787619.html
+ plugin_bug797677.html
+ plugin_bug820497.html
+ plugin_clickToPlayAllow.html
+ plugin_clickToPlayDeny.html
+ plugin_data_url.html
+ plugin_hidden_to_visible.html
+ plugin_iframe.html
+ plugin_outsideScrollArea.html
+ plugin_overlayed.html
+ plugin_positioned.html
+ plugin_small.html
+ plugin_small_2.html
+ plugin_syncRemoved.html
+ plugin_test.html
+ plugin_test2.html
+ plugin_test3.html
+ plugin_two_types.html
+ plugin_unknown.html
+ plugin_crashCommentAndURL.html
+ plugin_zoom.html
+
+[browser_bug743421.js]
+[browser_bug744745.js]
+[browser_bug787619.js]
+[browser_bug797677.js]
+[browser_bug812562.js]
+[browser_bug818118.js]
+[browser_bug820497.js]
+[browser_clearplugindata.js]
+[browser_CTP_context_menu.js]
+skip-if = toolkit == "gtk2" || toolkit == "gtk3" # fails intermittently on Linux (bug 909342)
+[browser_CTP_crashreporting.js]
+skip-if = !crashreporter
+[browser_CTP_data_urls.js]
+[browser_CTP_drag_drop.js]
+[browser_CTP_hide_overlay.js]
+[browser_CTP_iframe.js]
+[browser_CTP_multi_allow.js]
+[browser_CTP_nonplugins.js]
+[browser_CTP_notificationBar.js]
+[browser_CTP_outsideScrollArea.js]
+[browser_CTP_remove_navigate.js]
+[browser_CTP_resize.js]
+[browser_CTP_zoom.js]
+[browser_blocking.js]
+[browser_plugins_added_dynamically.js]
+[browser_pluginnotification.js]
+[browser_plugin_reloading.js]
+[browser_blocklist_content.js]
+skip-if = !e10s
+[browser_globalplugin_crashinfobar.js]
+skip-if = !crashreporter
+[browser_pluginCrashCommentAndURL.js]
+skip-if = !crashreporter
+[browser_pageInfo_plugins.js]
+[browser_pluginCrashReportNonDeterminism.js]
+skip-if = !crashreporter || os == 'linux' # Bug 1152811
+[browser_private_clicktoplay.js]
+
diff --git a/browser/base/content/test/plugins/browser_CTP_context_menu.js b/browser/base/content/test/plugins/browser_CTP_context_menu.js
new file mode 100644
index 000000000..03f3e18ef
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_context_menu.js
@@ -0,0 +1,69 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+});
+
+// Test that the activate action in content menus for CTP plugins works
+add_task(function* () {
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ let bindingPromise = waitForEvent(gBrowser.selectedBrowser, "PluginBindingAttached", null, true, true);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+ yield bindingPromise;
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(popupNotification, "Test 1, Should have a click-to-play notification");
+
+ // check plugin state
+ let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
+ ok(!pluginInfo.activated, "plugin should not be activated");
+
+ // Display a context menu on the test plugin so we can test
+ // activation menu options.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("contextmenu", left, top, 2, 1, 0);
+ });
+
+ popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(popupNotification, "Should have a click-to-play notification");
+ ok(popupNotification.dismissed, "notification should be dismissed");
+
+ // fixes a occasional test timeout on win7 opt
+ yield promiseForCondition(() => document.getElementById("context-ctp-play"));
+
+ let actMenuItem = document.getElementById("context-ctp-play");
+ ok(actMenuItem, "Should have a context menu entry for activating the plugin");
+
+ // Activate the plugin via the context menu
+ EventUtils.synthesizeMouseAtCenter(actMenuItem, {});
+
+ yield promiseForCondition(() => !PopupNotifications.panel.dismissed && PopupNotifications.panel.firstChild);
+
+ // Activate the plugin
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
+ ok(pluginInfo.activated, "plugin should not be activated");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_crashreporting.js b/browser/base/content/test/plugins/browser_CTP_crashreporting.js
new file mode 100644
index 000000000..bb52d5704
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_crashreporting.js
@@ -0,0 +1,233 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+const PLUGIN_PAGE = gTestRoot + "plugin_big.html";
+const PLUGIN_SMALL_PAGE = gTestRoot + "plugin_small.html";
+
+/**
+ * Takes an nsIPropertyBag and converts it into a JavaScript Object. It
+ * will also convert any nsIPropertyBag's within the nsIPropertyBag
+ * recursively.
+ *
+ * @param aBag
+ * The nsIPropertyBag to convert.
+ * @return Object
+ * Keyed on the names of the nsIProperty's within the nsIPropertyBag,
+ * and mapping to their values.
+ */
+function convertPropertyBag(aBag) {
+ let result = {};
+ let enumerator = aBag.enumerator;
+ while (enumerator.hasMoreElements()) {
+ let { name, value } = enumerator.getNext().QueryInterface(Ci.nsIProperty);
+ if (value instanceof Ci.nsIPropertyBag) {
+ value = convertPropertyBag(value);
+ }
+ result[name] = value;
+ }
+ return result;
+}
+
+add_task(function* setup() {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
+ // crash reports. This test needs them enabled. The test also needs a mock
+ // report server, and fortunately one is already set up by toolkit/
+ // crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
+ // which CrashSubmit.jsm uses as a server override.
+ let env = Cc["@mozilla.org/process/environment;1"].
+ getService(Components.interfaces.nsIEnvironment);
+ let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
+ let serverURL = env.get("MOZ_CRASHREPORTER_URL");
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+ env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ registerCleanupFunction(function cleanUp() {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
+ env.set("MOZ_CRASHREPORTER_URL", serverURL);
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ window.focus();
+ });
+});
+
+/**
+ * Test that plugin crash submissions still work properly after
+ * click-to-play activation.
+ */
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PLUGIN_PAGE,
+ }, function* (browser) {
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(browser);
+
+ let pluginInfo = yield promiseForPluginInfo("test", browser);
+ ok(!pluginInfo.activated, "Plugin should not be activated");
+
+ // Simulate clicking the "Allow Always" button.
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
+ yield promiseForNotificationShown(notification, browser);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // Prepare a crash report topic observer that only returns when
+ // the crash report has been successfully sent.
+ let crashReportChecker = (subject, data) => {
+ return (data == "success");
+ };
+ let crashReportPromise = TestUtils.topicObserved("crash-report-status",
+ crashReportChecker);
+
+ yield ContentTask.spawn(browser, null, function*() {
+ let plugin = content.document.getElementById("test");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+
+ yield ContentTaskUtils.waitForCondition(() => {
+ return plugin.activated;
+ }, "Waited too long for plugin to activate.");
+
+ try {
+ Components.utils.waiveXrays(plugin).crash();
+ } catch (e) {
+ }
+
+ let doc = plugin.ownerDocument;
+
+ let getUI = (anonid) => {
+ return doc.getAnonymousElementByAttribute(plugin, "anonid", anonid);
+ };
+
+ // Now wait until the plugin crash report UI shows itself, which is
+ // asynchronous.
+ let statusDiv;
+
+ yield ContentTaskUtils.waitForCondition(() => {
+ statusDiv = getUI("submitStatus");
+ return statusDiv.getAttribute("status") == "please";
+ }, "Waited too long for plugin to show crash report UI");
+
+ // Make sure the UI matches our expectations...
+ let style = content.getComputedStyle(getUI("pleaseSubmit"));
+ if (style.display != "block") {
+ throw new Error(`Submission UI visibility is not correct. ` +
+ `Expected block style, got ${style.display}.`);
+ }
+
+ // Fill the crash report in with some test values that we'll test for in
+ // the parent.
+ getUI("submitComment").value = "a test comment";
+ let optIn = getUI("submitURLOptIn");
+ if (!optIn.checked) {
+ throw new Error("URL opt-in should default to true.");
+ }
+
+ // Submit the report.
+ optIn.click();
+ getUI("submitButton").click();
+
+ // And wait for the parent to say that the crash report was submitted
+ // successfully.
+ yield ContentTaskUtils.waitForCondition(() => {
+ return statusDiv.getAttribute("status") == "success";
+ }, "Timed out waiting for plugin binding to be in success state");
+ });
+
+ let [subject, ] = yield crashReportPromise;
+
+ ok(subject instanceof Ci.nsIPropertyBag,
+ "The crash report subject should be an nsIPropertyBag.");
+
+ let crashData = convertPropertyBag(subject);
+ ok(crashData.serverCrashID, "Should have a serverCrashID set.");
+
+ // Remove the submitted report file after ensuring it exists.
+ let file = Cc["@mozilla.org/file/local;1"]
+ .createInstance(Ci.nsILocalFile);
+ file.initWithPath(Services.crashmanager._submittedDumpsDir);
+ file.append(crashData.serverCrashID + ".txt");
+ ok(file.exists(), "Submitted report file should exist");
+ file.remove(false);
+
+ ok(crashData.extra, "Extra data should exist");
+ is(crashData.extra.PluginUserComment, "a test comment",
+ "Comment in extra data should match comment in textbox");
+
+ is(crashData.extra.PluginContentURL, undefined,
+ "URL should be absent from extra data when opt-in not checked");
+ });
+});
+
+/**
+ * Test that plugin crash submissions still work properly after
+ * click-to-play with the notification bar.
+ */
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PLUGIN_SMALL_PAGE,
+ }, function* (browser) {
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(browser);
+
+ let pluginInfo = yield promiseForPluginInfo("test", browser);
+ ok(pluginInfo.activated, "Plugin should be activated from previous test");
+
+ // Prepare a crash report topic observer that only returns when
+ // the crash report has been successfully sent.
+ let crashReportChecker = (subject, data) => {
+ return (data == "success");
+ };
+ let crashReportPromise = TestUtils.topicObserved("crash-report-status",
+ crashReportChecker);
+
+ yield ContentTask.spawn(browser, null, function*() {
+ let plugin = content.document.getElementById("test");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+
+ yield ContentTaskUtils.waitForCondition(() => {
+ return plugin.activated;
+ }, "Waited too long for plugin to activate.");
+
+ try {
+ Components.utils.waiveXrays(plugin).crash();
+ } catch (e) {}
+ });
+
+ // Wait for the notification bar to be displayed.
+ let notification = yield waitForNotificationBar("plugin-crashed", browser);
+
+ // Then click the button to submit the crash report.
+ let buttons = notification.querySelectorAll(".notification-button");
+ is(buttons.length, 2, "Should have two buttons.");
+
+ // The "Submit Crash Report" button should be the second one.
+ let submitButton = buttons[1];
+ submitButton.click();
+
+ let [subject, ] = yield crashReportPromise;
+
+ ok(subject instanceof Ci.nsIPropertyBag,
+ "The crash report subject should be an nsIPropertyBag.");
+
+ let crashData = convertPropertyBag(subject);
+ ok(crashData.serverCrashID, "Should have a serverCrashID set.");
+
+ // Remove the submitted report file after ensuring it exists.
+ let file = Cc["@mozilla.org/file/local;1"]
+ .createInstance(Ci.nsILocalFile);
+ file.initWithPath(Services.crashmanager._submittedDumpsDir);
+ file.append(crashData.serverCrashID + ".txt");
+ ok(file.exists(), "Submitted report file should exist");
+ file.remove(false);
+
+ is(crashData.extra.PluginContentURL, undefined,
+ "URL should be absent from extra data when opt-in not checked");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_data_urls.js b/browser/base/content/test/plugins/browser_CTP_data_urls.js
new file mode 100644
index 000000000..0f4747b1e
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_data_urls.js
@@ -0,0 +1,255 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+});
+
+// Test that the click-to-play doorhanger still works when navigating to data URLs
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "Test 1a, Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 1a, plugin should not be activated");
+
+ let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ // navigate forward to a page with 'test' in it
+ content.document.getElementById("data-link-1").click();
+ });
+ yield loadPromise;
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "Test 1b, Should have a click-to-play notification");
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 1b, plugin should not be activated");
+
+ let promise = promisePopupNotification("click-to-play-plugins");
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ // Simulate clicking the "Allow Always" button.
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 1b, plugin should be activated");
+});
+
+// Test that the click-to-play notification doesn't break when navigating
+// to data URLs with multiple plugins.
+add_task(function* () {
+ // We click activated above
+ clearAllPluginPermissions();
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 2a, Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 2a, plugin should not be activated");
+
+ let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ // navigate forward to a page with 'test1' & 'test2' in it
+ content.document.getElementById("data-link-2").click();
+ });
+ yield loadPromise;
+
+ // Work around for delayed PluginBindingAttached
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ content.document.getElementById("test1").clientTop;
+ content.document.getElementById("test2").clientTop;
+ });
+
+ pluginInfo = yield promiseForPluginInfo("test1");
+ ok(!pluginInfo.activated, "Test 2a, test1 should not be activated");
+ pluginInfo = yield promiseForPluginInfo("test2");
+ ok(!pluginInfo.activated, "Test 2a, test2 should not be activated");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 2b, Should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ // Simulate choosing "Allow now" for the test plugin
+ is(notification.options.pluginData.size, 2, "Test 2b, Should have two types of plugin in the notification");
+
+ let centerAction = null;
+ for (let action of notification.options.pluginData.values()) {
+ if (action.pluginName == "Test") {
+ centerAction = action;
+ break;
+ }
+ }
+ ok(centerAction, "Test 2b, found center action for the Test plugin");
+
+ let centerItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ is(item.value, "block", "Test 2b, all plugins should start out blocked");
+ if (item.action == centerAction) {
+ centerItem = item;
+ break;
+ }
+ }
+ ok(centerItem, "Test 2b, found center item for the Test plugin");
+
+ // "click" the button to activate the Test plugin
+ centerItem.value = "allownow";
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test1");
+ ok(pluginInfo.activated, "Test 2b, plugin should be activated");
+});
+
+add_task(function* () {
+ // We click activated above
+ clearAllPluginPermissions();
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+});
+
+// Test that when navigating to a data url, the plugin permission is inherited
+add_task(function* () {
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 3a, Should have a click-to-play notification");
+
+ // check plugin state
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 3a, plugin should not be activated");
+
+ let promise = promisePopupNotification("click-to-play-plugins");
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ // Simulate clicking the "Allow Always" button.
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 3a, plugin should be activated");
+
+ let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ // navigate forward to a page with 'test' in it
+ content.document.getElementById("data-link-1").click();
+ });
+ yield loadPromise;
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 3b, plugin should be activated");
+
+ clearAllPluginPermissions();
+});
+
+// Test that the click-to-play doorhanger still works
+// when directly navigating to data URLs.
+// Fails, bug XXX. Plugins plus a data url don't fire a load event.
+/*
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab,
+ "data:text/html,Hi!<embed id='test' style='width:200px; height:200px' type='application/x-test'/>");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 4a, Should have a click-to-play notification");
+
+ // check plugin state
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 4a, plugin should not be activated");
+
+ let promise = promisePopupNotification("click-to-play-plugins");
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ // Simulate clicking the "Allow Always" button.
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 4a, plugin should be activated");
+});
+*/
diff --git a/browser/base/content/test/plugins/browser_CTP_drag_drop.js b/browser/base/content/test/plugins/browser_CTP_drag_drop.js
new file mode 100644
index 000000000..7c9858e27
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_drag_drop.js
@@ -0,0 +1,96 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gNewWindow = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gNewWindow.close();
+ gNewWindow = null;
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+});
+
+add_task(function* () {
+ gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
+
+ // XXX technically can't load fire before we get this call???
+ yield waitForEvent(gNewWindow, "load", null, true);
+
+ yield promisePopupNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
+
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
+ ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
+});
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, gNewWindow.gBrowser.selectedTab);
+
+ yield promisePopupNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab again");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+});
+
+add_task(function* () {
+ yield promisePopupNotification("click-to-play-plugins");
+
+ gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
+
+ yield promiseWaitForFocus(gNewWindow);
+
+ yield promisePopupNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
+});
+
+add_task(function* () {
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
+ ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
+
+ let pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
+ ok(!pluginInfo.activated, "plugin should not be activated");
+
+ yield ContentTask.spawn(gNewWindow.gBrowser.selectedBrowser, {}, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser).dismissed && gNewWindow.PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+});
+
+add_task(function* () {
+ // Click the activate button on doorhanger to make sure it works
+ gNewWindow.PopupNotifications.panel.firstChild._primaryButton.click();
+
+ let pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
+ ok(pluginInfo.activated, "plugin should be activated");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_hide_overlay.js b/browser/base/content/test/plugins/browser_CTP_hide_overlay.js
new file mode 100644
index 000000000..5fab7f6ed
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_hide_overlay.js
@@ -0,0 +1,88 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ // Tests that the overlay can be hidden for plugins using the close icon.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
+ let bounds = closeIcon.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+
+ Assert.ok(!overlay.classList.contains("visible"), "overlay should be hidden.");
+ });
+});
+
+// Test that the overlay cannot be interacted with after the user closes the overlay
+add_task(function* () {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
+ let closeIconBounds = closeIcon.getBoundingClientRect();
+ let overlayBounds = overlay.getBoundingClientRect();
+ let overlayLeft = (overlayBounds.left + overlayBounds.right) / 2;
+ let overlayTop = (overlayBounds.left + overlayBounds.right) / 2 ;
+ let closeIconLeft = (closeIconBounds.left + closeIconBounds.right) / 2;
+ let closeIconTop = (closeIconBounds.top + closeIconBounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ // Simulate clicking on the close icon.
+ utils.sendMouseEvent("mousedown", closeIconLeft, closeIconTop, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", closeIconLeft, closeIconTop, 0, 1, 0, false, 0, 0);
+
+ // Simulate clicking on the overlay.
+ utils.sendMouseEvent("mousedown", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
+
+ Assert.ok(overlay.hasAttribute("dismissed") && !overlay.classList.contains("visible"),
+ "Overlay should be hidden");
+ });
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+
+ ok(notification.dismissed, "No notification should be shown");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_iframe.js b/browser/base/content/test/plugins/browser_CTP_iframe.js
new file mode 100644
index 000000000..58565559f
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_iframe.js
@@ -0,0 +1,48 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_iframe.html");
+
+ // Tests that the overlays are visible and actionable if the plugin is in an iframe.
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+ let frame = content.document.getElementById("frame");
+ let doc = frame.contentDocument;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(plugin && overlay.classList.contains("visible"),
+ "Test 1, Plugin overlay should exist, not be hidden");
+
+ let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon");
+ let bounds = closeIcon.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = doc.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ Assert.ok(!overlay.classList.contains("visible"),
+ "Test 1, Plugin overlay should exist, be hidden");
+ });
+});
+
diff --git a/browser/base/content/test/plugins/browser_CTP_multi_allow.js b/browser/base/content/test/plugins/browser_CTP_multi_allow.js
new file mode 100644
index 000000000..7bc6aaabf
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_multi_allow.js
@@ -0,0 +1,99 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ // Test that the click-to-play doorhanger for multiple plugins shows the correct
+ // state when re-opening without reloads or navigation.
+
+ let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
+ ok(!pluginInfo.activated, "plugin should be activated");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(notification, "Test 1a, Should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ is(notification.options.pluginData.size, 2,
+ "Test 1a, Should have two types of plugin in the notification");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ is(PopupNotifications.panel.firstChild.childNodes.length, 2, "have child nodes");
+
+ let pluginItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ is(item.value, "block", "Test 1a, all plugins should start out blocked");
+ if (item.action.pluginName == "Test") {
+ pluginItem = item;
+ }
+ }
+
+ // Choose "Allow now" for the test plugin
+ pluginItem.value = "allownow";
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
+ ok(pluginInfo.activated, "plugin should be activated");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(notification, "Test 1b, Should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ pluginItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ if (item.action.pluginName == "Test") {
+ is(item.value, "allownow", "Test 1b, Test plugin should now be set to 'Allow now'");
+ } else {
+ is(item.value, "block", "Test 1b, Second Test plugin should still be blocked");
+ pluginItem = item;
+ }
+ }
+
+ // Choose "Allow and remember" for the Second Test plugin
+ pluginItem.value = "allowalways";
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("secondtestA", gBrowser.selectedBrowser);
+ ok(pluginInfo.activated, "plugin should be activated");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(notification, "Test 1c, Should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ if (item.action.pluginName == "Test") {
+ is(item.value, "allownow", "Test 1c, Test plugin should be set to 'Allow now'");
+ } else {
+ is(item.value, "allowalways", "Test 1c, Second Test plugin should be set to 'Allow always'");
+ }
+ }
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_nonplugins.js b/browser/base/content/test/plugins/browser_CTP_nonplugins.js
new file mode 100644
index 000000000..cdef44d9d
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_nonplugins.js
@@ -0,0 +1,58 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+
+ // Test that the click-to-play notification is not shown for non-plugin object elements
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(popupNotification, "Test 1, Should have a click-to-play notification");
+
+ let pluginRemovedPromise = waitForEvent(gBrowser.selectedBrowser, "PluginRemoved", null, true, true);
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+ let plugin = content.document.getElementById("secondtestA");
+ plugin.parentNode.removeChild(plugin);
+ plugin = content.document.getElementById("secondtestB");
+ plugin.parentNode.removeChild(plugin);
+
+ let image = content.document.createElement("object");
+ image.type = "image/png";
+ image.data = "moz.png";
+ content.document.body.appendChild(image);
+ });
+ yield pluginRemovedPromise;
+
+ popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(popupNotification, "Test 2, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.parentNode.removeChild(plugin);
+ });
+
+ popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
+ ok(popupNotification, "Test 3, Should still have a click-to-play notification");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_notificationBar.js b/browser/base/content/test/plugins/browser_CTP_notificationBar.js
new file mode 100644
index 000000000..3c7bd911c
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_notificationBar.js
@@ -0,0 +1,151 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ // Expecting a notification bar for hidden plugins
+ yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
+});
+
+add_task(function* () {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+ yield promiseForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null);
+});
+
+add_task(function* () {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_overlayed.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Expecting a plugin notification bar when plugins are overlaid.
+ yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_overlayed.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.equal(plugin.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 3b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+ });
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 1a, plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 3b, overlay should be hidden.");
+ });
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_positioned.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Expecting a plugin notification bar when plugins are overlaid offscreen.
+ yield promisePopupNotification("click-to-play-plugins");
+ yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.equal(plugin.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 4b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 4b, overlay should be hidden.");
+ });
+});
+
+// Test that the notification bar is getting dismissed when directly activating plugins
+// via the doorhanger.
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Expecting a plugin notification bar when plugins are overlaid offscreen.
+ yield promisePopupNotification("click-to-play-plugins");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.equal(plugin.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 6, Plugin should be click-to-play");
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 6, Should have a click-to-play notification");
+
+ // simulate "always allow"
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+ yield promiseForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 7, plugin should be activated");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_outsideScrollArea.js b/browser/base/content/test/plugins/browser_CTP_outsideScrollArea.js
new file mode 100644
index 000000000..ccb4d11d7
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_outsideScrollArea.js
@@ -0,0 +1,120 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
+});
+
+// Test that the click-to-play overlay is not hidden for elements
+// partially or fully outside the viewport.
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let doc = content.document;
+ let p = doc.createElement('embed');
+
+ p.setAttribute('id', 'test');
+ p.setAttribute('type', 'application/x-test');
+ p.style.left = "0";
+ p.style.bottom = "200px";
+
+ doc.getElementById('container').appendChild(p);
+ });
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ let doc = content.document;
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 2, overlay should be visible.");
+ });
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let doc = content.document;
+ let p = doc.createElement('embed');
+
+ p.setAttribute('id', 'test');
+ p.setAttribute('type', 'application/x-test');
+ p.style.left = "0";
+ p.style.bottom = "-410px";
+
+ doc.getElementById('container').appendChild(p);
+ });
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let doc = content.document;
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 3, overlay should be visible.");
+ });
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let doc = content.document;
+ let p = doc.createElement('embed');
+
+ p.setAttribute('id', 'test');
+ p.setAttribute('type', 'application/x-test');
+ p.style.left = "-600px";
+ p.style.bottom = "0";
+
+ doc.getElementById('container').appendChild(p);
+ });
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let doc = content.document;
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 4, overlay should be hidden.");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_remove_navigate.js b/browser/base/content/test/plugins/browser_CTP_remove_navigate.js
new file mode 100644
index 000000000..8ee1c5b5a
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_remove_navigate.js
@@ -0,0 +1,79 @@
+const gTestRoot = getRootDirectory(gTestPath);
+const gHttpTestRoot = gTestRoot.replace("chrome://mochitests/content/",
+ "http://127.0.0.1:8888/");
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ });
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+});
+
+/**
+ * Tests that if a plugin is removed just as we transition to
+ * a different page, that we don't show the hidden plugin
+ * notification bar on the new page.
+ */
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ // Load up a page with a plugin...
+ let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+ yield notificationPromise;
+
+ // Trigger the PluginRemoved event to be fired, and then immediately
+ // browse to a new page.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.remove();
+ });
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "about:mozilla");
+
+ // There should be no hidden plugin notification bar at about:mozilla.
+ let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
+ is(notificationBox.getNotificationWithValue("plugin-hidden"), null,
+ "Expected no notification box");
+});
+
+/**
+ * Tests that if a plugin is removed just as we transition to
+ * a different page with a plugin, that we show the right notification
+ * for the new page.
+ */
+add_task(function* () {
+ // Load up a page with a plugin...
+ let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
+ yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
+ yield notificationPromise;
+
+ // Trigger the PluginRemoved event to be fired, and then immediately
+ // browse to a new page.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.remove();
+ });
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small_2.html");
+ let notification = yield waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
+ ok(notification, "There should be a notification shown for the new page.");
+ // Ensure that the notification is showing information about
+ // the x-second-test plugin.
+ let label = notification.label;
+ ok(label.includes("Second Test"), "Should mention the second plugin");
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_resize.js b/browser/base/content/test/plugins/browser_CTP_resize.js
new file mode 100644
index 000000000..9b2a2cd82
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_resize.js
@@ -0,0 +1,130 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
+
+ yield promiseTabLoadEvent(newTab, gTestRoot + "plugin_small.html"); // 10x10 plugin
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+});
+
+// Test that the overlay is hidden for "small" plugin elements and is shown
+// once they are resized to a size that can hold the overlay
+add_task(function* () {
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "Test 2, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 2, overlay should be hidden.");
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.style.width = "300px";
+ });
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 3, overlay should be hidden.");
+ });
+});
+
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.style.height = "300px";
+ });
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ content.document.getElementById("test").clientTop;
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 4, overlay should be visible.");
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.style.width = "10px";
+ plugin.style.height = "10px";
+ });
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ content.document.getElementById("test").clientTop;
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!(overlay && overlay.classList.contains("visible")),
+ "Test 5, overlay should be hidden.");
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ plugin.style.height = "300px";
+ plugin.style.width = "300px";
+ });
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ content.document.getElementById("test").clientTop;
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 6, overlay should be visible.");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_CTP_zoom.js b/browser/base/content/test/plugins/browser_CTP_zoom.js
new file mode 100644
index 000000000..8b353232d
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_CTP_zoom.js
@@ -0,0 +1,62 @@
+"use strict";
+
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ FullZoom.reset(); // must be called before closing the tab we zoomed!
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_zoom.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+});
+
+// Enlarges the zoom level 4 times and tests that the overlay is
+// visible after each enlargement.
+add_task(function* () {
+ for (let count = 0; count < 4; count++) {
+
+ FullZoom.enlarge();
+
+ // Reload the page
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_zoom.html");
+ yield promiseUpdatePluginBindings(gTestBrowser);
+ yield ContentTask.spawn(gTestBrowser, { count }, function* (args) {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Overlay should be visible for zoom change count " + args.count);
+ });
+ }
+});
+
+
diff --git a/browser/base/content/test/plugins/browser_blocking.js b/browser/base/content/test/plugins/browser_blocking.js
new file mode 100644
index 000000000..334ed9f2e
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_blocking.js
@@ -0,0 +1,349 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+function updateAllTestPlugins(aState) {
+ setTestPluginEnabledState(aState, "Test Plug-in");
+ setTestPluginEnabledState(aState, "Second Test Plug-in");
+}
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_ENABLED);
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ }));
+});
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ // Prime the content process
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
+
+ // Make sure the blocklist service(s) are running
+ Components.classes["@mozilla.org/extensions/blocklist;1"]
+ .getService(Components.interfaces.nsIBlocklistService);
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+});
+
+add_task(function* () {
+ // enable hard blocklisting for the next test
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+ ok(notification.dismissed, "Test 5: The plugin notification should be dismissed by default");
+
+ yield promiseForNotificationShown(notification);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED, "Test 5, plugin fallback type should be PLUGIN_BLOCKLISTED");
+
+ is(notification.options.pluginData.size, 1, "Test 5: Only the blocked plugin should be present in the notification");
+ ok(PopupNotifications.panel.firstChild._buttonContainer.hidden, "Part 5: The blocked plugins notification should not have any buttons visible.");
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
+
+// Tests a vulnerable, updatable plugin
+
+add_task(function* () {
+ // enable hard blocklisting of test
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
+ "Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
+ ok(!pluginInfo.activated, "Test 18a, Plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 18a, Plugin overlay should exist, not be hidden");
+
+ let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
+ Assert.ok(updateLink.style.visibility != "hidden",
+ "Test 18a, Plugin should have an update link");
+ });
+
+ let promise = waitForEvent(gBrowser.tabContainer, "TabOpen", null, true);
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
+ let bounds = updateLink.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ promise = waitForEvent(gBrowser.tabContainer, "TabClose", null, true);
+ gBrowser.removeCurrentTab();
+ yield promise;
+});
+
+add_task(function* () {
+ // clicking the update link should not activate the plugin
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
+ "Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
+ ok(!pluginInfo.activated, "Test 18b, Plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 18b, Plugin overlay should exist, not be hidden");
+ });
+});
+
+// Tests a vulnerable plugin with no update
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableNoUpdate.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 18c, Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
+ "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
+ ok(!pluginInfo.activated, "Test 18c, Plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(overlay && overlay.classList.contains("visible"),
+ "Test 18c, Plugin overlay should exist, not be hidden");
+
+ let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
+ Assert.ok(updateLink && updateLink.style.display != "block",
+ "Test 18c, Plugin should not have an update link");
+ });
+
+ // check that click "Always allow" works with blocked plugins
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
+ "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
+ ok(pluginInfo.activated, "Test 18c, Plugin should be activated");
+ let enabledState = getTestPluginEnabledState();
+ ok(enabledState, "Test 18c, Plugin enabled state should be STATE_CLICKTOPLAY");
+});
+
+// continue testing "Always allow", make sure it sticks.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 18d, Waited too long for plugin to activate");
+
+ clearAllPluginPermissions();
+});
+
+// clicking the in-content overlay of a vulnerable plugin should bring
+// up the notification and not directly activate the plugin
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 18f, Should have a click-to-play notification");
+ ok(notification.dismissed, "Test 18f, notification should start dismissed");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 18f, Waited too long for plugin to activate");
+
+ var oldEventCallback = notification.options.eventCallback;
+ let promise = promiseForCondition(() => oldEventCallback == null);
+ notification.options.eventCallback = function() {
+ if (oldEventCallback) {
+ oldEventCallback();
+ }
+ oldEventCallback = null;
+ };
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ ok(notification, "Test 18g, Should have a click-to-play notification");
+ ok(!notification.dismissed, "Test 18g, notification should be open");
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
+});
+
+// Test that "always allow"-ing a plugin will not allow it when it becomes
+// blocklisted.
+add_task(function* () {
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 24a, Should have a click-to-play notification");
+
+ // Plugin should start as CTP
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 24a, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+ ok(!pluginInfo.activated, "Test 24a, Plugin should not be active.");
+
+ // simulate "always allow"
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 24a, Plugin should be active.");
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
+});
+
+// the plugin is now blocklisted, so it should not automatically load
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 24b, Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
+ "Test 24b, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
+ ok(!pluginInfo.activated, "Test 24b, Plugin should not be active.");
+
+ // simulate "always allow"
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 24b, Plugin should be active.");
+
+ clearAllPluginPermissions();
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
+
+// Plugin sync removal test. Note this test produces a notification drop down since
+// the plugin we add has zero dims.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_syncRemoved.html");
+
+ // Maybe there some better trick here, we need to wait for the page load, then
+ // wait for the js to execute in the page.
+ yield waitForMs(500);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+ ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed");
+ ok(notification.dismissed, "Test 25: The notification should be dismissed by default");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
+});
+
+// Tests a page with a blocked plugin in it and make sure the infoURL property
+// the blocklist file gets used.
+add_task(function* () {
+ clearAllPluginPermissions();
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginInfoURL.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+
+ // Since the plugin notification is dismissed by default, reshow it.
+ yield promiseForNotificationShown(notification);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED,
+ "Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(!objLoadingContent.activated, "Plugin should not be activated.");
+ });
+
+ const testUrl = "http://test.url.com/";
+
+ let firstPanelChild = PopupNotifications.panel.firstChild;
+ let infoLink = document.getAnonymousElementByAttribute(firstPanelChild, "anonid",
+ "click-to-play-plugins-notification-link");
+ is(infoLink.href, testUrl,
+ "Test 26, the notification URL needs to match the infoURL from the blocklist file.");
+});
+
diff --git a/browser/base/content/test/plugins/browser_blocklist_content.js b/browser/base/content/test/plugins/browser_blocklist_content.js
new file mode 100644
index 000000000..bf4e159bc
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_blocklist_content.js
@@ -0,0 +1,104 @@
+var gTestBrowser = null;
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gChromeRoot = getRootDirectory(gTestPath);
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ }));
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+
+ // Prime the blocklist service, the remote service doesn't launch on startup.
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let test = content.document.getElementById("test");
+ Assert.ok(test.activated, "task 1a: test plugin should be activated!");
+ });
+});
+
+// Load a fresh page, load a new plugin blocklist, then load the same page again.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let test = content.document.getElementById("test");
+ ok(!test.activated, "task 2a: test plugin shouldn't activate!");
+ });
+});
+
+// Unload the block list and lets do this again, only this time lets
+// hack around in the content blocklist service maliciously.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+
+ // Hack the planet! Load our blocklist shim, so we can mess with blocklist
+ // return results in the content process. Active until we close our tab.
+ let mm = gTestBrowser.messageManager;
+ info("test 3a: loading " + gChromeRoot + "blocklist_proxy.js" + "\n");
+ mm.loadFrameScript(gChromeRoot + "blocklist_proxy.js", true);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let test = content.document.getElementById("test");
+ Assert.ok(test.activated, "task 3a: test plugin should be activated!");
+ });
+});
+
+// Load a fresh page, load a new plugin blocklist, then load the same page again.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let test = content.document.getElementById("test");
+ Assert.ok(!test.activated, "task 4a: test plugin shouldn't activate!");
+ });
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
diff --git a/browser/base/content/test/plugins/browser_bug743421.js b/browser/base/content/test/plugins/browser_bug743421.js
new file mode 100644
index 000000000..966e7b012
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug743421.js
@@ -0,0 +1,119 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ }));
+});
+
+add_task(function* () {
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ // Prime the blocklist service, the remote service doesn't launch on startup.
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
+
+// Tests that navigation within the page and the window.history API doesn't break click-to-play state.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!notification, "Test 1a, Should not have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementsByTagName("embed")[0];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
+ });
+
+ // Click the activate button on doorhanger to make sure it works
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementsByTagName("embed")[0];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
+ });
+});
+
+add_task(function* () {
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 1c, Should still have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
+ let plugin = content.document.getElementsByTagName("embed")[1];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated,
+ "Test 1c, Newly inserted plugin in activated page should be activated");
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementsByTagName("embed")[1];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated, "Test 1d, Plugin should be activated");
+
+ let promise = ContentTaskUtils.waitForEvent(content, "hashchange");
+ content.location += "#anchorNavigation";
+ yield promise;
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
+ let plugin = content.document.getElementsByTagName("embed")[2];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated, "Test 1e, Plugin should be activated");
+ });
+});
+
+add_task(function* () {
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementsByTagName("embed")[2];
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated, "Test 1f, Plugin should be activated");
+
+ content.history.replaceState({}, "", "replacedState");
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
+ plugin = content.document.getElementsByTagName("embed")[3];
+ objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ Assert.ok(objLoadingContent.activated, "Test 1g, Plugin should be activated");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_bug744745.js b/browser/base/content/test/plugins/browser_bug744745.js
new file mode 100644
index 000000000..c9f552a4e
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug744745.js
@@ -0,0 +1,50 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gNumPluginBindingsAttached = 0;
+
+function pluginBindingAttached() {
+ gNumPluginBindingsAttached++;
+ if (gNumPluginBindingsAttached != 1) {
+ ok(false, "if we've gotten here, something is quite wrong");
+ }
+}
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
+
+ let testRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+ yield promiseTabLoadEvent(gBrowser.selectedTab, testRoot + "plugin_bug744745.html");
+
+ yield promiseForCondition(function () { return gNumPluginBindingsAttached == 1; });
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("test");
+ if (!plugin) {
+ Assert.ok(false, "plugin element not available.");
+ return;
+ }
+ // We can't use MochiKit's routine
+ let style = content.getComputedStyle(plugin);
+ Assert.ok(("opacity" in style) && style.opacity == 1, "plugin style properly configured.");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_bug787619.js b/browser/base/content/test/plugins/browser_bug787619.js
new file mode 100644
index 000000000..bfd52258c
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug787619.js
@@ -0,0 +1,65 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gWrapperClickCount = 0;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ let testRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+ yield promiseTabLoadEvent(gBrowser.selectedTab, testRoot + "plugin_bug787619.html");
+
+ // Due to layout being async, "PluginBindAttached" may trigger later.
+ // This forces a layout flush, thus triggering it, and schedules the
+ // test so it is definitely executed afterwards.
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // check plugin state
+ let pluginInfo = yield promiseForPluginInfo("plugin");
+ ok(!pluginInfo.activated, "1a plugin should not be activated");
+
+ // click the overlay to prompt
+ let promise = promisePopupNotification("click-to-play-plugins");
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ let plugin = content.document.getElementById("plugin");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+ yield promise;
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("plugin");
+ ok(!pluginInfo.activated, "1b plugin should not be activated");
+
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ // check plugin state
+ pluginInfo = yield promiseForPluginInfo("plugin");
+ ok(pluginInfo.activated, "plugin should be activated");
+
+ is(gWrapperClickCount, 0, 'wrapper should not have received any clicks');
+});
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 000000000..1ae9f5047
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug797677.js
@@ -0,0 +1,43 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gConsoleErrors = 0;
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ consoleService.unregisterListener(errorListener);
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ let consoleService = Cc["@mozilla.org/consoleservice;1"]
+ .getService(Ci.nsIConsoleService);
+ let errorListener = {
+ observe: function(aMessage) {
+ if (aMessage.message.includes("NS_ERROR_FAILURE"))
+ gConsoleErrors++;
+ }
+ };
+ consoleService.registerListener(errorListener);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug797677.html");
+
+ let pluginInfo = yield promiseForPluginInfo("plugin");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "plugin should not have been found.");
+
+ // simple cpows
+ yield ContentTask.spawn(gTestBrowser, null, 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_bug812562.js b/browser/base/content/test/plugins/browser_bug812562.js
new file mode 100644
index 000000000..be7b00b22
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug812562.js
@@ -0,0 +1,80 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ }));
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ // Prime the blocklist service, the remote service doesn't launch on startup.
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+});
+
+// Tests that the going back will reshow the notification for click-to-play
+// blocklisted plugins
+add_task(function* () {
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "test part 1: Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "plugin should be marked as VULNERABLE");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ Assert.ok(!!content.document.getElementById("test"),
+ "test part 1: plugin should not be activated");
+ });
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+});
+
+add_task(function* () {
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!popupNotification, "test part 2: Should not have a click-to-play notification");
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ Assert.ok(!content.document.getElementById("test"),
+ "test part 2: plugin should not be activated");
+ });
+
+ let obsPromise = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
+ let overlayPromise = promisePopupNotification("click-to-play-plugins");
+ gTestBrowser.goBack();
+ yield obsPromise;
+ yield overlayPromise;
+});
+
+add_task(function* () {
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "test part 3: Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "plugin should be marked as VULNERABLE");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ Assert.ok(!!content.document.getElementById("test"),
+ "test part 3: plugin should not be activated");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_bug818118.js b/browser/base/content/test/plugins/browser_bug818118.js
new file mode 100644
index 000000000..9dd6e22e7
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug818118.js
@@ -0,0 +1,40 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_both.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "plugin should be click to play");
+ ok(!pluginInfo.activated, "plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, () => {
+ let unknown = content.document.getElementById("unknown");
+ ok(unknown, "should have unknown plugin in page");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_bug820497.js b/browser/base/content/test/plugins/browser_bug820497.js
new file mode 100644
index 000000000..b2e0f5268
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_bug820497.js
@@ -0,0 +1,71 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var gNumPluginBindingsAttached = 0;
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ gTestBrowser.addEventListener("PluginBindingAttached", function () { gNumPluginBindingsAttached++ }, true, true);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug820497.html");
+
+ yield promiseForCondition(function () { return gNumPluginBindingsAttached == 1; });
+
+ yield ContentTask.spawn(gTestBrowser, null, () => {
+ // Note we add the second plugin in the code farther down, so there's
+ // no way we got here with anything but one plugin loaded.
+ let doc = content.document;
+ let testplugin = doc.getElementById("test");
+ ok(testplugin, "should have test plugin");
+ let secondtestplugin = doc.getElementById("secondtest");
+ ok(!secondtestplugin, "should not yet have second test plugin");
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ is(notification.options.pluginData.size, 1, "should be 1 type of plugin in the popup notification");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ XPCNativeWrapper.unwrap(content).addSecondPlugin();
+ });
+
+ yield promiseForCondition(function () { return gNumPluginBindingsAttached == 2; });
+
+ yield ContentTask.spawn(gTestBrowser, null, () => {
+ let doc = content.document;
+ let testplugin = doc.getElementById("test");
+ ok(testplugin, "should have test plugin");
+ let secondtestplugin = doc.getElementById("secondtest");
+ ok(secondtestplugin, "should have second test plugin");
+ });
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+
+ ok(notification, "should have popup notification");
+
+ yield promiseForNotificationShown(notification);
+
+ is(notification.options.pluginData.size, 2, "aited too long for 2 types of plugins in popup notification");
+});
diff --git a/browser/base/content/test/plugins/browser_clearplugindata.html b/browser/base/content/test/plugins/browser_clearplugindata.html
new file mode 100644
index 000000000..243350ba4
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_clearplugindata.html
@@ -0,0 +1,30 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <title>Plugin Clear Site Data sanitize test</title>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+ <script type="application/javascript">
+ function testSteps()
+ {
+ // Make sure clearing by timerange is supported.
+ var p = document.getElementById("plugin1");
+ p.setSitesWithDataCapabilities(true);
+
+ p.setSitesWithData(
+ "foo.com:0:5," +
+ "bar.com:0:100," +
+ "baz.com:1:5," +
+ "qux.com:1:100"
+ );
+ }
+ </script>
+ </head>
+
+ <body onload="testSteps();"></body>
+
+</html>
diff --git a/browser/base/content/test/plugins/browser_clearplugindata.js b/browser/base/content/test/plugins/browser_clearplugindata.js
new file mode 100644
index 000000000..69d474fed
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_clearplugindata.js
@@ -0,0 +1,127 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+var gTestBrowser = null;
+
+// Test clearing plugin data using sanitize.js.
+const testURL1 = gTestRoot + "browser_clearplugindata.html";
+const testURL2 = gTestRoot + "browser_clearplugindata_noage.html";
+
+var tempScope = {};
+Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
+ .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
+var Sanitizer = tempScope.Sanitizer;
+
+const pluginHostIface = Ci.nsIPluginHost;
+var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+pluginHost.QueryInterface(pluginHostIface);
+
+var pluginTag = getTestPlugin();
+var sanitizer = null;
+
+function stored(needles) {
+ let something = pluginHost.siteHasData(this.pluginTag, null);
+ if (!needles)
+ return something;
+
+ if (!something)
+ return false;
+
+ for (let i = 0; i < needles.length; ++i) {
+ if (!pluginHost.siteHasData(this.pluginTag, needles[i]))
+ return false;
+ }
+ return true;
+}
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ if (gTestBrowser) {
+ gBrowser.removeCurrentTab();
+ }
+ window.focus();
+ gTestBrowser = null;
+ });
+});
+
+add_task(function* () {
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+
+ sanitizer = new Sanitizer();
+ sanitizer.ignoreTimespan = false;
+ sanitizer.prefDomain = "privacy.cpd.";
+ let itemPrefs = gPrefService.getBranch(sanitizer.prefDomain);
+ itemPrefs.setBoolPref("history", false);
+ itemPrefs.setBoolPref("downloads", false);
+ itemPrefs.setBoolPref("cache", false);
+ itemPrefs.setBoolPref("cookies", true); // plugin data
+ itemPrefs.setBoolPref("formdata", false);
+ itemPrefs.setBoolPref("offlineApps", false);
+ itemPrefs.setBoolPref("passwords", false);
+ itemPrefs.setBoolPref("sessions", false);
+ itemPrefs.setBoolPref("siteSettings", false);
+});
+
+add_task(function* () {
+ // Load page to set data for the plugin.
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, testURL1);
+
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ ok(stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
+ "Data stored for sites");
+
+ // Clear 20 seconds ago
+ let now_uSec = Date.now() * 1000;
+ sanitizer.range = [now_uSec - 20*1000000, now_uSec];
+ yield sanitizer.sanitize();
+
+ ok(stored(["bar.com", "qux.com"]), "Data stored for sites");
+ ok(!stored(["foo.com"]), "Data cleared for foo.com");
+ ok(!stored(["baz.com"]), "Data cleared for baz.com");
+
+ // Clear everything
+ sanitizer.range = null;
+ yield sanitizer.sanitize();
+
+ ok(!stored(null), "All data cleared");
+
+ gBrowser.removeCurrentTab();
+ gTestBrowser = null;
+});
+
+add_task(function* () {
+ // Load page to set data for the plugin.
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, testURL2);
+
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ ok(stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
+ "Data stored for sites");
+
+ // Attempt to clear 20 seconds ago. The plugin will throw
+ // NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, which should result in us
+ // clearing all data regardless of age.
+ let now_uSec = Date.now() * 1000;
+ sanitizer.range = [now_uSec - 20*1000000, now_uSec];
+ yield sanitizer.sanitize();
+
+ ok(!stored(null), "All data cleared");
+
+ gBrowser.removeCurrentTab();
+ gTestBrowser = null;
+});
+
diff --git a/browser/base/content/test/plugins/browser_clearplugindata_noage.html b/browser/base/content/test/plugins/browser_clearplugindata_noage.html
new file mode 100644
index 000000000..820979541
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_clearplugindata_noage.html
@@ -0,0 +1,30 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <title>Plugin Clear Site Data sanitize test without age</title>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+ <script type="application/javascript">
+ function testSteps()
+ {
+ // Make sure clearing by timerange is disabled.
+ var p = document.getElementById("plugin1");
+ p.setSitesWithDataCapabilities(false);
+
+ p.setSitesWithData(
+ "foo.com:0:5," +
+ "bar.com:0:100," +
+ "baz.com:1:5," +
+ "qux.com:1:100"
+ );
+ }
+ </script>
+ </head>
+
+ <body onload="testSteps();"></body>
+
+</html>
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 000000000..bdca32e70
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js
@@ -0,0 +1,34 @@
+/**
+ * Test that the notification bar for crashed GMPs works.
+ */
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, function* (browser) {
+ yield ContentTask.spawn(browser, null, 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 = yield 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.getAttribute("label"),
+ "The GlobalTestPlugin plugin has crashed.",
+ "Correct message.");
+ });
+});
diff --git a/browser/base/content/test/plugins/browser_pageInfo_plugins.js b/browser/base/content/test/plugins/browser_pageInfo_plugins.js
new file mode 100644
index 000000000..0d941e0fa
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_pageInfo_plugins.js
@@ -0,0 +1,191 @@
+var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPageInfo = null;
+var gNextTest = null;
+var gTestBrowser = null;
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"]
+ .getService(Components.interfaces.nsIPluginHost);
+var gPermissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
+ .getService(Components.interfaces.nsIPermissionManager);
+var gTestPermissionString = gPluginHost.getPermissionStringForType("application/x-test");
+var gSecondTestPermissionString = gPluginHost.getPermissionStringForType("application/x-second-test");
+
+function doOnPageLoad(url, continuation) {
+ gNextTest = continuation;
+ gTestBrowser.addEventListener("load", pageLoad, true);
+ gTestBrowser.contentWindow.location = url;
+}
+
+function pageLoad() {
+ gTestBrowser.removeEventListener("load", pageLoad);
+ // The plugin events are async dispatched and can come after the load event
+ // This just allows the events to fire before we then go on to test the states
+ executeSoon(gNextTest);
+}
+
+function doOnOpenPageInfo(continuation) {
+ Services.obs.addObserver(pageInfoObserve, "page-info-dialog-loaded", false);
+ gNextTest = continuation;
+ // An explanation: it looks like the test harness complains about leaked
+ // windows if we don't keep a reference to every window we've opened.
+ // So, don't reuse pointers to opened Page Info windows - simply append
+ // to this list.
+ gPageInfo = BrowserPageInfo(null, "permTab");
+}
+
+function pageInfoObserve(win, topic, data) {
+ Services.obs.removeObserver(pageInfoObserve, "page-info-dialog-loaded");
+ gPageInfo.onFinished.push(() => executeSoon(gNextTest));
+}
+
+function finishTest() {
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ gBrowser.removeCurrentTab();
+
+ gPageInfo = null;
+ gNextTest = null;
+ gTestBrowser = null;
+ gPluginHost = null;
+ gPermissionManager = null;
+
+ executeSoon(finish);
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
+ doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart1a);
+}
+
+// The first test plugin is CtP and the second test plugin is enabled.
+function testPart1a() {
+ let test = gTestBrowser.contentDocument.getElementById("test");
+ let objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!objLoadingContent.activated, "part 1a: Test plugin should not be activated");
+ let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA");
+ objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(objLoadingContent.activated, "part 1a: Second Test plugin should be activated");
+
+ doOnOpenPageInfo(testPart1b);
+}
+
+function testPart1b() {
+ let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
+ let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
+
+ is(testRadioGroup.selectedItem, testRadioDefault, "part 1b: Test radio group should be set to 'Default'");
+ let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
+ testRadioGroup.selectedItem = testRadioAllow;
+ testRadioAllow.doCommand();
+
+ let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
+ let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
+ is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 1b: Second Test radio group should be set to 'Default'");
+ let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
+ secondtestRadioGroup.selectedItem = secondtestRadioAsk;
+ secondtestRadioAsk.doCommand();
+
+ doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart2);
+}
+
+// Now, the Test plugin should be allowed, and the Test2 plugin should be CtP
+function testPart2() {
+ let test = gTestBrowser.contentDocument.getElementById("test").
+ QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(test.activated, "part 2: Test plugin should be activated");
+
+ let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
+ QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!secondtest.activated, "part 2: Second Test plugin should not be activated");
+ is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "part 2: Second test plugin should be click-to-play.");
+
+ let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
+ let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
+ is(testRadioGroup.selectedItem, testRadioAllow, "part 2: Test radio group should be set to 'Allow'");
+ let testRadioBlock = gPageInfo.document.getElementById(gTestPermissionString + "#2");
+ testRadioGroup.selectedItem = testRadioBlock;
+ testRadioBlock.doCommand();
+
+ let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
+ let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
+ is(secondtestRadioGroup.selectedItem, secondtestRadioAsk, "part 2: Second Test radio group should be set to 'Always Ask'");
+ let secondtestRadioBlock = gPageInfo.document.getElementById(gSecondTestPermissionString + "#2");
+ secondtestRadioGroup.selectedItem = secondtestRadioBlock;
+ secondtestRadioBlock.doCommand();
+
+ doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart3);
+}
+
+// Now, all the things should be blocked
+function testPart3() {
+ let test = gTestBrowser.contentDocument.getElementById("test").
+ QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!test.activated, "part 3: Test plugin should not be activated");
+ is(test.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
+ "part 3: Test plugin should be marked as PLUGIN_DISABLED");
+
+ let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
+ QueryInterface(Ci.nsIObjectLoadingContent);
+
+ ok(!secondtest.activated, "part 3: Second Test plugin should not be activated");
+ is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
+ "part 3: Second test plugin should be marked as PLUGIN_DISABLED");
+
+ // reset permissions
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
+ gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
+ // check that changing the permissions affects the radio state in the
+ // open Page Info window
+ let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
+ let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
+ is(testRadioGroup.selectedItem, testRadioDefault, "part 3: Test radio group should be set to 'Default'");
+ let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
+ let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
+ is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 3: Second Test radio group should be set to 'Default'");
+
+ doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart4a);
+}
+
+// Now test that setting permission directly (as from the popup notification)
+// immediately influences Page Info.
+function testPart4a() {
+ // simulate "allow" from the doorhanger
+ gPermissionManager.add(gTestBrowser.currentURI, gTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
+ gPermissionManager.add(gTestBrowser.currentURI, gSecondTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
+
+ // check (again) that changing the permissions affects the radio state in the
+ // open Page Info window
+ let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
+ let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
+ is(testRadioGroup.selectedItem, testRadioAllow, "part 4a: Test radio group should be set to 'Allow'");
+ let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
+ let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
+ is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4a: Second Test radio group should be set to 'Always Allow'");
+
+ // now close Page Info and see that it opens with the right settings
+ gPageInfo.close();
+ doOnOpenPageInfo(testPart4b);
+}
+
+// check that "always allow" resulted in the radio buttons getting set to allow
+function testPart4b() {
+ let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
+ let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
+ is(testRadioGroup.selectedItem, testRadioAllow, "part 4b: Test radio group should be set to 'Allow'");
+
+ let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
+ let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
+ is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4b: Second Test radio group should be set to 'Allow'");
+
+ Services.prefs.setBoolPref("plugins.click_to_play", false);
+ gPageInfo.close();
+ finishTest();
+}
diff --git a/browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js b/browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js
new file mode 100644
index 000000000..ab4743f6f
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js
@@ -0,0 +1,207 @@
+Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
+
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gTestBrowser = null;
+var config = {};
+
+add_task(function* () {
+ // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
+ // crash reports. This test needs them enabled. The test also needs a mock
+ // report server, and fortunately one is already set up by toolkit/
+ // crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
+ // which CrashSubmit.jsm uses as a server override.
+ let env = Components.classes["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
+ let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+ env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ // Crash immediately
+ Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 0);
+
+ registerCleanupFunction(Task.async(function*() {
+ Services.prefs.clearUserPref("dom.ipc.plugins.timeoutSecs");
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
+ env.set("MOZ_CRASHREPORTER_URL", serverUrl);
+ env = null;
+ config = null;
+ gTestBrowser = null;
+ gBrowser.removeCurrentTab();
+ window.focus();
+ }));
+});
+
+add_task(function* () {
+ config = {
+ shouldSubmissionUIBeVisible: true,
+ comment: "",
+ urlOptIn: false
+ };
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
+
+ let pluginCrashed = promisePluginCrashed();
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Wait for the plugin to crash
+ yield pluginCrashed;
+
+ let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
+
+ // Test that the crash submission UI is actually visible and submit the crash report.
+ yield ContentTask.spawn(gTestBrowser, config, function* (aConfig) {
+ let doc = content.document;
+ let plugin = doc.getElementById("plugin");
+ let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
+ let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
+ // Test that we don't send the URL when urlOptIn is false.
+ doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
+ submitButton.click();
+ Assert.equal(content.getComputedStyle(pleaseSubmit).display == "block",
+ aConfig.shouldSubmissionUIBeVisible, "The crash UI should be visible");
+ });
+
+ yield crashReportStatus;
+});
+
+add_task(function* () {
+ config = {
+ shouldSubmissionUIBeVisible: true,
+ comment: "a test comment",
+ urlOptIn: true
+ };
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
+
+ let pluginCrashed = promisePluginCrashed();
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Wait for the plugin to crash
+ yield pluginCrashed;
+
+ let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
+
+ // Test that the crash submission UI is actually visible and submit the crash report.
+ yield ContentTask.spawn(gTestBrowser, config, function* (aConfig) {
+ let doc = content.document;
+ let plugin = doc.getElementById("plugin");
+ let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
+ let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
+ // Test that we send the URL when urlOptIn is true.
+ doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
+ doc.getAnonymousElementByAttribute(plugin, "anonid", "submitComment").value = aConfig.comment;
+ submitButton.click();
+ Assert.equal(content.getComputedStyle(pleaseSubmit).display == "block",
+ aConfig.shouldSubmissionUIBeVisible, "The crash UI should be visible");
+ });
+
+ yield crashReportStatus;
+});
+
+add_task(function* () {
+ config = {
+ shouldSubmissionUIBeVisible: false,
+ comment: "",
+ urlOptIn: true
+ };
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
+
+ let pluginCrashed = promisePluginCrashed();
+
+ // Make sure that the plugin container is too small to display the crash submission UI
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html?" +
+ encodeURIComponent(JSON.stringify({width: 300, height: 300})));
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ // Wait for the plugin to crash
+ yield pluginCrashed;
+
+ // Test that the crash submission UI is not visible and do not submit a crash report.
+ yield ContentTask.spawn(gTestBrowser, config, function* (aConfig) {
+ let doc = content.document;
+ let plugin = doc.getElementById("plugin");
+ let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
+ Assert.equal(!!pleaseSubmit && content.getComputedStyle(pleaseSubmit).display == "block",
+ aConfig.shouldSubmissionUIBeVisible, "Plugin crash UI should not be visible");
+ });
+});
+
+function promisePluginCrashed() {
+ return new ContentTask.spawn(gTestBrowser, {}, function* () {
+ yield new Promise((resolve) => {
+ addEventListener("PluginCrashReporterDisplayed", function onPluginCrashed() {
+ removeEventListener("PluginCrashReporterDisplayed", onPluginCrashed);
+ resolve();
+ });
+ });
+ })
+}
+
+function onSubmitStatus(aSubject, aData) {
+ // Wait for success or failed, doesn't matter which.
+ if (aData != "success" && aData != "failed")
+ return false;
+
+ let propBag = aSubject.QueryInterface(Ci.nsIPropertyBag);
+ if (aData == "success") {
+ let remoteID = getPropertyBagValue(propBag, "serverCrashID");
+ ok(!!remoteID, "serverCrashID should be set");
+
+ // Remove the submitted report file.
+ let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+ file.initWithPath(Services.crashmanager._submittedDumpsDir);
+ file.append(remoteID + ".txt");
+ ok(file.exists(), "Submitted report file should exist");
+ file.remove(false);
+ }
+
+ let extra = getPropertyBagValue(propBag, "extra");
+ ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
+
+ let val = getPropertyBagValue(extra, "PluginUserComment");
+ if (config.comment)
+ is(val, config.comment,
+ "Comment in extra data should match comment in textbox");
+ else
+ ok(val === undefined,
+ "Comment should be absent from extra data when textbox is empty");
+
+ val = getPropertyBagValue(extra, "PluginContentURL");
+ if (config.urlOptIn)
+ is(val, gBrowser.currentURI.spec,
+ "URL in extra data should match browser URL when opt-in checked");
+ else
+ ok(val === undefined,
+ "URL should be absent from extra data when opt-in not checked");
+
+ return true;
+}
+
+function getPropertyBagValue(bag, key) {
+ try {
+ var val = bag.getProperty(key);
+ }
+ catch (e) {
+ if (e.result != Cr.NS_ERROR_FAILURE) {
+ throw e;
+ }
+ }
+ return val;
+}
diff --git a/browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js b/browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js
new file mode 100644
index 000000000..42ef57314
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js
@@ -0,0 +1,254 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * With e10s, plugins must run in their own process. This means we have
+ * three processes at a minimum when we're running a plugin:
+ *
+ * 1) The main browser, or "chrome" process
+ * 2) The content process hosting the plugin instance
+ * 3) The plugin process
+ *
+ * If the plugin process crashes, we cannot be sure if the chrome process
+ * will hear about it first, or the content process will hear about it
+ * first. Because of how IPC works, that's really up to the operating system,
+ * and we assume any guarantees about it, so we have to account for both
+ * possibilities.
+ *
+ * This test exercises the browser's reaction to both possibilities.
+ */
+
+const CRASH_URL = "http://example.com/browser/browser/base/content/test/plugins/plugin_crashCommentAndURL.html";
+const CRASHED_MESSAGE = "BrowserPlugins:NPAPIPluginProcessCrashed";
+
+/**
+ * In order for our test to work, we need to be able to put a plugin
+ * in a very specific state. Specifically, we need it to match the
+ * :-moz-handler-crashed pseudoselector. The only way I can find to
+ * do that is by actually crashing the plugin. So we wait for the
+ * plugin to crash and show the "please" state (since that will
+ * only show if both the message from the parent has been received
+ * AND the PluginCrashed event has fired).
+ *
+ * Once in that state, we try to rewind the clock a little bit - we clear
+ * out the crashData cache in the PluginContent with a message, and we also
+ * override the pluginFallbackState of the <object> to fool PluginContent
+ * into believing that the plugin is in a particular state.
+ *
+ * @param browser
+ * The browser that has loaded the CRASH_URL that we need to
+ * prepare to be in the special state.
+ * @param pluginFallbackState
+ * The value we should override the <object>'s pluginFallbackState
+ * with.
+ * @return Promise
+ * The Promise resolves when the plugin has officially been put into
+ * the crash reporter state, and then "rewound" to have the "status"
+ * attribute of the statusDiv removed. The resolved Promise returns
+ * the run ID for the crashed plugin. It rejects if we never get into
+ * the crash reporter state.
+ */
+function preparePlugin(browser, pluginFallbackState) {
+ return ContentTask.spawn(browser, pluginFallbackState, function* (pluginFallbackState) {
+ let plugin = content.document.getElementById("plugin");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ // CRASH_URL will load a plugin that crashes immediately. We
+ // wait until the plugin has finished being put into the crash
+ // state.
+ let statusDiv;
+ yield ContentTaskUtils.waitForCondition(() => {
+ statusDiv = plugin.ownerDocument
+ .getAnonymousElementByAttribute(plugin, "anonid",
+ "submitStatus");
+ return statusDiv && statusDiv.getAttribute("status") == "please";
+ }, "Timed out waiting for plugin to be in crash report state");
+
+ // "Rewind", by wiping out the status attribute...
+ statusDiv.removeAttribute("status");
+ // Somehow, I'm able to get away with overriding the getter for
+ // this XPCOM object. Probably because I've got chrome privledges.
+ Object.defineProperty(plugin, "pluginFallbackType", {
+ get: function() {
+ return pluginFallbackState;
+ }
+ });
+ return plugin.runID;
+ }).then((runID) => {
+ browser.messageManager.sendAsyncMessage("BrowserPlugins:Test:ClearCrashData");
+ return runID;
+ });
+}
+
+add_task(function* setup() {
+ // Bypass click-to-play
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
+
+ // Clear out any minidumps we create from plugins - we really don't care
+ // about them.
+ let crashObserver = (subject, topic, data) => {
+ if (topic != "plugin-crashed") {
+ return;
+ }
+
+ let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
+ let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
+
+ let minidumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ minidumpDir.append("minidumps");
+
+ let pluginDumpFile = minidumpDir.clone();
+ pluginDumpFile.append(minidumpID + ".dmp");
+
+ let extraFile = minidumpDir.clone();
+ extraFile.append(minidumpID + ".extra");
+
+ ok(pluginDumpFile.exists(), "Found minidump");
+ ok(extraFile.exists(), "Found extra file");
+
+ pluginDumpFile.remove(false);
+ extraFile.remove(false);
+ };
+
+ Services.obs.addObserver(crashObserver, "plugin-crashed", false);
+ // plugins.testmode will make BrowserPlugins:Test:ClearCrashData work.
+ Services.prefs.setBoolPref("plugins.testmode", true);
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("plugins.testmode");
+ Services.obs.removeObserver(crashObserver, "plugin-crashed");
+ });
+});
+
+/**
+ * In this case, the chrome process hears about the crash first.
+ */
+add_task(function* testChromeHearsPluginCrashFirst() {
+ // Open a remote window so that we can run this test even if e10s is not
+ // enabled by default.
+ let win = yield BrowserTestUtils.openNewBrowserWindow({remote: true});
+ let browser = win.gBrowser.selectedBrowser;
+
+ browser.loadURI(CRASH_URL);
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ // In this case, we want the <object> to match the -moz-handler-crashed
+ // pseudoselector, but we want it to seem still active, because the
+ // content process is not yet supposed to know that the plugin has
+ // crashed.
+ let runID = yield preparePlugin(browser,
+ Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE);
+
+ // Send the message down to PluginContent.jsm saying that the plugin has
+ // crashed, and that we have a crash report.
+ let mm = browser.messageManager;
+ mm.sendAsyncMessage(CRASHED_MESSAGE,
+ { pluginName: "", runID, state: "please" });
+
+ yield ContentTask.spawn(browser, null, function* () {
+ // At this point, the content process should have heard the
+ // plugin crash message from the parent, and we are OK to emit
+ // the PluginCrashed event.
+ let plugin = content.document.getElementById("plugin");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let statusDiv = plugin.ownerDocument
+ .getAnonymousElementByAttribute(plugin, "anonid",
+ "submitStatus");
+
+ if (statusDiv.getAttribute("status") == "please") {
+ Assert.ok(false, "Did not expect plugin to be in crash report mode yet.");
+ return;
+ }
+
+ // Now we need the plugin to seem crashed to PluginContent.jsm, without
+ // actually crashing the plugin again. We hack around this by overriding
+ // the pluginFallbackType again.
+ Object.defineProperty(plugin, "pluginFallbackType", {
+ get: function() {
+ return Ci.nsIObjectLoadingContent.PLUGIN_CRASHED;
+ },
+ });
+
+ let event = new content.PluginCrashedEvent("PluginCrashed", {
+ pluginName: "",
+ pluginDumpID: "",
+ browserDumpID: "",
+ submittedCrashReport: false,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ plugin.dispatchEvent(event);
+ Assert.equal(statusDiv.getAttribute("status"), "please",
+ "Should have been showing crash report UI");
+ });
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+/**
+ * In this case, the content process hears about the crash first.
+ */
+add_task(function* testContentHearsCrashFirst() {
+ // Open a remote window so that we can run this test even if e10s is not
+ // enabled by default.
+ let win = yield BrowserTestUtils.openNewBrowserWindow({remote: true});
+ let browser = win.gBrowser.selectedBrowser;
+
+ browser.loadURI(CRASH_URL);
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ // In this case, we want the <object> to match the -moz-handler-crashed
+ // pseudoselector, and we want the plugin to seem crashed, since the
+ // content process in this case has heard about the crash first.
+ let runID = yield preparePlugin(browser,
+ Ci.nsIObjectLoadingContent.PLUGIN_CRASHED);
+
+ yield ContentTask.spawn(browser, null, function* () {
+ // At this point, the content process has not yet heard from the
+ // parent about the crash report. Let's ensure that by making sure
+ // we're not showing the plugin crash report UI.
+ let plugin = content.document.getElementById("plugin");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let statusDiv = plugin.ownerDocument
+ .getAnonymousElementByAttribute(plugin, "anonid",
+ "submitStatus");
+
+ if (statusDiv.getAttribute("status") == "please") {
+ Assert.ok(false, "Did not expect plugin to be in crash report mode yet.");
+ }
+
+ let event = new content.PluginCrashedEvent("PluginCrashed", {
+ pluginName: "",
+ pluginDumpID: "",
+ browserDumpID: "",
+ submittedCrashReport: false,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ plugin.dispatchEvent(event);
+
+ Assert.notEqual(statusDiv.getAttribute("status"), "please",
+ "Should not yet be showing crash report UI");
+ });
+
+ // Now send the message down to PluginContent.jsm that the plugin has
+ // crashed...
+ let mm = browser.messageManager;
+ mm.sendAsyncMessage(CRASHED_MESSAGE,
+ { pluginName: "", runID, state: "please"});
+
+ yield ContentTask.spawn(browser, null, function* () {
+ // At this point, the content process will have heard the message
+ // from the parent and reacted to it. We should be showing the plugin
+ // crash report UI now.
+ let plugin = content.document.getElementById("plugin");
+ plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let statusDiv = plugin.ownerDocument
+ .getAnonymousElementByAttribute(plugin, "anonid",
+ "submitStatus");
+
+ Assert.equal(statusDiv.getAttribute("status"), "please",
+ "Should have been showing crash report UI");
+ });
+
+ yield BrowserTestUtils.closeWindow(win);
+});
diff --git a/browser/base/content/test/plugins/browser_plugin_reloading.js b/browser/base/content/test/plugins/browser_plugin_reloading.js
new file mode 100644
index 000000000..7327d4cf9
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_plugin_reloading.js
@@ -0,0 +1,85 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+var gTestBrowser = null;
+
+function updateAllTestPlugins(aState) {
+ setTestPluginEnabledState(aState, "Test Plug-in");
+ setTestPluginEnabledState(aState, "Second Test Plug-in");
+}
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gTestBrowser = null;
+ gBrowser.removeCurrentTab();
+ window.focus();
+ }));
+});
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ // Prime the blocklist service, the remote service doesn't launch on startup.
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
+
+// Tests that a click-to-play plugin retains its activated state upon reloading
+add_task(function* () {
+ clearAllPluginPermissions();
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 1, Should have a click-to-play notification");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 2, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+
+ // run the plugin
+ yield promisePlayObject("test");
+
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 3, plugin should have started");
+ ok(pluginInfo.activated, "Test 4, plugin node should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let npobj1 = Components.utils.waiveXrays(plugin).getObjectValue();
+ plugin.src = plugin.src;
+ let pluginsDiffer = false;
+ try {
+ Components.utils.waiveXrays(plugin).checkObjectValue(npobj1);
+ } catch (e) {
+ pluginsDiffer = true;
+ }
+
+ Assert.ok(pluginsDiffer, "Test 5, plugins differ.");
+ });
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 6, Plugin should have retained activated state.");
+ is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 7, plugin should have started");
+});
diff --git a/browser/base/content/test/plugins/browser_pluginnotification.js b/browser/base/content/test/plugins/browser_pluginnotification.js
new file mode 100644
index 000000000..bf32f37a4
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_pluginnotification.js
@@ -0,0 +1,626 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+var gTestBrowser = null;
+
+function updateAllTestPlugins(aState) {
+ setTestPluginEnabledState(aState, "Test Plug-in");
+ setTestPluginEnabledState(aState, "Second Test Plug-in");
+}
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gTestBrowser = null;
+ gBrowser.removeCurrentTab();
+ window.focus();
+ }));
+});
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab();
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ // Prime the blocklist service, the remote service doesn't launch on startup.
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
+ let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
+ ok(!exmsg, "exception: " + exmsg);
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+});
+
+// Tests a page with an unknown plugin in it.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_unknown.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("unknown");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED,
+ "Test 1a, plugin fallback type should be PLUGIN_UNSUPPORTED");
+});
+
+// Test that the doorhanger is shown when the user clicks on the overlay
+// after having previously blocked the plugin.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Plugin should not be activated");
+
+ // Simulate clicking the "Allow Now" button.
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._secondaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Plugin should be activated");
+
+ // Simulate clicking the "Block" button.
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Plugin should not be activated");
+
+ // Simulate clicking the overlay
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let bounds = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ ok(!notification.dismissed, "A plugin notification should be shown.");
+
+ clearAllPluginPermissions();
+});
+
+// Tests that going back will reshow the notification for click-to-play plugins
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
+
+ // make sure the notification is gone
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!notification, "Test 11b, Should not have a click-to-play notification");
+
+ gTestBrowser.webNavigation.goBack();
+
+ yield promisePopupNotification("click-to-play-plugins");
+});
+
+// Tests that the "Allow Always" permission works for click-to-play plugins
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 12a, Plugin should not be activated");
+
+ // Simulate clicking the "Allow Always" button.
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+
+ yield promiseForNotificationShown(notification);
+
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 12a, Plugin should be activated");
+});
+
+// Test that the "Always" permission, when set for just the Test plugin,
+// does not also allow the Second Test plugin.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let test = content.document.getElementById("test");
+ let secondtestA = content.document.getElementById("secondtestA");
+ let secondtestB = content.document.getElementById("secondtestB");
+ Assert.ok(test.activated && !secondtestA.activated && !secondtestB.activated,
+ "Content plugins are set up");
+ });
+
+ clearAllPluginPermissions();
+});
+
+// Tests that the plugin's "activated" property is true for working plugins
+// with click-to-play disabled.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_ENABLED);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test2.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("test1");
+ ok(pluginInfo.activated, "Test 14, Plugin should be activated");
+});
+
+// Tests that the overlay is shown instead of alternate content when
+// plugins are click to play.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_alternate_content.html");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let mainBox = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!!mainBox, "Test 15, Plugin overlay should exist");
+ });
+});
+
+// Tests that mContentType is used for click-to-play plugins, and not the
+// inspected type.
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug749455.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 17, Should have a click-to-play notification");
+});
+
+// Tests that clicking the icon of the overlay activates the doorhanger
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
+
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed,
+ "Test 19a, Doorhanger should start out dismissed");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let icon = doc.getAnonymousElementByAttribute(plugin, "class", "icon");
+ let bounds = icon.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed;
+ yield promiseForCondition(condition);
+});
+
+// Tests that clicking the text of the overlay activates the plugin
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
+
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed,
+ "Test 19c, Doorhanger should start out dismissed");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let text = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay");
+ let bounds = text.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed;
+ yield promiseForCondition(condition);
+});
+
+// Tests that clicking the box of the overlay activates the doorhanger
+// (just to be thorough)
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
+
+ ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed,
+ "Test 19e, Doorhanger should start out dismissed");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", 50, 50, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", 50, 50, 0, 1, 0, false, 0, 0);
+ });
+
+ let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 19e, Plugin should not be activated");
+
+ clearAllPluginPermissions();
+});
+
+// Tests that a plugin in a div that goes from style="display: none" to
+// "display: block" can be clicked to activate.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_hidden_to_visible.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 20a, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ Assert.ok(!!overlay, "Test 20a, Plugin overlay should exist");
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let mainBox = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ let overlayRect = mainBox.getBoundingClientRect();
+ Assert.ok(overlayRect.width == 0 && overlayRect.height == 0,
+ "Test 20a, plugin should have an overlay with 0px width and height");
+ });
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 20b, plugin should not be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let div = doc.getElementById("container");
+ Assert.equal(div.style.display, "none",
+ "Test 20b, container div should be display: none");
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let div = doc.getElementById("container");
+ div.style.display = "block";
+ });
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let mainBox = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
+ let overlayRect = mainBox.getBoundingClientRect();
+ Assert.ok(overlayRect.width == 200 && overlayRect.height == 200,
+ "Test 20c, plugin should have overlay dims of 200px");
+ });
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(!pluginInfo.activated, "Test 20b, plugin should not be activated");
+
+ ok(notification.dismissed, "Test 20c, Doorhanger should start out dismissed");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let bounds = plugin.getBoundingClientRect();
+ let left = (bounds.left + bounds.right) / 2;
+ let top = (bounds.top + bounds.bottom) / 2;
+ let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ let condition = () => !notification.dismissed && !!PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 20c, plugin should be activated");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlayRect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ Assert.ok(overlayRect.width == 0 && overlayRect.height == 0,
+ "Test 20c, plugin should have overlay dims of 0px");
+ });
+
+ clearAllPluginPermissions();
+});
+
+// Test having multiple different types of plugin on one page
+add_task(function* () {
+ // contains three plugins, application/x-test, application/x-second-test x 2
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 21a, Should have a click-to-play notification");
+
+ // confirm all three are blocked by ctp at this point
+ let ids = ["test", "secondtestA", "secondtestB"];
+ for (let id of ids) {
+ yield ContentTask.spawn(gTestBrowser, { id }, function* (args) {
+ let doc = content.document;
+ let plugin = doc.getElementById(args.id);
+ let overlayRect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ Assert.ok(overlayRect.width == 200 && overlayRect.height == 200,
+ "Test 21a, plugin " + args.id + " should have click-to-play overlay with dims");
+ });
+
+ let pluginInfo = yield promiseForPluginInfo(id);
+ ok(!pluginInfo.activated, "Test 21a, Plugin with id=" + id + " should not be activated");
+ }
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 21a, Should have a click-to-play notification");
+
+ // we have to actually show the panel to get the bindings to instantiate
+ yield promiseForNotificationShown(notification);
+
+ is(notification.options.pluginData.size, 2, "Test 21a, Should have two types of plugin in the notification");
+
+ let centerAction = null;
+ for (let action of notification.options.pluginData.values()) {
+ if (action.pluginName == "Test") {
+ centerAction = action;
+ break;
+ }
+ }
+ ok(centerAction, "Test 21b, found center action for the Test plugin");
+
+ let centerItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ is(item.value, "block", "Test 21b, all plugins should start out blocked");
+ if (item.action == centerAction) {
+ centerItem = item;
+ break;
+ }
+ }
+ ok(centerItem, "Test 21b, found center item for the Test plugin");
+
+ // Select the allow now option in the select drop down for Test Plugin
+ centerItem.value = "allownow";
+
+ // "click" the button to activate the Test plugin
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ ok(pluginInfo.activated, "Test 21b, plugin should be activated");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 21b, Should have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ ok(notification.options.pluginData.size == 2, "Test 21c, Should have one type of plugin in the notification");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ let overlayRect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ Assert.ok(overlayRect.width == 0 && overlayRect.height == 0,
+ "Test 21c, plugin should have overlay dims of 0px");
+ });
+
+ ids = ["secondtestA", "secondtestB"];
+ for (let id of ids) {
+ yield ContentTask.spawn(gTestBrowser, { id }, function* (args) {
+ let doc = content.document;
+ let plugin = doc.getElementById(args.id);
+ let overlayRect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ Assert.ok(overlayRect.width == 200 && overlayRect.height == 200,
+ "Test 21c, plugin " + args.id + " should have click-to-play overlay with zero dims");
+ });
+
+
+ let pluginInfo = yield promiseForPluginInfo(id);
+ ok(!pluginInfo.activated, "Test 21c, Plugin with id=" + id + " should not be activated");
+ }
+
+ centerAction = null;
+ for (let action of notification.options.pluginData.values()) {
+ if (action.pluginName == "Second Test") {
+ centerAction = action;
+ break;
+ }
+ }
+ ok(centerAction, "Test 21d, found center action for the Second Test plugin");
+
+ centerItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ if (item.action == centerAction) {
+ is(item.value, "block", "Test 21d, test plugin 2 should start blocked");
+ centerItem = item;
+ break;
+ }
+ else {
+ is(item.value, "allownow", "Test 21d, test plugin should be enabled");
+ }
+ }
+ ok(centerItem, "Test 21d, found center item for the Second Test plugin");
+
+ // Select the allow now option in the select drop down for Second Test Plguins
+ centerItem.value = "allownow";
+
+ // "click" the button to activate the Second Test plugins
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 21d, Should have a click-to-play notification");
+
+ ids = ["test", "secondtestA", "secondtestB"];
+ for (let id of ids) {
+ yield ContentTask.spawn(gTestBrowser, { id }, function* (args) {
+ let doc = content.document;
+ let plugin = doc.getElementById(args.id);
+ let overlayRect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
+ Assert.ok(overlayRect.width == 0 && overlayRect.height == 0,
+ "Test 21d, plugin " + args.id + " should have click-to-play overlay with zero dims");
+ });
+
+ let pluginInfo = yield promiseForPluginInfo(id);
+ ok(pluginInfo.activated, "Test 21d, Plugin with id=" + id + " should not be activated");
+ }
+});
+
+// Tests that a click-to-play plugin resets its activated state when changing types
+add_task(function* () {
+ clearAllPluginPermissions();
+
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 22, Should have a click-to-play notification");
+
+ // Plugin should start as CTP
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 23, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ plugin.type = null;
+ // We currently don't properly change state just on type change,
+ // so rebind the plugin to tree. bug 767631
+ plugin.parentNode.appendChild(plugin);
+ });
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_NULL, "Test 23, plugin should be TYPE_NULL");
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let doc = content.document;
+ let plugin = doc.getElementById("test");
+ plugin.type = "application/x-test";
+ plugin.parentNode.appendChild(plugin);
+ });
+
+ pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_NULL, "Test 23, plugin should be TYPE_NULL");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
+ "Test 23, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
+ ok(!pluginInfo.activated, "Test 23, plugin node should not be activated");
+});
+
+// Plugin sync removal test. Note this test produces a notification drop down since
+// the plugin we add has zero dims.
+add_task(function* () {
+ updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_syncRemoved.html");
+
+ // Maybe there some better trick here, we need to wait for the page load, then
+ // wait for the js to execute in the page.
+ yield waitForMs(500);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+ ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed");
+ ok(notification.dismissed, "Test 25: The notification should be dismissed by default");
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
+});
+
+// Tests a page with a blocked plugin in it and make sure the infoURL property
+// the blocklist file gets used.
+add_task(function* () {
+ clearAllPluginPermissions();
+
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginInfoURL.xml", gTestBrowser);
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
+
+ // Work around for delayed PluginBindingAttached
+ yield promiseUpdatePluginBindings(gTestBrowser);
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins");
+
+ // Since the plugin notification is dismissed by default, reshow it.
+ yield promiseForNotificationShown(notification);
+
+ let pluginInfo = yield promiseForPluginInfo("test");
+ is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED,
+ "Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED");
+ ok(!pluginInfo.activated, "Plugin should be activated.");
+
+ const testUrl = "http://test.url.com/";
+
+ let firstPanelChild = PopupNotifications.panel.firstChild;
+ let infoLink = document.getAnonymousElementByAttribute(firstPanelChild, "anonid",
+ "click-to-play-plugins-notification-link");
+ is(infoLink.href, testUrl,
+ "Test 26, the notification URL needs to match the infoURL from the blocklist file.");
+});
diff --git a/browser/base/content/test/plugins/browser_plugins_added_dynamically.js b/browser/base/content/test/plugins/browser_plugins_added_dynamically.js
new file mode 100644
index 000000000..22077a54d
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_plugins_added_dynamically.js
@@ -0,0 +1,137 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+var gTestBrowser = null;
+
+add_task(function* () {
+ registerCleanupFunction(Task.async(function*() {
+ clearAllPluginPermissions();
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+ yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
+ resetBlocklist();
+ gBrowser.removeCurrentTab();
+ window.focus();
+ gTestBrowser = null;
+ }));
+});
+
+// "Activate" of a given type -> plugins of that type dynamically added should
+// automatically play.
+add_task(function* () {
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+
+ Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+});
+
+add_task(function* () {
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!notification, "Test 1a, Should not have a click-to-play notification");
+
+ // Add a plugin of type test
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("pluginone", "application/x-test"));
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 1a, Should not have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ let centerAction = null;
+ for (let action of notification.options.pluginData.values()) {
+ if (action.pluginName == "Test") {
+ centerAction = action;
+ break;
+ }
+ }
+ ok(centerAction, "Test 2, found center action for the Test plugin");
+
+ let centerItem = null;
+ for (let item of PopupNotifications.panel.firstChild.childNodes) {
+ is(item.value, "block", "Test 3, all plugins should start out blocked");
+ if (item.action == centerAction) {
+ centerItem = item;
+ break;
+ }
+ }
+ ok(centerItem, "Test 4, found center item for the Test plugin");
+
+ // Select the allow now option in the select drop down for Test Plugin
+ centerItem.value = "allownow";
+
+ // "click" the button to activate the Test plugin
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ let pluginInfo = yield promiseForPluginInfo("pluginone");
+ ok(pluginInfo.activated, "Test 5, plugin should be activated");
+
+ // Add another plugin of type test
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("plugintwo", "application/x-test"));
+ });
+
+ pluginInfo = yield promiseForPluginInfo("plugintwo");
+ ok(pluginInfo.activated, "Test 6, plugins should be activated");
+});
+
+// "Activate" of a given type -> plugins of other types dynamically added
+// should not automatically play.
+add_task(function* () {
+ clearAllPluginPermissions();
+
+ yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
+
+ let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(!notification, "Test 7, Should not have a click-to-play notification");
+
+ // Add a plugin of type test
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("pluginone", "application/x-test"));
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(notification, "Test 8, Should not have a click-to-play notification");
+
+ yield promiseForNotificationShown(notification);
+
+ is(notification.options.pluginData.size, 1, "Should be one plugin action");
+
+ let pluginInfo = yield promiseForPluginInfo("pluginone");
+ ok(!pluginInfo.activated, "Test 8, test plugin should be activated");
+
+ let condition = () => !notification.dismissed &&
+ PopupNotifications.panel.firstChild;
+ yield promiseForCondition(condition);
+
+ // "click" the button to activate the Test plugin
+ PopupNotifications.panel.firstChild._primaryButton.click();
+
+ pluginInfo = yield promiseForPluginInfo("pluginone");
+ ok(pluginInfo.activated, "Test 9, test plugin should be activated");
+
+ yield ContentTask.spawn(gTestBrowser, {}, function* () {
+ new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("plugintwo", "application/x-second-test"));
+ });
+
+ yield promisePopupNotification("click-to-play-plugins");
+
+ pluginInfo = yield promiseForPluginInfo("pluginone");
+ ok(pluginInfo.activated, "Test 10, plugins should be activated");
+ pluginInfo = yield promiseForPluginInfo("plugintwo");
+ ok(!pluginInfo.activated, "Test 11, plugins should be activated");
+});
diff --git a/browser/base/content/test/plugins/browser_private_clicktoplay.js b/browser/base/content/test/plugins/browser_private_clicktoplay.js
new file mode 100644
index 000000000..785b1bb31
--- /dev/null
+++ b/browser/base/content/test/plugins/browser_private_clicktoplay.js
@@ -0,0 +1,216 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir;
+const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+var gTestBrowser = null;
+var gNextTest = null;
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var gPrivateWindow = null;
+var gPrivateBrowser = null;
+
+function finishTest() {
+ clearAllPluginPermissions();
+ gBrowser.removeCurrentTab();
+ if (gPrivateWindow) {
+ gPrivateWindow.close();
+ }
+ window.focus();
+}
+
+let createPrivateWindow = Task.async(function* createPrivateWindow(url) {
+ gPrivateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+ ok(!!gPrivateWindow, "should have created a private window.");
+ gPrivateBrowser = gPrivateWindow.getBrowser().selectedBrowser;
+
+ BrowserTestUtils.loadURI(gPrivateBrowser, url);
+ yield BrowserTestUtils.browserLoaded(gPrivateBrowser);
+});
+
+add_task(function* test() {
+ registerCleanupFunction(function() {
+ clearAllPluginPermissions();
+ getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
+ getTestPlugin("Second Test Plug-in").enabledState = Ci.nsIPluginTag.STATE_ENABLED;
+ });
+
+ let newTab = gBrowser.addTab();
+ gBrowser.selectedTab = newTab;
+ gTestBrowser = gBrowser.selectedBrowser;
+ let promise = BrowserTestUtils.browserLoaded(gTestBrowser);
+
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
+ getTestPlugin("Second Test Plug-in").enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
+ yield promise;
+});
+
+add_task(function* test1a() {
+ yield createPrivateWindow(gHttpTestRoot + "plugin_test.html");
+});
+
+add_task(function* test1b() {
+ let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
+ ok(popupNotification, "Test 1b, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gPrivateBrowser, null, function() {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
+ });
+
+ // Check the button status
+ let promiseShown = BrowserTestUtils.waitForEvent(gPrivateWindow.PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+
+ yield promiseShown;
+ let button1 = gPrivateWindow.PopupNotifications.panel.firstChild._primaryButton;
+ let button2 = gPrivateWindow.PopupNotifications.panel.firstChild._secondaryButton;
+ is(button1.getAttribute("action"), "_singleActivateNow", "Test 1b, Blocked plugin in private window should have a activate now button");
+ ok(button2.hidden, "Test 1b, Blocked plugin in a private window should not have a secondary button")
+
+ gPrivateWindow.close();
+ BrowserTestUtils.loadURI(gTestBrowser, gHttpTestRoot + "plugin_test.html");
+ yield BrowserTestUtils.browserLoaded(gTestBrowser);
+});
+
+add_task(function* test2a() {
+ // enable test plugin on this site
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "Test 2a, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, null, function() {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!objLoadingContent.activated, "Test 2a, Plugin should not be activated");
+ });
+
+ // Simulate clicking the "Allow Now" button.
+ let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+ yield promiseShown;
+
+ PopupNotifications.panel.firstChild._secondaryButton.click();
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let condition = () => objLoadingContent.activated;
+ yield ContentTaskUtils.waitForCondition(condition, "Test 2a, Waited too long for plugin to activate");
+ });
+});
+
+add_task(function* test2c() {
+ let topicObserved = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
+ yield createPrivateWindow(gHttpTestRoot + "plugin_test.html");
+ yield topicObserved;
+
+ let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
+ ok(popupNotification, "Test 2c, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gPrivateBrowser, null, function() {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(objLoadingContent.activated, "Test 2c, Plugin should be activated");
+ });
+
+ // Check the button status
+ let promiseShown = BrowserTestUtils.waitForEvent(gPrivateWindow.PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+ yield promiseShown;
+ let buttonContainer = gPrivateWindow.PopupNotifications.panel.firstChild._buttonContainer;
+ ok(buttonContainer.hidden, "Test 2c, Activated plugin in a private window should not have visible buttons");
+
+ clearAllPluginPermissions();
+ gPrivateWindow.close();
+
+ BrowserTestUtils.loadURI(gTestBrowser, gHttpTestRoot + "plugin_test.html");
+ yield BrowserTestUtils.browserLoaded(gTestBrowser);
+});
+
+add_task(function* test3a() {
+ // enable test plugin on this site
+ let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+ ok(popupNotification, "Test 3a, Should have a click-to-play notification");
+
+ yield ContentTask.spawn(gTestBrowser, null, function() {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!objLoadingContent.activated, "Test 3a, Plugin should not be activated");
+ });
+
+ // Simulate clicking the "Allow Always" button.
+ let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+ yield promiseShown;
+ PopupNotifications.panel.firstChild._secondaryButton.click();
+
+ yield ContentTask.spawn(gTestBrowser, null, function* () {
+ let plugin = content.document.getElementById("test");
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let condition = () => objLoadingContent.activated;
+ yield ContentTaskUtils.waitForCondition(condition, "Test 3a, Waited too long for plugin to activate");
+ });
+});
+
+add_task(function* test3c() {
+ let topicObserved = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
+ yield createPrivateWindow(gHttpTestRoot + "plugin_test.html");
+ yield topicObserved;
+
+ let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
+ ok(popupNotification, "Test 3c, Should have a click-to-play notification");
+
+ // Check the button status
+ let promiseShown = BrowserTestUtils.waitForEvent(gPrivateWindow.PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+ yield promiseShown;
+ let buttonContainer = gPrivateWindow.PopupNotifications.panel.firstChild._buttonContainer;
+ ok(buttonContainer.hidden, "Test 3c, Activated plugin in a private window should not have visible buttons");
+
+ BrowserTestUtils.loadURI(gPrivateBrowser, gHttpTestRoot + "plugin_two_types.html");
+ yield BrowserTestUtils.browserLoaded(gPrivateBrowser);
+});
+
+add_task(function* test3d() {
+ let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
+ ok(popupNotification, "Test 3d, Should have a click-to-play notification");
+
+ // Check the list item status
+ let promiseShown = BrowserTestUtils.waitForEvent(gPrivateWindow.PopupNotifications.panel,
+ "Shown");
+ popupNotification.reshow();
+ yield promiseShown;
+ let doc = gPrivateWindow.document;
+ for (let item of gPrivateWindow.PopupNotifications.panel.firstChild.childNodes) {
+ let allowalways = doc.getAnonymousElementByAttribute(item, "anonid", "allowalways");
+ ok(allowalways, "Test 3d, should have list item for allow always");
+ let allownow = doc.getAnonymousElementByAttribute(item, "anonid", "allownow");
+ ok(allownow, "Test 3d, should have list item for allow now");
+ let block = doc.getAnonymousElementByAttribute(item, "anonid", "block");
+ ok(block, "Test 3d, should have list item for block");
+
+ if (item.action.pluginName === "Test") {
+ is(item.value, "allowalways", "Test 3d, Plugin should bet set to 'allow always'");
+ ok(!allowalways.hidden, "Test 3d, Plugin set to 'always allow' should have a visible 'always allow' action.");
+ ok(allownow.hidden, "Test 3d, Plugin set to 'always allow' should have an invisible 'allow now' action.");
+ ok(block.hidden, "Test 3d, Plugin set to 'always allow' should have an invisible 'block' action.");
+ } else if (item.action.pluginName === "Second Test") {
+ is(item.value, "block", "Test 3d, Second plugin should bet set to 'block'");
+ ok(allowalways.hidden, "Test 3d, Plugin set to 'block' should have a visible 'always allow' action.");
+ ok(!allownow.hidden, "Test 3d, Plugin set to 'block' should have a visible 'allow now' action.");
+ ok(!block.hidden, "Test 3d, Plugin set to 'block' should have a visible 'block' action.");
+ } else {
+ ok(false, "Test 3d, Unexpected plugin '"+item.action.pluginName+"'");
+ }
+ }
+
+ finishTest();
+});
diff --git a/browser/base/content/test/plugins/head.js b/browser/base/content/test/plugins/head.js
new file mode 100644
index 000000000..4995c4dc6
--- /dev/null
+++ b/browser/base/content/test/plugins/head.js
@@ -0,0 +1,396 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+ "resource://gre/modules/Task.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+ "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
+ "resource://gre/modules/PromiseUtils.jsm");
+
+// The blocklist shim running in the content process does not initialize at
+// start up, so it's not active until we load content that needs to do a
+// check. This helper bypasses the delay to get the svc up and running
+// immediately. Note, call this after remote content has loaded.
+function promiseInitContentBlocklistSvc(aBrowser)
+{
+ return ContentTask.spawn(aBrowser, {}, function* () {
+ try {
+ Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsIBlocklistService);
+ } catch (ex) {
+ return ex.message;
+ }
+ return null;
+ });
+}
+
+/**
+ * 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);
+ }
+ });
+}
+
+function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
+ return new Promise((resolve, reject) => {
+ subject.addEventListener(eventName, function listener(event) {
+ try {
+ if (checkFn && !checkFn(event)) {
+ return;
+ }
+ subject.removeEventListener(eventName, listener, useCapture);
+ resolve(event);
+ } catch (ex) {
+ try {
+ subject.removeEventListener(eventName, listener, useCapture);
+ } catch (ex2) {
+ // Maybe the provided object does not support removeEventListener.
+ }
+ reject(ex);
+ }
+ }, useCapture, useUntrusted);
+ });
+}
+
+
+/**
+ * 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 the chrome side nsIPluginTag for this plugin
+function getTestPlugin(aName) {
+ let pluginName = aName || "Test Plug-in";
+ let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+ let tags = ph.getPluginTags();
+
+ // Find the test plugin
+ for (let i = 0; i < tags.length; i++) {
+ if (tags[i].name == pluginName)
+ return tags[i];
+ }
+ ok(false, "Unable to find plugin");
+ return null;
+}
+
+// Set the 'enabledState' on the nsIPluginTag stored in the main or chrome
+// process.
+function setTestPluginEnabledState(newEnabledState, pluginName) {
+ let name = pluginName || "Test Plug-in";
+ let plugin = getTestPlugin(name);
+ plugin.enabledState = newEnabledState;
+}
+
+// Get the 'enabledState' on the nsIPluginTag stored in the main or chrome
+// process.
+function getTestPluginEnabledState(pluginName) {
+ let name = pluginName || "Test Plug-in";
+ let plugin = getTestPlugin(name);
+ return plugin.enabledState;
+}
+
+// Returns a promise for nsIObjectLoadingContent props data.
+function promiseForPluginInfo(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return ContentTask.spawn(browser, aId, function* (aId) {
+ let plugin = content.document.getElementById(aId);
+ if (!(plugin instanceof Ci.nsIObjectLoadingContent))
+ throw new Error("no plugin found");
+ return {
+ pluginFallbackType: plugin.pluginFallbackType,
+ activated: plugin.activated,
+ hasRunningPlugin: plugin.hasRunningPlugin,
+ displayedType: plugin.displayedType,
+ };
+ });
+}
+
+// Return a promise and call the plugin's nsIObjectLoadingContent
+// playPlugin() method.
+function promisePlayObject(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return ContentTask.spawn(browser, aId, function* (aId) {
+ let plugin = content.document.getElementById(aId);
+ let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ objLoadingContent.playPlugin();
+ });
+}
+
+function promiseCrashObject(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return ContentTask.spawn(browser, aId, function* (aId) {
+ let plugin = content.document.getElementById(aId);
+ Components.utils.waiveXrays(plugin).crash();
+ });
+}
+
+// Return a promise and call the plugin's getObjectValue() method.
+function promiseObjectValueResult(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return ContentTask.spawn(browser, aId, function* (aId) {
+ let plugin = content.document.getElementById(aId);
+ return Components.utils.waiveXrays(plugin).getObjectValue();
+ });
+}
+
+// Return a promise and reload the target plugin in the page
+function promiseReloadPlugin(aId, aBrowser) {
+ let browser = aBrowser || gTestBrowser;
+ return ContentTask.spawn(browser, aId, function* (aId) {
+ let plugin = content.document.getElementById(aId);
+ plugin.src = plugin.src;
+ });
+}
+
+// after a test is done using the plugin doorhanger, we should just clear
+// any permissions that may have crept in
+function clearAllPluginPermissions() {
+ let perms = Services.perms.enumerator;
+ while (perms.hasMoreElements()) {
+ let perm = perms.getNext();
+ if (perm.type.startsWith('plugin')) {
+ info("removing permission:" + perm.principal.origin + " " + perm.type + "\n");
+ Services.perms.removePermission(perm);
+ }
+ }
+}
+
+function updateBlocklist(aCallback) {
+ let blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsITimerCallback);
+ let observer = function() {
+ Services.obs.removeObserver(observer, "blocklist-updated");
+ SimpleTest.executeSoon(aCallback);
+ };
+ Services.obs.addObserver(observer, "blocklist-updated", false);
+ blocklistNotifier.notify(null);
+}
+
+var _originalTestBlocklistURL = null;
+function setAndUpdateBlocklist(aURL, aCallback) {
+ if (!_originalTestBlocklistURL) {
+ _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
+ }
+ Services.prefs.setCharPref("extensions.blocklist.url", aURL);
+ updateBlocklist(aCallback);
+}
+
+// A generator that insures a new blocklist is loaded (in both
+// processes if applicable).
+function* asyncSetAndUpdateBlocklist(aURL, aBrowser) {
+ info("*** loading new blocklist: " + aURL);
+ let doTestRemote = aBrowser ? aBrowser.isRemoteBrowser : false;
+ if (!_originalTestBlocklistURL) {
+ _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
+ }
+ Services.prefs.setCharPref("extensions.blocklist.url", aURL);
+ let localPromise = TestUtils.topicObserved("blocklist-updated");
+ let remotePromise;
+ if (doTestRemote) {
+ remotePromise = TestUtils.topicObserved("content-blocklist-updated");
+ }
+ let blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsITimerCallback);
+ blocklistNotifier.notify(null);
+ info("*** waiting on local load");
+ yield localPromise;
+ if (doTestRemote) {
+ info("*** waiting on remote load");
+ yield remotePromise;
+ }
+ info("*** blocklist loaded.");
+}
+
+// Reset back to the blocklist we had at the start of the test run.
+function resetBlocklist() {
+ Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
+}
+
+// Insure there's a popup notification present. This test does not indicate
+// open state. aBrowser can be undefined.
+function promisePopupNotification(aName, aBrowser) {
+ return new Promise((resolve) => {
+ waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
+ () => {
+ ok(!!PopupNotifications.getNotification(aName, aBrowser),
+ aName + " notification appeared");
+
+ resolve();
+ }, "timeout waiting for popup notification " + aName);
+ });
+}
+
+/**
+ * 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 onShown(e) {
+ PopupNotifications.panel.removeEventListener("popupshown", onShown);
+ callback();
+ }, false);
+ notification.reshow();
+}
+
+function promiseForNotificationShown(notification) {
+ return new Promise((resolve) => {
+ waitForNotificationShown(notification, resolve);
+ });
+}
+
+/**
+ * Due to layout being async, "PluginBindAttached" may trigger later. This
+ * returns a Promise that resolves once we've forced a layout flush, which
+ * triggers the PluginBindAttached event to fire. This trick only works if
+ * there is some sort of plugin in the page.
+ * @param browser
+ * The browser to force plugin bindings in.
+ * @return Promise
+ */
+function promiseUpdatePluginBindings(browser) {
+ return ContentTask.spawn(browser, {}, function* () {
+ let doc = content.document;
+ let elems = doc.getElementsByTagName('embed');
+ if (!elems || elems.length < 1) {
+ elems = doc.getElementsByTagName('object');
+ }
+ if (elems && elems.length > 0) {
+ elems[0].clientTop;
+ }
+ });
+}
diff --git a/browser/base/content/test/plugins/plugin_add_dynamically.html b/browser/base/content/test/plugins/plugin_add_dynamically.html
new file mode 100644
index 000000000..863d36e09
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_add_dynamically.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<script>
+function addPlugin(aId, aType="application/x-test") {
+ var embed = document.createElement("embed");
+ embed.setAttribute("id", aId);
+ embed.style.width = "200px";
+ embed.style.height = "200px";
+ embed.setAttribute("type", aType);
+ return document.body.appendChild(embed);
+}
+</script>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_alternate_content.html b/browser/base/content/test/plugins/plugin_alternate_content.html
new file mode 100644
index 000000000..f8acc833c
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_alternate_content.html
@@ -0,0 +1,9 @@
+<!-- bug 739575 -->
+<html>
+<head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<object id="test" type="application/x-test" style="height: 200px; width:200px">
+<p><a href="about:blank">you should not see this link when plugins are click-to-play</a></p>
+</object>
+</body></html>
diff --git a/browser/base/content/test/plugins/plugin_big.html b/browser/base/content/test/plugins/plugin_big.html
new file mode 100644
index 000000000..d11506176
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_big.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 500px; height: 500px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_both.html b/browser/base/content/test/plugins/plugin_both.html
new file mode 100644
index 000000000..2335366dc
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_both.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
+<embed id="test" style="width: 100px; height: 100px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_both2.html b/browser/base/content/test/plugins/plugin_both2.html
new file mode 100644
index 000000000..ba605d6e8
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_both2.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 100px; height: 100px" type="application/x-test">
+<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_bug744745.html b/browser/base/content/test/plugins/plugin_bug744745.html
new file mode 100644
index 000000000..d0691c9c0
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_bug744745.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body>
+<style>
+.x {
+ opacity: 0 !important;
+}
+</style>
+<object id="test" class="x" type="application/x-test" width=200 height=200></object>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_bug749455.html b/browser/base/content/test/plugins/plugin_bug749455.html
new file mode 100644
index 000000000..831dc82f7
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_bug749455.html
@@ -0,0 +1,8 @@
+<!-- bug 749455 -->
+<html>
+<head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<embed src="plugin_bug749455.html" type="application/x-test" width="100px" height="100px"></embed>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_bug787619.html b/browser/base/content/test/plugins/plugin_bug787619.html
new file mode 100644
index 000000000..cb91116f0
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_bug787619.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body>
+ <a id="wrapper">
+ <embed id="plugin" style="width: 200px; height: 200px" type="application/x-test">
+ </a>
+</body>
+</html>
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 000000000..1545f3647
--- /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_bug820497.html b/browser/base/content/test/plugins/plugin_bug820497.html
new file mode 100644
index 000000000..4884e9dbe
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_bug820497.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body>
+<object id="test" type="application/x-test" width=200 height=200></object>
+<script>
+ function addSecondPlugin() {
+ var object = document.createElement("object");
+ object.type = "application/x-second-test";
+ object.width = 200;
+ object.height = 200;
+ object.id = "secondtest";
+ document.body.appendChild(object);
+ }
+</script>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_clickToPlayAllow.html b/browser/base/content/test/plugins/plugin_clickToPlayAllow.html
new file mode 100644
index 000000000..3f5df1984
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_clickToPlayAllow.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 200px; height: 200px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_clickToPlayDeny.html b/browser/base/content/test/plugins/plugin_clickToPlayDeny.html
new file mode 100644
index 000000000..3f5df1984
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_clickToPlayDeny.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 200px; height: 200px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_crashCommentAndURL.html b/browser/base/content/test/plugins/plugin_crashCommentAndURL.html
new file mode 100644
index 000000000..711a19ed3
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_crashCommentAndURL.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <script type="text/javascript">
+ function crash() {
+ var plugin = document.getElementById("plugin");
+ var argStr = decodeURIComponent(window.location.search.substr(1));
+ if (argStr) {
+ var args = JSON.parse(argStr);
+ for (var key in args)
+ plugin.setAttribute(key, args[key]);
+ }
+ try {
+ plugin.crash();
+ }
+ catch (err) {}
+ }
+ </script>
+ </head>
+ <body onload="crash();">
+ <embed id="plugin" type="application/x-test"
+ width="400" height="400"
+ drawmode="solid" color="FF00FFFF">
+ </embed>
+ </body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_data_url.html b/browser/base/content/test/plugins/plugin_data_url.html
new file mode 100644
index 000000000..77e101144
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_data_url.html
@@ -0,0 +1,11 @@
+<html>
+<body>
+ <a id="data-link-1" href='data:text/html,<embed id="test" style="width: 200px; height: 200px" type="application/x-test"/>'>
+ data: with one plugin
+ </a><br />
+ <a id="data-link-2" href='data:text/html,<embed id="test1" style="width: 200px; height: 200px" type="application/x-test"/><embed id="test2" style="width: 200px; height: 200px" type="application/x-second-test"/>'>
+ data: with two plugins
+ </a><br />
+ <object id="test" style="width: 200px; height: 200px" type="application/x-test"></object>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_hidden_to_visible.html b/browser/base/content/test/plugins/plugin_hidden_to_visible.html
new file mode 100644
index 000000000..eeacc1874
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_hidden_to_visible.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+ <div id="container" style="display: none">
+ <object id="test" type="application/x-test" style="width: 200px; height: 200px;"></object>
+ </div>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_iframe.html b/browser/base/content/test/plugins/plugin_iframe.html
new file mode 100644
index 000000000..239c9a771
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_iframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<iframe id="frame" with="400" height="400" src="plugin_test.html">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_outsideScrollArea.html b/browser/base/content/test/plugins/plugin_outsideScrollArea.html
new file mode 100644
index 000000000..c6ef50d5d
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_outsideScrollArea.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<style type="text/css">
+#container {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100%;
+ background: blue;
+}
+
+#test {
+ width: 400px;
+ height: 400px;
+ position: absolute;
+}
+</style>
+</head>
+<body>
+ <div id="container"></div>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_overlayed.html b/browser/base/content/test/plugins/plugin_overlayed.html
new file mode 100644
index 000000000..11c127093
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_overlayed.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <style type="text/css">
+ .absthing {
+ width: 400px;
+ height: 400px;
+ position: absolute;
+ left: 20px;
+ top: 20px;
+ }
+ #d1 {
+ z-index: 1;
+ }
+ #d2 {
+ z-index: 2;
+ background-color: rgba(0,0,255,0.5);
+ border: 1px solid red;
+ }
+ </style>
+<body>
+ <div class="absthing" id="d1">
+ <embed id="test" type="application/x-test">
+ </div>
+ <div class="absthing" id="d2">
+ <p>This is overlaying
+ </div>
diff --git a/browser/base/content/test/plugins/plugin_positioned.html b/browser/base/content/test/plugins/plugin_positioned.html
new file mode 100644
index 000000000..1bad7ee46
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_positioned.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <style type="text/css">
+ #test {
+ position: absolute;
+ left: -1000px;
+ top: -1000px;
+ }
+ </style>
+<body>
+ <embed id="test" type="application/x-test">
diff --git a/browser/base/content/test/plugins/plugin_small.html b/browser/base/content/test/plugins/plugin_small.html
new file mode 100644
index 000000000..f37ee28c7
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_small.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 10px; height: 10px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_small_2.html b/browser/base/content/test/plugins/plugin_small_2.html
new file mode 100644
index 000000000..ebc5ffe84
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_small_2.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 10px; height: 10px" type="application/x-second-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_syncRemoved.html b/browser/base/content/test/plugins/plugin_syncRemoved.html
new file mode 100644
index 000000000..d97787056
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_syncRemoved.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<body>
+<script type="text/javascript">
+ // create an embed, insert it in the doc and immediately remove it
+ var embed = document.createElement('embed');
+ embed.setAttribute("id", "test");
+ embed.setAttribute("type", "application/x-test");
+ embed.setAttribute("style", "width: 0px; height: 0px;");
+ document.body.appendChild(embed);
+ window.getComputedStyle(embed, null).top;
+ document.body.remove(embed);
+</script>
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 000000000..d4b5b6ca7
--- /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: 200px; height: 200px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_test2.html b/browser/base/content/test/plugins/plugin_test2.html
new file mode 100644
index 000000000..95614c930
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_test2.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test1" style="width: 200px; height: 200px" type="application/x-test">
+<embed id="test2" style="width: 200px; height: 200px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_test3.html b/browser/base/content/test/plugins/plugin_test3.html
new file mode 100644
index 000000000..215c02326
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_test3.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 0px; height: 0px" type="application/x-test">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_two_types.html b/browser/base/content/test/plugins/plugin_two_types.html
new file mode 100644
index 000000000..2359d2ec1
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_two_types.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body>
+<embed id="test" style="width: 200px; height: 200px" type="application/x-test"/>
+<embed id="secondtestA" style="width: 200px; height: 200px" type="application/x-second-test"/>
+<embed id="secondtestB" style="width: 200px; height: 200px" type="application/x-second-test"/>
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_unknown.html b/browser/base/content/test/plugins/plugin_unknown.html
new file mode 100644
index 000000000..578f455cc
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_unknown.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
+</body>
+</html>
diff --git a/browser/base/content/test/plugins/plugin_zoom.html b/browser/base/content/test/plugins/plugin_zoom.html
new file mode 100644
index 000000000..f9e598658
--- /dev/null
+++ b/browser/base/content/test/plugins/plugin_zoom.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<!-- The odd width and height are here to trigger bug 972237. -->
+<embed id="test" style="width: 99.789%; height: 99.123%" type="application/x-test">
+</body>
+</html>