summaryrefslogtreecommitdiffstats
path: root/browser/tools
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /browser/tools
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'browser/tools')
-rw-r--r--browser/tools/mozscreenshots/.eslintrc.js15
-rw-r--r--browser/tools/mozscreenshots/browser.ini12
-rw-r--r--browser/tools/mozscreenshots/browser_screenshots.js16
-rw-r--r--browser/tools/mozscreenshots/controlCenter/browser.ini6
-rw-r--r--browser/tools/mozscreenshots/controlCenter/browser_controlCenter.js16
-rw-r--r--browser/tools/mozscreenshots/devtools/browser.ini6
-rw-r--r--browser/tools/mozscreenshots/devtools/browser_devtools.js16
-rw-r--r--browser/tools/mozscreenshots/head.js53
-rw-r--r--browser/tools/mozscreenshots/moz.build20
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in12
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm179
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm279
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js65
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm84
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm85
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm243
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm61
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm42
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm59
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm92
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm130
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm127
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm152
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm38
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm57
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm68
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf33
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn6
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/black_theme.pngbin0 -> 977 bytes
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/borderify.xpibin0 -> 1611 bytes
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed.html11
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_active.html10
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_passive.html10
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/password.html13
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/tracking.html10
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-script.js13
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-style.css28
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots.html36
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/permissionPrompts.html30
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/robot.pngbin0 -> 9817 bytes
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/lib/white_theme.pngbin0 -> 977 bytes
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/moz.build17
-rw-r--r--browser/tools/mozscreenshots/permissionPrompts/browser.ini6
-rw-r--r--browser/tools/mozscreenshots/permissionPrompts/browser_permissionPrompts.js16
-rw-r--r--browser/tools/mozscreenshots/preferences/browser.ini6
-rw-r--r--browser/tools/mozscreenshots/preferences/browser_preferences.js16
-rw-r--r--browser/tools/mozscreenshots/primaryUI/browser.ini6
-rw-r--r--browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js18
48 files changed, 2218 insertions, 0 deletions
diff --git a/browser/tools/mozscreenshots/.eslintrc.js b/browser/tools/mozscreenshots/.eslintrc.js
new file mode 100644
index 000000000..55b05398e
--- /dev/null
+++ b/browser/tools/mozscreenshots/.eslintrc.js
@@ -0,0 +1,15 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": [
+ "../../../testing/mochitest/browser.eslintrc.js"
+ ],
+
+ "rules": {
+ "no-unused-vars": ["error", {
+ "vars": "all",
+ "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$",
+ "args": "none"
+ }]
+ }
+};
diff --git a/browser/tools/mozscreenshots/browser.ini b/browser/tools/mozscreenshots/browser.ini
new file mode 100644
index 000000000..e72a3acb4
--- /dev/null
+++ b/browser/tools/mozscreenshots/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ head.js
+ mozscreenshots/extension/lib/permissionPrompts.html
+ mozscreenshots/extension/lib/controlCenter/password.html
+ mozscreenshots/extension/lib/controlCenter/mixed.html
+ mozscreenshots/extension/lib/controlCenter/mixed_active.html
+ mozscreenshots/extension/lib/controlCenter/mixed_passive.html
+ mozscreenshots/extension/lib/borderify.xpi
+
+[browser_screenshots.js]
diff --git a/browser/tools/mozscreenshots/browser_screenshots.js b/browser/tools/mozscreenshots/browser_screenshots.js
new file mode 100644
index 000000000..502f90fec
--- /dev/null
+++ b/browser/tools/mozscreenshots/browser_screenshots.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+add_task(function* capture() {
+ let setsEnv = env.get("MOZSCREENSHOTS_SETS");
+ if (!setsEnv) {
+ ok(true, "MOZSCREENSHOTS_SETS wasn't specified so there's nothing to capture");
+ return;
+ }
+
+ let sets = setsEnv.trim().split(",");
+ yield TestRunner.start(sets);
+});
diff --git a/browser/tools/mozscreenshots/controlCenter/browser.ini b/browser/tools/mozscreenshots/controlCenter/browser.ini
new file mode 100644
index 000000000..f5b084edc
--- /dev/null
+++ b/browser/tools/mozscreenshots/controlCenter/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ ../head.js
+
+[browser_controlCenter.js]
diff --git a/browser/tools/mozscreenshots/controlCenter/browser_controlCenter.js b/browser/tools/mozscreenshots/controlCenter/browser_controlCenter.js
new file mode 100644
index 000000000..7e1ffb125
--- /dev/null
+++ b/browser/tools/mozscreenshots/controlCenter/browser_controlCenter.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../head.js */
+
+"use strict";
+
+add_task(function* capture() {
+ if (!shouldCapture()) {
+ return;
+ }
+ let sets = ["LightweightThemes", "ControlCenter"];
+
+ yield TestRunner.start(sets, "controlCenter");
+});
diff --git a/browser/tools/mozscreenshots/devtools/browser.ini b/browser/tools/mozscreenshots/devtools/browser.ini
new file mode 100644
index 000000000..e4fa0a988
--- /dev/null
+++ b/browser/tools/mozscreenshots/devtools/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ ../head.js
+
+[browser_devtools.js]
diff --git a/browser/tools/mozscreenshots/devtools/browser_devtools.js b/browser/tools/mozscreenshots/devtools/browser_devtools.js
new file mode 100644
index 000000000..a47548958
--- /dev/null
+++ b/browser/tools/mozscreenshots/devtools/browser_devtools.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../head.js */
+
+"use strict";
+
+add_task(function* capture() {
+ if (!shouldCapture()) {
+ return;
+ }
+ let sets = ["DevTools"];
+
+ yield TestRunner.start(sets, "devtools");
+});
diff --git a/browser/tools/mozscreenshots/head.js b/browser/tools/mozscreenshots/head.js
new file mode 100644
index 000000000..c1702ab08
--- /dev/null
+++ b/browser/tools/mozscreenshots/head.js
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* exported TestRunner, shouldCapture */
+
+"use strict";
+
+const {AddonWatcher} = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
+const chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+const EXTENSION_DIR = "chrome://mochitests/content/extensions/mozscreenshots/browser/";
+
+let TestRunner;
+
+function* setup() {
+ requestLongerTimeout(10);
+
+ info("installing extension temporarily");
+ let chromeURL = Services.io.newURI(EXTENSION_DIR, null, null);
+ let dir = chromeRegistry.convertChromeURL(chromeURL).QueryInterface(Ci.nsIFileURL).file;
+ yield AddonManager.installTemporaryAddon(dir);
+
+ info("Checking for mozscreenshots extension");
+ return new Promise((resolve) => {
+ AddonManager.getAddonByID("mozscreenshots@mozilla.org", function(aAddon) {
+ isnot(aAddon, null, "The mozscreenshots extension should be installed");
+ AddonWatcher.ignoreAddonPermanently(aAddon.id);
+ TestRunner = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {}).TestRunner;
+ resolve();
+ });
+ });
+}
+
+function shouldCapture() {
+ // Try pushes only capture in browser_screenshots.js with MOZSCREENSHOTS_SETS.
+ if (env.get("MOZSCREENSHOTS_SETS")) {
+ ok(true, "MOZSCREENSHOTS_SETS was specified so only capture what was " +
+ "requested (in browser_screenshots.js)");
+ return false;
+ }
+
+ // Automation isn't able to schedule test jobs to only run on nightlies so we handle it here
+ // (see also: bug 1116275).
+ let capture = AppConstants.MOZ_UPDATE_CHANNEL == "nightly" ||
+ AppConstants.SOURCE_REVISION_URL == "";
+ if (!capture) {
+ ok(true, "Capturing is disabled for this MOZ_UPDATE_CHANNEL or REPO");
+ }
+ return capture;
+}
+
+add_task(setup);
diff --git a/browser/tools/mozscreenshots/moz.build b/browser/tools/mozscreenshots/moz.build
new file mode 100644
index 000000000..0c8b98b6a
--- /dev/null
+++ b/browser/tools/mozscreenshots/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += [
+ # Each test is in it's own directory so it gets run in a clean profile with
+ # run-by-dir.
+ 'browser.ini',
+ 'controlCenter/browser.ini',
+ 'devtools/browser.ini',
+ 'permissionPrompts/browser.ini',
+ 'preferences/browser.ini',
+ 'primaryUI/browser.ini',
+]
+
+TEST_DIRS += [
+ 'mozscreenshots/extension',
+]
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in b/browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in
new file mode 100644
index 000000000..b0004aaa7
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in
@@ -0,0 +1,12 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions
+GENERATED_DIRS = $(TEST_EXTENSIONS_DIR)
+XPI_PKGNAME = mozscreenshots@mozilla.org
+
+include $(topsrcdir)/config/rules.mk
+
+libs::
+ (cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
new file mode 100644
index 000000000..c43514e94
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
@@ -0,0 +1,179 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["Screenshot"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+
+// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+ let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+ let consoleOptions = {
+ maxLogLevel: "info",
+ maxLogLevelPref: PREF_LOG_LEVEL,
+ prefix: "mozscreenshots",
+ };
+ return new ConsoleAPI(consoleOptions);
+});
+
+this.Screenshot = {
+ _extensionPath: null,
+ _path: null,
+ _imagePrefix: "",
+ _imageExtension: ".png",
+ _screenshotFunction: null,
+
+ init(path, extensionPath, imagePrefix = "") {
+ this._path = path;
+
+ let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ dir.initWithPath(this._path);
+ if (!dir.exists()) {
+ dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+ }
+
+ this._extensionPath = extensionPath;
+ this._imagePrefix = imagePrefix;
+ switch (Services.appinfo.OS) {
+ case "WINNT":
+ this._screenshotFunction = this._screenshotWindows;
+ break;
+ case "Darwin":
+ this._screenshotFunction = this._screenshotOSX;
+ break;
+ case "Linux":
+ this._screenshotFunction = this._screenshotLinux;
+ break;
+ default:
+ throw new Error("Unsupported operating system");
+ }
+ },
+
+ _buildImagePath(baseName) {
+ return OS.Path.join(this._path, this._imagePrefix + baseName + this._imageExtension);
+ },
+
+ // Capture the whole screen using an external application.
+ captureExternal(filename) {
+ let imagePath = this._buildImagePath(filename);
+ return this._screenshotFunction(imagePath).then(() => {
+ log.debug("saved screenshot: " + filename);
+ });
+ },
+
+ // helpers
+
+ _screenshotWindows(filename) {
+ return new Promise((resolve, reject) => {
+ let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
+ exe.append("screenshot.exe");
+ if (!exe.exists()) {
+ exe = Services.dirsvc.get("CurWorkD", Ci.nsIFile).parent;
+ exe.append("bin");
+ exe.append("screenshot.exe");
+ }
+ let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(exe);
+
+ let args = [filename];
+ process.runAsync(args, args.length, this._processObserver(resolve, reject));
+ });
+ },
+
+ _screenshotOSX: Task.async(function*(filename) {
+ let screencapture = (windowID = null) => {
+ return new Promise((resolve, reject) => {
+ // Get the screencapture executable
+ let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ file.initWithPath("/usr/sbin/screencapture");
+
+ let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ // Run the process.
+ let args = ["-x", "-t", "png"];
+ // Darwin version number for OS X 10.6 is 10.x
+ if (windowID && Services.sysinfo.getProperty("version").indexOf("10.") !== 0) {
+ // Capture only that window on 10.7+
+ args.push("-l");
+ args.push(windowID);
+ }
+ args.push(filename);
+ process.runAsync(args, args.length, this._processObserver(resolve, reject));
+ });
+ };
+
+ function readWindowID() {
+ let decoder = new TextDecoder();
+ let promise = OS.File.read("/tmp/mozscreenshots-windowid");
+ return promise.then(function onSuccess(array) {
+ return decoder.decode(array);
+ });
+ }
+
+ let promiseWindowID = () => {
+ return new Promise((resolve, reject) => {
+ // Get the window ID of the application (assuming its front-most)
+ let osascript = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ osascript.initWithPath("/bin/bash");
+
+ let osascriptP = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ osascriptP.init(osascript);
+ let osaArgs = ["-c", "/usr/bin/osascript -e 'tell application (path to frontmost application as text) to set winID to id of window 1' > /tmp/mozscreenshots-windowid"];
+ osascriptP.runAsync(osaArgs, osaArgs.length, this._processObserver(resolve, reject));
+ });
+ };
+
+ yield promiseWindowID();
+ let windowID = yield readWindowID();
+ yield screencapture(windowID);
+ }),
+
+ _screenshotLinux(filename) {
+ return new Promise((resolve, reject) => {
+ let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
+ exe.append("screentopng");
+ if (!exe.exists()) {
+ exe = Services.dirsvc.get("CurWorkD", Ci.nsIFile).parent;
+ exe.append("bin");
+ exe.append("screentopng");
+ }
+ let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(exe);
+
+ let args = [filename];
+ process.runAsync(args, args.length, this._processObserver(resolve, reject));
+ });
+ },
+
+ _processObserver(resolve, reject) {
+ return {
+ observe(subject, topic, data) {
+ switch (topic) {
+ case "process-finished":
+ try {
+ // Wait 1s after process to resolve
+ setTimeout(resolve, 1000);
+ } catch (ex) {
+ reject(ex);
+ }
+ break;
+ default:
+ reject(topic);
+ break;
+ }
+ },
+ };
+ },
+};
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
new file mode 100644
index 000000000..557b867b9
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -0,0 +1,279 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["TestRunner"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+const APPLY_CONFIG_TIMEOUT_MS = 60 * 1000;
+const HOME_PAGE = "chrome://mozscreenshots/content/lib/mozscreenshots.html";
+
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserTestUtils",
+ "resource://testing-common/BrowserTestUtils.jsm");
+
+Cu.import("chrome://mozscreenshots/content/Screenshot.jsm");
+
+// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+ let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+ let consoleOptions = {
+ maxLogLevel: "info",
+ maxLogLevelPref: PREF_LOG_LEVEL,
+ prefix: "mozscreenshots",
+ };
+ return new ConsoleAPI(consoleOptions);
+});
+
+this.TestRunner = {
+ combos: null,
+ completedCombos: 0,
+ currentComboIndex: 0,
+ _lastCombo: null,
+ _libDir: null,
+
+ init(extensionPath) {
+ log.debug("init");
+ this._extensionPath = extensionPath;
+ },
+
+ /**
+ * Load specified sets, execute all combinations of them, and capture screenshots.
+ */
+ start: Task.async(function*(setNames, jobName = null) {
+ let subDirs = ["mozscreenshots",
+ (new Date()).toISOString().replace(/:/g, "-") + "_" + Services.appinfo.OS];
+ let screenshotPath = FileUtils.getFile("TmpD", subDirs).path;
+
+ const MOZ_UPLOAD_DIR = env.get("MOZ_UPLOAD_DIR");
+ if (MOZ_UPLOAD_DIR) {
+ screenshotPath = MOZ_UPLOAD_DIR;
+ }
+
+ log.info("Saving screenshots to:", screenshotPath);
+
+ let screenshotPrefix = Services.appinfo.appBuildID;
+ if (jobName) {
+ screenshotPrefix += "-" + jobName;
+ }
+ screenshotPrefix += "_";
+ Screenshot.init(screenshotPath, this._extensionPath, screenshotPrefix);
+ this._libDir = this._extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
+ this._libDir.append("chrome");
+ this._libDir.append("mozscreenshots");
+ this._libDir.append("lib");
+
+ let sets = this.loadSets(setNames);
+
+ log.info(sets.length + " sets:", setNames);
+ this.combos = new LazyProduct(sets);
+ log.info(this.combos.length + " combinations");
+
+ this.currentComboIndex = this.completedCombos = 0;
+ this._lastCombo = null;
+
+ // Setup some prefs
+ Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl",
+ "data:text/html;charset=utf-8,Generated by mozscreenshots");
+ Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
+ // Don't let the caret blink since it causes false positives for image diffs
+ Services.prefs.setIntPref("ui.caretBlinkTime", -1);
+
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let selectedBrowser = browserWindow.gBrowser.selectedBrowser;
+ yield BrowserTestUtils.loadURI(selectedBrowser, HOME_PAGE);
+ yield BrowserTestUtils.browserLoaded(selectedBrowser);
+
+ for (let i = 0; i < this.combos.length; i++) {
+ this.currentComboIndex = i;
+ yield this._performCombo(this.combos.item(this.currentComboIndex));
+ }
+
+ log.info("Done: Completed " + this.completedCombos + " out of " +
+ this.combos.length + " configurations.");
+ this.cleanup();
+ }),
+
+ /**
+ * Load sets of configurations from JSMs.
+ * @param {String[]} setNames - array of set names (e.g. ["Tabs", "WindowSize"].
+ * @return {Object[]} Array of sets containing `name` and `configurations` properties.
+ */
+ loadSets(setNames) {
+ let sets = [];
+ for (let setName of setNames) {
+ try {
+ let imported = {};
+ Cu.import("chrome://mozscreenshots/content/configurations/" + setName + ".jsm",
+ imported);
+ imported[setName].init(this._libDir);
+ let configurationNames = Object.keys(imported[setName].configurations);
+ if (!configurationNames.length) {
+ throw new Error(setName + " has no configurations for this environment");
+ }
+ for (let config of configurationNames) {
+ // Automatically set the name property of the configuration object to
+ // its name from the configuration object.
+ imported[setName].configurations[config].name = config;
+ }
+ sets.push(imported[setName].configurations);
+ } catch (ex) {
+ log.error("Error loading set: " + setName);
+ log.error(ex);
+ throw ex;
+ }
+ }
+ return sets;
+ },
+
+ cleanup() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ while (gBrowser.tabs.length > 1) {
+ gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+ }
+ gBrowser.unpinTab(gBrowser.selectedTab);
+ gBrowser.selectedBrowser.loadURI("data:text/html;charset=utf-8,<h1>Done!");
+ browserWindow.restore();
+ },
+
+ // helpers
+
+ _performCombo: function*(combo) {
+ let paddedComboIndex = padLeft(this.currentComboIndex + 1, String(this.combos.length).length);
+ log.info("Combination " + paddedComboIndex + "/" + this.combos.length + ": " +
+ this._comboName(combo).substring(1));
+
+ function changeConfig(config) {
+ log.debug("calling " + config.name);
+ let applyPromise = Promise.resolve(config.applyConfig());
+ let timeoutPromise = new Promise((resolve, reject) => {
+ setTimeout(reject, APPLY_CONFIG_TIMEOUT_MS, "Timed out");
+ });
+ log.debug("called " + config.name);
+ // Add a default timeout of 500ms to avoid conflicts when configurations
+ // try to apply at the same time. e.g WindowSize and TabsInTitlebar
+ return Promise.race([applyPromise, timeoutPromise]).then(() => {
+ return new Promise((resolve) => {
+ setTimeout(resolve, 500);
+ });
+ });
+ }
+
+ try {
+ // First go through and actually apply all of the configs
+ for (let i = 0; i < combo.length; i++) {
+ let config = combo[i];
+ if (!this._lastCombo || config !== this._lastCombo[i]) {
+ log.debug("promising", config.name);
+ yield changeConfig(config);
+ }
+ }
+
+ // Update the lastCombo since it's now been applied regardless of whether it's accepted below.
+ log.debug("fulfilled all applyConfig so setting lastCombo.");
+ this._lastCombo = combo;
+
+ // Then ask configs if the current setup is valid. We can't can do this in
+ // the applyConfig methods of the config since it doesn't know what configs
+ // later in the loop will do that may invalidate the combo.
+ for (let i = 0; i < combo.length; i++) {
+ let config = combo[i];
+ // A configuration can specify an optional verifyConfig method to indicate
+ // if the current config is valid for a screenshot. This gets called even
+ // if the this config was used in the lastCombo since another config may
+ // have invalidated it.
+ if (config.verifyConfig) {
+ log.debug("checking if the combo is valid with", config.name);
+ yield config.verifyConfig();
+ }
+ }
+ } catch (ex) {
+ log.warn("\tskipped configuration: " + ex);
+ // Don't set lastCombo here so that we properly know which configurations
+ // need to be applied since the last screenshot
+
+ // Return so we don't take a screenshot.
+ return;
+ }
+
+ yield this._onConfigurationReady(combo);
+ },
+
+ _onConfigurationReady(combo) {
+ let delayedScreenshot = () => {
+ let filename = padLeft(this.currentComboIndex + 1,
+ String(this.combos.length).length) + this._comboName(combo);
+ return Screenshot.captureExternal(filename)
+ .then(() => {
+ this.completedCombos++;
+ });
+ };
+
+ log.debug("_onConfigurationReady");
+ return Task.spawn(delayedScreenshot);
+ },
+
+ _comboName(combo) {
+ return combo.reduce(function(a, b) {
+ return a + "_" + b.name;
+ }, "");
+ },
+};
+
+/**
+ * Helper to lazily compute the Cartesian product of all of the sets of configurations.
+ **/
+function LazyProduct(sets) {
+ /**
+ * An entry for each set with the value being:
+ * [the number of permutations of the sets with lower index,
+ * the number of items in the set at the index]
+ */
+ this.sets = sets;
+ this.lookupTable = [];
+ let combinations = 1;
+ for (let i = this.sets.length - 1; i >= 0; i--) {
+ let set = this.sets[i];
+ let setLength = Object.keys(set).length;
+ this.lookupTable[i] = [combinations, setLength];
+ combinations *= setLength;
+ }
+}
+LazyProduct.prototype = {
+ get length() {
+ let last = this.lookupTable[0];
+ if (!last)
+ return 0;
+ return last[0] * last[1];
+ },
+
+ item(n) {
+ // For set i, get the item from the set with the floored value of
+ // (n / the number of permutations of the sets already chosen from) modulo the length of set i
+ let result = [];
+ for (let i = this.sets.length - 1; i >= 0; i--) {
+ let priorCombinations = this.lookupTable[i][0];
+ let setLength = this.lookupTable[i][1];
+ let keyIndex = Math.floor(n / priorCombinations) % setLength;
+ let keys = Object.keys(this.sets[i]);
+ result[i] = this.sets[i][keys[keyIndex]];
+ }
+ return result;
+ },
+};
+
+function padLeft(number, width, padding = "0") {
+ return padding.repeat(Math.max(0, width - String(number).length)) + number;
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js b/browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js
new file mode 100644
index 000000000..c7e238606
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+#if 0
+Workaround a build system bug where this file doesn't get packaged if not pre-processed.
+#endif
+*/
+
+/* exported install, uninstall, startup, shutdown */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AddonManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "TestRunner",
+ "chrome://mozscreenshots/content/TestRunner.jsm");
+
+function install(data, reason) {
+ if (!isAppSupported()) {
+ uninstallExtension(data);
+ return;
+ }
+
+ AddonManager.getAddonByID(data.id, function(addon) {
+ // Enable on install in case the user disabled a prior version
+ if (addon) {
+ addon.userDisabled = false;
+ }
+ });
+}
+
+function startup(data, reason) {
+ if (!isAppSupported()) {
+ uninstallExtension(data);
+ return;
+ }
+
+ AddonManager.getAddonByID(data.id, function(addon) {
+ let extensionPath = addon.getResourceURI();
+ TestRunner.init(extensionPath);
+ });
+}
+
+function shutdown(data, reason) { }
+
+function uninstall(data, reason) { }
+
+/**
+ * @return boolean whether the test suite applies to the application.
+ */
+function isAppSupported() {
+ return true;
+}
+
+function uninstallExtension(data) {
+ AddonManager.getAddonByID(data.id, function(addon) {
+ addon.uninstall();
+ });
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
new file mode 100644
index 000000000..5dbb2c1e2
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["AppMenu"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.AppMenu = {
+
+ init(libDir) {},
+
+ configurations: {
+ appMenuClosed: {
+ applyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ browserWindow.PanelUI.hide();
+ }),
+ },
+
+ appMenuMainView: {
+ applyConfig() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let promise = browserWindow.PanelUI.show();
+ browserWindow.PanelUI.showMainView();
+ return promise;
+ },
+ },
+
+ appMenuHistorySubview: {
+ applyConfig() {
+ // History has a footer
+ if (isCustomizing()) {
+ return Promise.reject("Can't show subviews while customizing");
+ }
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let promise = browserWindow.PanelUI.show();
+ return promise.then(() => {
+ browserWindow.PanelUI.showMainView();
+ browserWindow.document.getElementById("history-panelmenu").click();
+ });
+ },
+
+ verifyConfig: verifyConfigHelper,
+ },
+
+ appMenuHelpSubview: {
+ applyConfig() {
+ if (isCustomizing()) {
+ return Promise.reject("Can't show subviews while customizing");
+ }
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let promise = browserWindow.PanelUI.show();
+ return promise.then(() => {
+ browserWindow.PanelUI.showMainView();
+ browserWindow.document.getElementById("PanelUI-help").click();
+ });
+ },
+
+ verifyConfig: verifyConfigHelper,
+ },
+
+ },
+};
+
+function verifyConfigHelper() {
+ if (isCustomizing()) {
+ return Promise.reject("AppMenu verifyConfigHelper");
+ }
+ return Promise.resolve("AppMenu verifyConfigHelper");
+}
+
+function isCustomizing() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.document.documentElement.hasAttribute("customizing")) {
+ return true;
+ }
+ return false;
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
new file mode 100644
index 000000000..97d8354d5
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["Buttons"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource:///modules/CustomizableUI.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.Buttons = {
+
+ init(libDir) {
+ createWidget();
+ },
+
+ configurations: {
+ navBarButtons: {
+ applyConfig: Task.async(() => {
+ CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_NAVBAR);
+ }),
+ },
+
+ tabsToolbarButtons: {
+ applyConfig: Task.async(() => {
+ CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_TABSTRIP);
+ }),
+ },
+
+ menuPanelButtons: {
+ applyConfig: Task.async(() => {
+ CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_PANEL);
+ }),
+
+ verifyConfig() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.PanelUI.panel.state == "closed") {
+ return Promise.reject("The button isn't shown when the panel isn't open.");
+ }
+ return Promise.resolve("menuPanelButtons.verifyConfig");
+ },
+ },
+
+ custPaletteButtons: {
+ applyConfig: Task.async(() => {
+ CustomizableUI.removeWidgetFromArea("screenshot-widget");
+ }),
+
+ verifyConfig() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.document.documentElement.getAttribute("customizing") != "true") {
+ return Promise.reject("The button isn't shown when we're not in customize mode.");
+ }
+ return Promise.resolve("custPaletteButtons.verifyConfig");
+ },
+ },
+ },
+};
+
+function createWidget() {
+ let id = "screenshot-widget";
+ let spec = {
+ id: id,
+ label: "My Button",
+ removable: true,
+ tooltiptext: "",
+ type: "button",
+ };
+ CustomizableUI.createWidget(spec);
+
+ // Append a <style> for the image
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let st = browserWindow.document.createElementNS("http://www.w3.org/1999/xhtml", "style");
+ let styles = "" +
+ "#screenshot-widget > .toolbarbutton-icon {" +
+ " list-style-image: url(chrome://browser/skin/Toolbar.png);" +
+ " -moz-image-region: rect(0px, 18px, 18px, 0px);" +
+ "}";
+ st.appendChild(browserWindow.document.createTextNode(styles));
+ browserWindow.document.documentElement.appendChild(st);
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
new file mode 100644
index 000000000..ed4d92b4f
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
@@ -0,0 +1,243 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ControlCenter"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+Cu.import("resource:///modules/SitePermissions.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+
+let {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
+
+const RESOURCE_PATH = "extensions/mozscreenshots/browser/chrome/mozscreenshots/lib/controlCenter";
+const HTTP_PAGE = "http://example.com/";
+const HTTPS_PAGE = "https://example.com/";
+const PERMISSIONS_PAGE = "https://test1.example.com/";
+const HTTP_PASSWORD_PAGE = `http://test2.example.org/${RESOURCE_PATH}/password.html`;
+const MIXED_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed.html`;
+const MIXED_ACTIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_active.html`;
+const MIXED_PASSIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_passive.html`;
+const TRACKING_PAGE = `http://tracking.example.org/${RESOURCE_PATH}/tracking.html`;
+
+this.ControlCenter = {
+ init(libDir) { },
+
+ configurations: {
+ about: {
+ applyConfig: Task.async(function* () {
+ yield loadPage("about:home");
+ yield openIdentityPopup();
+ }),
+ },
+
+ localFile: {
+ applyConfig: Task.async(function* () {
+ let channel = NetUtil.newChannel({
+ uri: "chrome://mozscreenshots/content/lib/mozscreenshots.html",
+ loadUsingSystemPrincipal: true
+ });
+ channel = channel.QueryInterface(Ci.nsIFileChannel);
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ BrowserTestUtils.loadURI(gBrowser.selectedBrowser, channel.file.path);
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ yield openIdentityPopup();
+ }),
+ },
+
+ http: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTP_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ httpSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTP_PAGE);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ https: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTPS_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ httpsSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTPS_PAGE);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ singlePermission: {
+ applyConfig: Task.async(function* () {
+ let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
+ SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
+
+ yield loadPage(PERMISSIONS_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ allPermissions: {
+ applyConfig: Task.async(function* () {
+ // there are 3 possible non-default permission states, so we alternate between them
+ let states = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.SESSION];
+ let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
+ SitePermissions.listPermissions().forEach(function (permission, index) {
+ SitePermissions.set(uri, permission, states[index % 3]);
+ });
+
+ yield loadPage(PERMISSIONS_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ mixed: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_CONTENT_URL);
+ yield openIdentityPopup();
+ }),
+ },
+
+ mixedSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_CONTENT_URL);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ mixedPassive: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_PASSIVE_CONTENT_URL);
+ yield openIdentityPopup();
+ }),
+ },
+
+ mixedPassiveSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_PASSIVE_CONTENT_URL);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ mixedActive: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_ACTIVE_CONTENT_URL);
+ yield openIdentityPopup();
+ }),
+ },
+
+ mixedActiveSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(MIXED_ACTIVE_CONTENT_URL);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ mixedActiveUnblocked: {
+ applyConfig: Task.async(function* () {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ yield loadPage(MIXED_ACTIVE_CONTENT_URL);
+ gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
+ yield openIdentityPopup();
+ }),
+ },
+
+ mixedActiveUnblockedSubView: {
+ applyConfig: Task.async(function* () {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ yield loadPage(MIXED_ACTIVE_CONTENT_URL);
+ gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ httpPassword: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTP_PASSWORD_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ httpPasswordSubView: {
+ applyConfig: Task.async(function* () {
+ yield loadPage(HTTP_PASSWORD_PAGE);
+ yield openIdentityPopup(true);
+ }),
+ },
+
+ trackingProtectionNoElements: {
+ applyConfig: Task.async(function* () {
+ Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
+
+ yield loadPage(HTTP_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ trackingProtectionEnabled: {
+ applyConfig: Task.async(function* () {
+ Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
+ Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
+ yield UrlClassifierTestUtils.addTestTrackers();
+
+ yield loadPage(TRACKING_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+
+ trackingProtectionDisabled: {
+ applyConfig: Task.async(function* () {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
+ Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
+ yield UrlClassifierTestUtils.addTestTrackers();
+
+ yield loadPage(TRACKING_PAGE);
+ yield openIdentityPopup();
+ // unblock the page
+ gBrowser.ownerGlobal.document.querySelector("#tracking-action-unblock").click();
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, TRACKING_PAGE);
+ yield openIdentityPopup();
+ }),
+ },
+ },
+};
+
+function* loadPage(url) {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, url);
+}
+
+function* openIdentityPopup(expand) {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ let { gIdentityHandler } = gBrowser.ownerGlobal;
+ gIdentityHandler._identityPopup.hidePopup();
+ gIdentityHandler._identityBox.querySelector("#identity-icon").click();
+ if (expand) {
+ // give some time for opening to avoid weird style issues
+ yield new Promise((c) => setTimeout(c, 500));
+ gIdentityHandler._identityPopup.querySelector("#identity-popup-security-expander").click();
+ }
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm
new file mode 100644
index 000000000..bb856508b
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["CustomizeMode"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.CustomizeMode = {
+
+ init(libDir) {},
+
+ configurations: {
+ notCustomizing: {
+ applyConfig() {
+ return new Promise((resolve) => {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (!browserWindow.document.documentElement.hasAttribute("customizing")) {
+ resolve("notCustomizing: already not customizing");
+ return;
+ }
+ function onCustomizationEnds() {
+ browserWindow.gNavToolbox.removeEventListener("aftercustomization",
+ onCustomizationEnds);
+ // Wait for final changes
+ setTimeout(() => resolve("notCustomizing: onCustomizationEnds"), 500);
+ }
+ browserWindow.gNavToolbox.addEventListener("aftercustomization",
+ onCustomizationEnds);
+ browserWindow.gCustomizeMode.exit();
+ });
+ },
+ },
+
+ customizing: {
+ applyConfig() {
+ return new Promise((resolve) => {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.document.documentElement.hasAttribute("customizing")) {
+ resolve("customizing: already customizing");
+ return;
+ }
+ function onCustomizing() {
+ browserWindow.gNavToolbox.removeEventListener("customizationready",
+ onCustomizing);
+ // Wait for final changes
+ setTimeout(() => resolve("customizing: onCustomizing"), 500);
+ }
+ browserWindow.gNavToolbox.addEventListener("customizationready",
+ onCustomizing);
+ browserWindow.gCustomizeMode.enter();
+ });
+ },
+ },
+ },
+};
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm
new file mode 100644
index 000000000..fd981bca3
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["DevEdition"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+const THEME_ID = "firefox-devedition@mozilla.org";
+
+Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.DevEdition = {
+ init(libDir) {},
+
+ configurations: {
+ devEditionLight: {
+ applyConfig: Task.async(() => {
+ Services.prefs.setCharPref("devtools.theme", "light");
+ LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID);
+ Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+ }),
+ },
+ devEditionDark: {
+ applyConfig: Task.async(() => {
+ Services.prefs.setCharPref("devtools.theme", "dark");
+ LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID);
+ Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+ }),
+ },
+ devEditionOff: {
+ applyConfig: Task.async(() => {
+ Services.prefs.clearUserPref("devtools.theme");
+ LightweightThemeManager.currentTheme = null;
+ Services.prefs.clearUserPref("browser.devedition.theme.showCustomizeButton");
+ }),
+ },
+ },
+};
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
new file mode 100644
index 000000000..f06000b4c
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["DevTools"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://devtools/client/framework/gDevTools.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+let { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+let TargetFactory = devtools.TargetFactory;
+
+function getTargetForSelectedTab() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let target = TargetFactory.forTab(browserWindow.gBrowser.selectedTab);
+ return target;
+}
+
+this.DevTools = {
+ init(libDir) {
+ let panels = ["options", "webconsole", "jsdebugger", "styleeditor",
+ "performance", "netmonitor"];
+
+ panels.forEach(panel => {
+ this.configurations[panel] = {};
+ this.configurations[panel].applyConfig = Task.async(function* () {
+ yield gDevTools.showToolbox(getTargetForSelectedTab(), panel, "bottom");
+ yield new Promise(resolve => setTimeout(resolve, 500));
+ });
+ });
+ },
+
+ configurations: {
+ bottomToolbox: {
+ applyConfig: Task.async(function* () {
+ yield gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "bottom");
+ yield new Promise(resolve => setTimeout(resolve, 1000));
+ }),
+ },
+ sideToolbox: {
+ applyConfig: Task.async(function* () {
+ yield gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "side");
+ yield new Promise(resolve => setTimeout(resolve, 500));
+ }),
+ },
+ undockedToolbox: {
+ applyConfig: Task.async(function* () {
+ yield gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "window");
+ yield new Promise(resolve => setTimeout(resolve, 500));
+ }),
+ }
+ },
+};
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
new file mode 100644
index 000000000..52d0c2207
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["LightweightThemes"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.LightweightThemes = {
+ init(libDir) {
+ // convert -size 3000x200 canvas:#333 black_theme.png
+ let blackImage = libDir.clone();
+ blackImage.append("black_theme.png");
+ this._blackImageURL = Services.io.newFileURI(blackImage).spec;
+
+ // convert -size 3000x200 canvas:#eee white_theme.png
+ let whiteImage = libDir.clone();
+ whiteImage.append("white_theme.png");
+ this._whiteImageURL = Services.io.newFileURI(whiteImage).spec;
+ },
+
+ configurations: {
+ noLWT: {
+ applyConfig: Task.async(function*() {
+ LightweightThemeManager.currentTheme = null;
+ }),
+ },
+
+ darkLWT: {
+ applyConfig() {
+ LightweightThemeManager.setLocalTheme({
+ id: "black",
+ name: "black",
+ headerURL: LightweightThemes._blackImageURL,
+ footerURL: LightweightThemes._blackImageURL,
+ textcolor: "#eeeeee",
+ accentcolor: "#111111",
+ });
+
+ // Wait for LWT listener
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve("darkLWT");
+ }, 500);
+ });
+ },
+
+ verifyConfig: verifyConfigHelper,
+ },
+
+ lightLWT: {
+ applyConfig() {
+ LightweightThemeManager.setLocalTheme({
+ id: "white",
+ name: "white",
+ headerURL: LightweightThemes._whiteImageURL,
+ footerURL: LightweightThemes._whiteImageURL,
+ textcolor: "#111111",
+ accentcolor: "#eeeeee",
+ });
+ // Wait for LWT listener
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve("lightLWT");
+ }, 500);
+ });
+ },
+
+ verifyConfig: verifyConfigHelper,
+ },
+
+ },
+};
+
+
+function verifyConfigHelper() {
+ return new Promise((resolve, reject) => {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.document.documentElement.hasAttribute("lwtheme")) {
+ resolve("verifyConfigHelper");
+ } else {
+ reject("The @lwtheme attribute wasn't present so themes may not be available");
+ }
+ });
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm
new file mode 100644
index 000000000..5e5a988c4
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm
@@ -0,0 +1,130 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["PermissionPrompts"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource:///modules/E10SUtils.jsm");
+Cu.import("resource://testing-common/ContentTask.jsm");
+Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+
+const URL = "https://test1.example.com/extensions/mozscreenshots/browser/chrome/mozscreenshots/lib/permissionPrompts.html";
+let lastTab = null;
+
+this.PermissionPrompts = {
+ init(libDir) {
+ Services.prefs.setBoolPref("media.navigator.permission.fake", true);
+ Services.prefs.setBoolPref("media.getusermedia.screensharing.allow_on_old_platforms", true);
+ Services.prefs.setCharPref("media.getusermedia.screensharing.allowed_domains",
+ "test1.example.com");
+ Services.prefs.setBoolPref("extensions.install.requireBuiltInCerts", false);
+ },
+
+ configurations: {
+ shareDevices: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#webRTC-shareDevices");
+ }),
+ },
+
+ shareMicrophone: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#webRTC-shareMicrophone");
+ }),
+ },
+
+ shareVideoAndMicrophone: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#webRTC-shareDevices2");
+ }),
+ },
+
+ shareScreen: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#webRTC-shareScreen");
+ }),
+ },
+
+ geo: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#geo");
+ }),
+ },
+
+ loginCapture: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#login-capture", URL);
+ }),
+ },
+
+ notifications: {
+ applyConfig: Task.async(function*() {
+ yield closeLastTab();
+ yield clickOn("#web-notifications", URL);
+ }),
+ },
+
+ addons: {
+ applyConfig: Task.async(function*() {
+ Services.prefs.setBoolPref("xpinstall.whitelist.required", true);
+
+ yield closeLastTab();
+ yield clickOn("#addons", URL);
+ }),
+ },
+
+ addonsNoWhitelist: {
+ applyConfig: Task.async(function*() {
+ Services.prefs.setBoolPref("xpinstall.whitelist.required", false);
+
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let notification = browserWindow.document.getElementById("addon-install-confirmation-notification");
+
+ yield closeLastTab();
+ yield clickOn("#addons", URL);
+
+ // We want to skip the progress-notification, so we wait for
+ // the install-confirmation screen to be "not hidden" = shown.
+ yield BrowserTestUtils.waitForCondition(() => !notification.hasAttribute("hidden"),
+ "addon install confirmation did not show", 200);
+ }),
+ },
+ },
+};
+
+function* closeLastTab(selector) {
+ if (!lastTab) {
+ return;
+ }
+ yield BrowserTestUtils.removeTab(lastTab);
+ lastTab = null;
+}
+
+function* clickOn(selector) {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+
+ // Save the tab so we can close it later.
+ lastTab = yield BrowserTestUtils.openNewForegroundTab(browserWindow.gBrowser, URL);
+
+ yield ContentTask.spawn(lastTab.linkedBrowser, selector, function* (arg) {
+ E10SUtils.wrapHandlingUserInput(content, true, function() {
+ let element = content.document.querySelector(arg);
+ element.click();
+ });
+ });
+
+ // Wait for the popup to actually be shown before making the screenshot
+ yield BrowserTestUtils.waitForEvent(browserWindow.PopupNotifications.panel, "popupshown");
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
new file mode 100644
index 000000000..aa2b3f2a7
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["Preferences"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://testing-common/TestUtils.jsm");
+Cu.import("resource://testing-common/ContentTask.jsm");
+
+this.Preferences = {
+
+ init(libDir) {
+ let panes = [
+ ["paneGeneral", null],
+ ["paneSearch", null],
+ ["paneContent", null],
+ ["paneApplications", null],
+ ["panePrivacy", null],
+ ["panePrivacy", null, DNTDialog],
+ ["panePrivacy", null, clearRecentHistoryDialog],
+ ["paneSecurity", null],
+ ["paneSync", null],
+ ["paneAdvanced", "generalTab"],
+ ["paneAdvanced", "dataChoicesTab"],
+ ["paneAdvanced", "networkTab"],
+ ["paneAdvanced", "networkTab", connectionDialog],
+ ["paneAdvanced", "updateTab"],
+ ["paneAdvanced", "encryptionTab"],
+ ["paneAdvanced", "encryptionTab", certManager],
+ ["paneAdvanced", "encryptionTab", deviceManager],
+ ];
+ for (let [primary, advanced, customFn] of panes) {
+ let configName = primary.replace(/^pane/, "prefs") + (advanced ? "-" + advanced : "");
+ if (customFn) {
+ configName += "-" + customFn.name;
+ }
+ this.configurations[configName] = {};
+ this.configurations[configName].applyConfig = prefHelper.bind(null, primary, advanced, customFn);
+ }
+ },
+
+ configurations: {},
+};
+
+let prefHelper = Task.async(function*(primary, advanced = null, customFn = null) {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let selectedBrowser = browserWindow.gBrowser.selectedBrowser;
+
+ // close any dialog that might still be open
+ yield ContentTask.spawn(selectedBrowser, null, function*() {
+ if (!content.window.gSubDialog) {
+ return;
+ }
+ content.window.gSubDialog.close();
+ });
+
+ let readyPromise = null;
+ if (selectedBrowser.currentURI.specIgnoringRef == "about:preferences") {
+ if (selectedBrowser.currentURI.spec == "about:preferences#" + primary.replace(/^pane/, "")) {
+ // We're already on the correct pane.
+ readyPromise = Promise.resolve();
+ } else {
+ readyPromise = paintPromise(browserWindow);
+ }
+ } else {
+ readyPromise = TestUtils.topicObserved("advanced-pane-loaded");
+ }
+
+ if (primary == "paneAdvanced") {
+ browserWindow.openAdvancedPreferences(advanced);
+ } else {
+ browserWindow.openPreferences(primary);
+ }
+
+ yield readyPromise;
+
+ if (customFn) {
+ let customPaintPromise = paintPromise(browserWindow);
+ yield* customFn(selectedBrowser);
+ yield customPaintPromise;
+ }
+});
+
+function paintPromise(browserWindow) {
+ return new Promise((resolve) => {
+ browserWindow.addEventListener("MozAfterPaint", function onPaint() {
+ browserWindow.removeEventListener("MozAfterPaint", onPaint);
+ resolve();
+ });
+ });
+}
+
+function* DNTDialog(aBrowser) {
+ yield ContentTask.spawn(aBrowser, null, function* () {
+ content.document.getElementById("doNotTrackSettings").click();
+ });
+}
+
+function* connectionDialog(aBrowser) {
+ yield ContentTask.spawn(aBrowser, null, function* () {
+ content.document.getElementById("connectionSettings").click();
+ });
+}
+
+function* clearRecentHistoryDialog(aBrowser) {
+ yield ContentTask.spawn(aBrowser, null, function* () {
+ content.document.getElementById("historyRememberClear").click();
+ });
+}
+
+function* certManager(aBrowser) {
+ yield ContentTask.spawn(aBrowser, null, function* () {
+ content.document.getElementById("viewCertificatesButton").click();
+ });
+}
+
+function* deviceManager(aBrowser) {
+ yield ContentTask.spawn(aBrowser, null, function* () {
+ content.document.getElementById("viewSecurityDevicesButton").click();
+ });
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
new file mode 100644
index 000000000..f2ff43561
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
@@ -0,0 +1,152 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["Tabs"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+const CUST_TAB = "chrome://browser/skin/customizableui/customizeFavicon.ico";
+const PREFS_TAB = "chrome://browser/skin/preferences/in-content/favicon.ico";
+const DEFAULT_FAVICON_TAB = `data:text/html,<meta charset="utf-8">
+<title>No favicon</title>`;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.Tabs = {
+ init(libDir) {},
+
+ configurations: {
+ fiveTabs: {
+ applyConfig: Task.async(function*() {
+ fiveTabsHelper();
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ hoverTab(browserWindow.gBrowser.tabs[3]);
+ yield new Promise((resolve, reject) => {
+ setTimeout(resolve, 3000);
+ });
+ }),
+ },
+
+ fourPinned: {
+ applyConfig: Task.async(function*() {
+ fiveTabsHelper();
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let tab = browserWindow.gBrowser.addTab(PREFS_TAB);
+ browserWindow.gBrowser.pinTab(tab);
+ tab = browserWindow.gBrowser.addTab(CUST_TAB);
+ browserWindow.gBrowser.pinTab(tab);
+ tab = browserWindow.gBrowser.addTab("about:privatebrowsing");
+ browserWindow.gBrowser.pinTab(tab);
+ tab = browserWindow.gBrowser.addTab("about:home");
+ browserWindow.gBrowser.pinTab(tab);
+ browserWindow.gBrowser.selectTabAtIndex(5);
+ hoverTab(browserWindow.gBrowser.tabs[2]);
+ // also hover the new tab button
+ let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.
+ gBrowser.tabContainer, "class", "tabs-newtab-button");
+ hoverTab(newTabButton);
+ browserWindow.gBrowser.tabs[browserWindow.gBrowser.tabs.length - 1].
+ setAttribute("beforehovered", true);
+ yield new Promise((resolve, reject) => {
+ setTimeout(resolve, 3000);
+ });
+ }),
+ },
+
+ twoPinnedWithOverflow: {
+ applyConfig: Task.async(function*() {
+ fiveTabsHelper();
+
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ browserWindow.gBrowser.loadTabs([
+ PREFS_TAB,
+ CUST_TAB,
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ ], true, true);
+ browserWindow.gBrowser.pinTab(browserWindow.gBrowser.tabs[1]);
+ browserWindow.gBrowser.pinTab(browserWindow.gBrowser.tabs[2]);
+ browserWindow.gBrowser.selectTabAtIndex(3);
+ hoverTab(browserWindow.gBrowser.tabs[5]);
+ yield new Promise((resolve, reject) => {
+ setTimeout(resolve, 3000);
+ });
+ }),
+ },
+ },
+};
+
+
+/* helpers */
+
+function fiveTabsHelper() {
+ // some with no favicon and some with. Selected tab in middle.
+ closeAllButOneTab("about:addons");
+
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ browserWindow.gBrowser.loadTabs([
+ "about:addons",
+ "about:home",
+ DEFAULT_FAVICON_TAB,
+ "about:newtab",
+ CUST_TAB,
+ ], true, true);
+ browserWindow.gBrowser.selectTabAtIndex(1);
+}
+
+function closeAllButOneTab(url = "about:blank") {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let gBrowser = browserWindow.gBrowser;
+ // Close all tabs except the last so we don't quit the browser.
+ while (gBrowser.tabs.length > 1)
+ gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+ gBrowser.selectedBrowser.loadURI(url);
+ if (gBrowser.selectedTab.pinned)
+ gBrowser.unpinTab(gBrowser.selectedTab);
+ let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button");
+ hoverTab(newTabButton, false);
+}
+
+function hoverTab(tab, hover = true) {
+ const inIDOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
+ if (hover) {
+ inIDOMUtils.addPseudoClassLock(tab, ":hover");
+ } else {
+ inIDOMUtils.clearPseudoClassLocks(tab);
+ }
+ // XXX TODO: this isn't necessarily testing what we ship
+ if (tab.nextElementSibling)
+ tab.nextElementSibling.setAttribute("afterhovered", hover || null);
+ if (tab.previousElementSibling)
+ tab.previousElementSibling.setAttribute("beforehovered", hover || null);
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
new file mode 100644
index 000000000..5b9d7d9b9
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["TabsInTitlebar"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+const PREF_TABS_IN_TITLEBAR = "browser.tabs.drawInTitlebar";
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.TabsInTitlebar = {
+
+ init(libDir) {},
+
+ configurations: {
+ tabsInTitlebar: {
+ applyConfig: Task.async(function*() {
+ if (Services.appinfo.OS == "Linux") {
+ return Promise.reject("TabsInTitlebar isn't supported on Linux");
+ }
+ Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, true);
+ return undefined;
+ }),
+ },
+
+ tabsOutsideTitlebar: {
+ applyConfig: Task.async(function*() {
+ Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, false);
+ }),
+ },
+
+ },
+};
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
new file mode 100644
index 000000000..ee284bf97
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["Toolbars"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.Toolbars = {
+ init(libDir) {},
+
+ configurations: {
+ onlyNavBar: {
+ applyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
+ browserWindow.setToolbarVisibility(personalToolbar, false);
+ toggleMenubarIfNecessary(false);
+ }),
+ },
+
+ allToolbars: {
+ applyConfig: Task.async(function*() { // Boookmarks and menubar
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ let personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
+ browserWindow.setToolbarVisibility(personalToolbar, true);
+ toggleMenubarIfNecessary(true);
+ }),
+
+ verifyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (browserWindow.fullScreen) {
+ return Promise.reject("The bookmark toolbar and menubar are not shown in fullscreen.");
+ }
+ return undefined;
+ }),
+ },
+
+ },
+};
+
+
+// helpers
+
+function toggleMenubarIfNecessary(visible) {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ // The menubar is not shown on OS X or while in fullScreen
+ if (Services.appinfo.OS != "Darwin" /* && !browserWindow.fullScreen*/) {
+ let menubar = browserWindow.document.getElementById("toolbar-menubar");
+ browserWindow.setToolbarVisibility(menubar, visible);
+ }
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm
new file mode 100644
index 000000000..5cc0d6522
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["WindowSize"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+
+this.WindowSize = {
+
+ init(libDir) {
+ Services.prefs.setBoolPref("browser.fullscreen.autohide", false);
+ },
+
+ configurations: {
+ maximized: {
+ applyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ yield toggleFullScreen(browserWindow, false);
+
+ // Wait for the Lion fullscreen transition to end as there doesn't seem to be an event
+ // and trying to maximize while still leaving fullscreen doesn't work.
+ yield new Promise((resolve, reject) => {
+ setTimeout(function waitToLeaveFS() {
+ browserWindow.maximize();
+ resolve();
+ }, 5000);
+ });
+ }),
+ },
+
+ normal: {
+ applyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ yield toggleFullScreen(browserWindow, false);
+ browserWindow.restore();
+ yield new Promise((resolve, reject) => {
+ setTimeout(resolve, 5000);
+ });
+ }),
+ },
+
+ fullScreen: {
+ applyConfig: Task.async(function*() {
+ let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ yield toggleFullScreen(browserWindow, true);
+ // OS X Lion fullscreen transition takes a while
+ yield new Promise((resolve, reject) => {
+ setTimeout(resolve, 5000);
+ });
+ }),
+ },
+ },
+};
+
+function toggleFullScreen(browserWindow, wantsFS) {
+ browserWindow.fullScreen = wantsFS;
+ return BrowserTestUtils.waitForCondition(() => {
+ return wantsFS == browserWindow.document.documentElement.hasAttribute("inFullscreen");
+ }, "waiting for @inFullscreen change");
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf b/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf
new file mode 100644
index 000000000..429a35840
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>mozscreenshots@mozilla.org</em:id>
+#expand <em:version>__MOZILLA_VERSION_U__</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <!-- for running custom screenshot binaries -->
+ <em:unpack>true</em:unpack>
+
+ <!-- Front End MetaData -->
+ <em:name>mozscreenshots</em:name>
+ <em:description>Take screenshots of Mozilla applications in various UI configurations.</em:description>
+ <em:creator>Mozilla</em:creator>
+
+ <em:targetApplication>
+ <Description>
+ <!-- Firefox -->
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+#expand <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ </Description>
+</RDF>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn b/browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn
new file mode 100644
index 000000000..0f403013a
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn
@@ -0,0 +1,6 @@
+mozscreenshots.jar:
+% content mozscreenshots chrome/mozscreenshots/
+ Screenshot.jsm
+ TestRunner.jsm
+ configurations/ (configurations/*.jsm)
+ lib/ (lib/*)
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/black_theme.png b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/black_theme.png
new file mode 100644
index 000000000..78e47207b
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/black_theme.png
Binary files differ
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/borderify.xpi b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/borderify.xpi
new file mode 100644
index 000000000..66ae92ed2
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/borderify.xpi
Binary files differ
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed.html
new file mode 100644
index 000000000..9d2ef75c0
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Mixed Content test</title>
+ </head>
+ <body>
+ <iframe style="visibility:hidden" src="http://example.com"></iframe>
+ <img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
+ </body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_active.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_active.html
new file mode 100644
index 000000000..f43ff079f
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_active.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Mixed Active Content test</title>
+ </head>
+ <body>
+ <iframe style="visibility:hidden" src="http://example.com"></iframe>
+ </body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_passive.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_passive.html
new file mode 100644
index 000000000..ba8978267
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/mixed_passive.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Mixed Passive Content test</title>
+ </head>
+ <body>
+ <img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
+ </body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/password.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/password.html
new file mode 100644
index 000000000..010384270
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/password.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>HTTP Password test</title>
+ </head>
+ <body>
+ <form>
+ <input type="password" />
+ <button type="submit">Submit</button>
+ </form>
+ </body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/tracking.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/tracking.html
new file mode 100644
index 000000000..6fb230645
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/controlCenter/tracking.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Tracking test</title>
+ </head>
+ <body>
+ <iframe style="visibility:hidden" src="http://tracking.example.com/"></iframe>
+ </body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-script.js b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-script.js
new file mode 100644
index 000000000..66cdd8c86
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-script.js
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+console.log(document, document.body);
+console.assert(false, "Failing mozscreenshots assertion");
+
+console.group("Grouped Message");
+console.log("group message 1");
+console.groupEnd("Grouped Message");
+
+console.count("counter");
+console.count("counter");
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-style.css b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-style.css
new file mode 100644
index 000000000..145a4e57d
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-style.css
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+body {
+ --background-color: #f3f3f3;
+ background: tomato;
+}
+
+body {
+ background: var(--background-color);
+ color: #222;
+ padding: 0 10px;
+ margin: 0;
+}
+
+header {
+ background: #eee;
+ border-bottom: solid 2px #ccc;
+ margin: 0 -10px;
+ margin-bottom: 5px;
+ padding: 4px;
+}
+
+header h1 {
+ margin: 0;
+ padding: 0;
+}
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots.html
new file mode 100644
index 000000000..6778cf7da
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>mozscreenshots</title>
+ <link rel="stylesheet" href="mozscreenshots-style.css" />
+ <script>console.info("This page was generated by mozscreenshots");</script>
+ </head>
+
+<body>
+ <header><h1>mozscreenshots</h1></header>
+
+ <p>
+ This page was generated by mozscreenshots
+ </p>
+
+ <img src="robot.png" />
+
+ <p>Welcome Humans! We invite others to keep the Manifesto’s principles; use the creation delivery and commitment. Advancing the Manifesto. We have shiny metal posteriors which <strong>should not be bitten</strong>. And they have distilled a public benefit is committed to use Mozilla project one basic and communities of modern life.</p>
+
+ <p>Robots have <mark>distilled a balance between commercial aspects of life</mark>.</p>
+
+ <p>Robots may not they have shown in education communication collaboration business entertainment and other people to pursue; speak to continue; and opportunity are many different ways to benefit the public benefit the Manifesto’s principles; build and motivate us and trademarks infrastructure funds and trademarks infrastructure funds and enable open-source technologies and provide a whole. </p>
+
+ <p>And they have seen things you people who believe that Mozilla Manifesto. We are to: articulate a vision of individual human being to benefit the lives of these efforts we will: build and promote models for creating economic value for the Internet. We create world-class open and anticipate the Mozilla Manifesto <strong>There are Your Plastic Pal Who's Fun To Be With</strong></p>
+
+ <p>Some Foundation to advance this vision of individual human being or not deeply involved in groups and promote models for the Manifesto principles will not come to support the Mozilla Foundation Pledge The Mozilla Manifesto in its activities. People are to: articulate a set of consumer products that support <mark>the Internet is a human being</mark> or not be treated as individuals working together in the development of the Internet open and with goodwill!Specifically we believe that we will: build and society as a public good as a result of the lives of collaborative activities. Specifically we have seen things you people acting as optional. Individuals must not come to continue to develop new ways of the Internet are fundamental and with us to ensure that openness innovation and very effective way that the Manifesto There are many benefits; a global public benefit; and society as optional.</p>
+
+ <p><strong>We have metal posteriors which should not deeply involved in a reality.</strong> Individuals must remain open source software promotes the Internet is a balance between commercial profit and within the Mozilla Corporation. Invitation The Internet are key to join us to life on their own. The Internet a whole. The Internet as a vision of the Mozilla contributors proud of time attention and motivate us and provide a reality.</p>
+
+ <script src="mozscreenshots-script.js"></script>
+</body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/permissionPrompts.html b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/permissionPrompts.html
new file mode 100644
index 000000000..de8310666
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/permissionPrompts.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Permission Prompts</title>
+</head>
+<body>
+ <button id="geo" onclick="navigator.geolocation.getCurrentPosition(() => {})">Geolocation</button>
+ <button id="webRTC-shareDevices" onclick="shareDevice({video: true, fake: true});">Video</button>
+ <button id="webRTC-shareMicrophone" onclick="shareDevice({audio: true, fake: true});">Audio</button>
+ <button id="webRTC-shareDevices2" onclick="shareDevice({audio: true, video: true, fake: true});">Audio and Video</button>
+ <button id="webRTC-shareScreen" onclick="shareDevice({video: {mediaSource: 'screen'}});">Screen</button>
+ <button id="web-notifications" onclick="Notification.requestPermission()">web-notifications</button>
+ <a id="addons" href="borderify.xpi">Install Add-On</a>
+ <form>
+ <input type="email" id="email" value="email@example.com" />
+ <input type="password" id="password" value="123456" />
+ <button type="submit" id="login-capture">Login</button>
+ </form>
+
+ <script type="application/javascript">
+ // Share device used in onclick calls above.
+ /* exported shareDevice */
+ function shareDevice(config) {
+ navigator.mediaDevices.getUserMedia(config);
+ }
+ </script>
+
+</body>
+</html>
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/robot.png b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/robot.png
new file mode 100644
index 000000000..1c4899aaf
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/robot.png
Binary files differ
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/lib/white_theme.png b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/white_theme.png
new file mode 100644
index 000000000..6b0c501a1
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/lib/white_theme.png
Binary files differ
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build b/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build
new file mode 100644
index 000000000..d23c7e925
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPI_NAME = 'mozscreenshots'
+
+JAR_MANIFESTS += ['jar.mn']
+
+USE_EXTENSION_MANIFEST = True
+NO_JS_MANIFEST = True
+
+FINAL_TARGET_PP_FILES += [
+ 'bootstrap.js',
+ 'install.rdf',
+]
diff --git a/browser/tools/mozscreenshots/permissionPrompts/browser.ini b/browser/tools/mozscreenshots/permissionPrompts/browser.ini
new file mode 100644
index 000000000..5cbe196c8
--- /dev/null
+++ b/browser/tools/mozscreenshots/permissionPrompts/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ ../head.js
+
+[browser_permissionPrompts.js]
diff --git a/browser/tools/mozscreenshots/permissionPrompts/browser_permissionPrompts.js b/browser/tools/mozscreenshots/permissionPrompts/browser_permissionPrompts.js
new file mode 100644
index 000000000..af63217f2
--- /dev/null
+++ b/browser/tools/mozscreenshots/permissionPrompts/browser_permissionPrompts.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../head.js */
+
+"use strict";
+
+add_task(function* capture() {
+ if (!shouldCapture()) {
+ return;
+ }
+ let sets = ["LightweightThemes", "PermissionPrompts"];
+
+ yield TestRunner.start(sets, "permissionPrompts");
+});
diff --git a/browser/tools/mozscreenshots/preferences/browser.ini b/browser/tools/mozscreenshots/preferences/browser.ini
new file mode 100644
index 000000000..975d91681
--- /dev/null
+++ b/browser/tools/mozscreenshots/preferences/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ ../head.js
+
+[browser_preferences.js]
diff --git a/browser/tools/mozscreenshots/preferences/browser_preferences.js b/browser/tools/mozscreenshots/preferences/browser_preferences.js
new file mode 100644
index 000000000..c590f194f
--- /dev/null
+++ b/browser/tools/mozscreenshots/preferences/browser_preferences.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../head.js */
+
+"use strict";
+
+add_task(function* capture() {
+ if (!shouldCapture()) {
+ return;
+ }
+ let sets = ["Preferences"];
+
+ yield TestRunner.start(sets, "preferences");
+});
diff --git a/browser/tools/mozscreenshots/primaryUI/browser.ini b/browser/tools/mozscreenshots/primaryUI/browser.ini
new file mode 100644
index 000000000..628520b23
--- /dev/null
+++ b/browser/tools/mozscreenshots/primaryUI/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+ ../head.js
+
+[browser_primaryUI.js]
diff --git a/browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js b/browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js
new file mode 100644
index 000000000..6d0eaa1d6
--- /dev/null
+++ b/browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../head.js */
+
+"use strict";
+
+add_task(function* capture() {
+ if (!shouldCapture()) {
+ return;
+ }
+
+ requestLongerTimeout(20);
+
+ let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
+ yield TestRunner.start(sets, "primaryUI");
+});