summaryrefslogtreecommitdiffstats
path: root/browser/extensions/screenshots/test
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/screenshots/test')
-rw-r--r--browser/extensions/screenshots/test/browser/.eslintrc.yml5
-rw-r--r--browser/extensions/screenshots/test/browser/browser.ini4
-rw-r--r--browser/extensions/screenshots/test/browser/browser_screenshots_injection.js72
-rw-r--r--browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js94
-rw-r--r--browser/extensions/screenshots/test/browser/injection-page.html24
5 files changed, 199 insertions, 0 deletions
diff --git a/browser/extensions/screenshots/test/browser/.eslintrc.yml b/browser/extensions/screenshots/test/browser/.eslintrc.yml
new file mode 100644
index 0000000000..f5cf5d3929
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/.eslintrc.yml
@@ -0,0 +1,5 @@
+env:
+ node: true
+
+extends:
+ - plugin:mozilla/browser-test
diff --git a/browser/extensions/screenshots/test/browser/browser.ini b/browser/extensions/screenshots/test/browser/browser.ini
new file mode 100644
index 0000000000..9c27b311fe
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/browser.ini
@@ -0,0 +1,4 @@
+[browser_screenshots_injection.js]
+support-files = injection-page.html
+[browser_screenshots_ui_check.js]
+skip-if = os == 'win' && debug # Bug 1394967
diff --git a/browser/extensions/screenshots/test/browser/browser_screenshots_injection.js b/browser/extensions/screenshots/test/browser/browser_screenshots_injection.js
new file mode 100644
index 0000000000..571d7d6615
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/browser_screenshots_injection.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_PATH = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+/**
+ * Check that web content cannot break into screenshots.
+ */
+add_task(async function test_inject_srcdoc() {
+ // If Screenshots was disabled, enable it just for this test.
+ const addon = await AddonManager.getAddonByID("screenshots@mozilla.org");
+ const isEnabled = addon.enabled;
+ if (!isEnabled) {
+ await addon.enable({allowSystemAddons: true});
+ registerCleanupFunction(async () => {
+ await addon.disable({allowSystemAddons: true});
+ });
+ }
+
+ await BrowserTestUtils.withNewTab(TEST_PATH + "injection-page.html",
+ async (browser) => {
+ // Set up the content hijacking. Do this so we can see it without
+ // awaiting - the promise should never resolve.
+ let response = null;
+ let responsePromise = SpecialPowers.spawn(browser, [], () => {
+ return new Promise(resolve => {
+ // We can't pass `resolve` directly because of sandboxing.
+ // `responseHandler` gets invoked from the content page.
+ content.wrappedJSObject.responseHandler = Cu.exportFunction(
+ function(arg) {
+ resolve(arg)
+ },
+ content
+ );
+ });
+ }).then(
+ r => {
+ ok(false, "Should not have gotten HTML but got: " + r);
+ response = r;
+ },
+ () => {
+ // Do nothing - we expect this to error when the test finishes
+ // and the actor is destroyed, while the promise still hasn't
+ // been resolved. We need to catch it in order not to throw
+ // uncaught rejection errors and inadvertently fail the test.
+ }
+ );
+
+ let error;
+ let errorPromise = new Promise(resolve => {
+ SpecialPowers.registerConsoleListener(msg => {
+ if (msg.message?.match(/iframe URL does not match expected blank.html/)) {
+ error = msg;
+ resolve();
+ }
+ });
+ });
+
+ // Now try to start the screenshot flow:
+ document.querySelector("keyset[id*=screenshot] > key").doCommand();
+ await Promise.race([errorPromise, responsePromise]);
+ ok(error, "Should get the relevant error: " + error?.message);
+ ok(!response, "Should not get a response from the webpage.");
+
+ SpecialPowers.postConsoleSentinel();
+ });
+});
diff --git a/browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js b/browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js
new file mode 100644
index 0000000000..f77d6c32ea
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js
@@ -0,0 +1,94 @@
+"use strict";
+
+ChromeUtils.defineModuleGetter(this, "AddonManager",
+ "resource://gre/modules/AddonManager.jsm");
+
+const BUTTON_ID = "pageAction-panel-screenshots_mozilla_org";
+
+function checkElements(expectPresent, l) {
+ for (const id of l) {
+ is(!!document.getElementById(id), expectPresent, "element " + id + (expectPresent ? " is" : " is not") + " present");
+ }
+}
+
+async function togglePageActionPanel() {
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelEvent("popuphidden");
+}
+
+function promiseOpenPageActionPanel() {
+ return BrowserTestUtils.waitForCondition(() => {
+ // Wait for the main page action button to become visible. It's hidden for
+ // some URIs, so depending on when this is called, it may not yet be quite
+ // visible. It's up to the caller to make sure it will be visible.
+ info("Waiting for main page action button to have non-0 size");
+ const bounds = window.windowUtils.getBoundsWithoutFlushing(BrowserPageActions.mainButtonNode);
+ return bounds.width > 0 && bounds.height > 0;
+ }).then(() => {
+ // Wait for the panel to become open, by clicking the button if necessary.
+ info("Waiting for main page action panel to be open");
+ if (BrowserPageActions.panelNode.state === "open") {
+ return Promise.resolve();
+ }
+ const shownPromise = promisePageActionPanelEvent("popupshown");
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ return shownPromise;
+ }).then(() => {
+ // Wait for items in the panel to become visible.
+ return promisePageActionViewChildrenVisible(BrowserPageActions.mainViewNode);
+ });
+}
+
+function promisePageActionPanelEvent(eventType) {
+ return new Promise(resolve => {
+ const panel = BrowserPageActions.panelNode;
+ if ((eventType === "popupshown" && panel.state === "open") ||
+ (eventType === "popuphidden" && panel.state === "closed")) {
+ executeSoon(resolve);
+ return;
+ }
+ panel.addEventListener(eventType, () => {
+ executeSoon(resolve);
+ }, { once: true });
+ });
+}
+
+function promisePageActionViewChildrenVisible(panelViewNode) {
+ info("promisePageActionViewChildrenVisible waiting for a child node to be visible");
+ return BrowserTestUtils.waitForCondition(() => {
+ const bodyNode = panelViewNode.firstElementChild;
+ for (const childNode of bodyNode.children) {
+ const bounds = window.windowUtils.getBoundsWithoutFlushing(childNode);
+ if (bounds.width > 0 && bounds.height > 0) {
+ return true;
+ }
+ }
+ return false;
+ });
+}
+
+add_task(async function() {
+ // If Screenshots was disabled, enable it just for this test.
+ const addon = await AddonManager.getAddonByID("screenshots@mozilla.org");
+ const isEnabled = addon.enabled;
+ if (!isEnabled) {
+ await addon.enable({allowSystemAddons: true});
+ registerCleanupFunction(async () => {
+ await addon.disable({allowSystemAddons: true});
+ });
+ }
+
+ // Toggle the page action panel to get it to rebuild itself. An actionable
+ // page must be opened first.
+ const url = "http://example.com/browser_screenshots_ui_check";
+ await BrowserTestUtils.withNewTab(url, async () => { // eslint-disable-line space-before-function-paren
+ await togglePageActionPanel();
+
+ await BrowserTestUtils.waitForCondition(
+ () => document.getElementById(BUTTON_ID),
+ "Screenshots button should be present", 100, 100);
+
+ checkElements(true, [BUTTON_ID]);
+ });
+});
diff --git a/browser/extensions/screenshots/test/browser/injection-page.html b/browser/extensions/screenshots/test/browser/injection-page.html
new file mode 100644
index 0000000000..c7579aa8b5
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/injection-page.html
@@ -0,0 +1,24 @@
+<body>
+<script>
+let callback = function(mutationsList, observer) {
+ for (let mutation of mutationsList) {
+ let [added] = mutation.addedNodes;
+ if (added instanceof HTMLIFrameElement && added.id == "firefox-screenshots-preview-iframe") {
+ added.srcdoc = "<html></html>";
+ // Now we have to wait for the doc to be populated.
+ let interval = setInterval(() => {
+ console.log(added.contentDocument.innerHTML);
+ if (added.contentDocument.body.innerHTML) {
+ clearInterval(interval);
+ window.responseHandler(added.contentDocument.body.innerHTML);
+ }
+ }, 100);
+ observer.disconnect();
+ }
+ }
+};
+
+observer = new MutationObserver(callback);
+observer.observe(document.body, {childList: true});
+</script>
+</body>