summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js')
-rw-r--r--toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js226
1 files changed, 226 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js b/toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js
new file mode 100644
index 0000000000..b2fb9484c2
--- /dev/null
+++ b/toolkit/components/extensions/test/browser/browser_ext_extension_page_tab_navigated.js
@@ -0,0 +1,226 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+// The test tasks in this test file tends to trigger an intermittent
+// exception raised from JSActor::AfterDestroy, because of a race between
+// when the WebExtensions API event is being emitted from the parent process
+// and the navigation triggered on the test extension pages.
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+PromiseTestUtils.allowMatchingRejectionsGlobally(
+ /Actor 'Conduits' destroyed before query 'RunListener' was resolved/
+);
+
+AddonTestUtils.initMochitest(this);
+
+const server = AddonTestUtils.createHttpServer({
+ hosts: ["example.com", "anotherwebpage.org"],
+});
+
+server.registerPathHandler("/", (request, response) => {
+ response.write(`<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <title>test webpage</title>
+ </head>
+ </html>
+ `);
+});
+
+function createTestExtPage({ script }) {
+ return `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <script src="${script}"></script>
+ </head>
+ </html>
+ `;
+}
+
+function createTestExtPageScript(name) {
+ return `(${function (pageName) {
+ browser.webRequest.onBeforeRequest.addListener(
+ details => {
+ browser.test.log(
+ `Extension page "${pageName}" got a webRequest event: ${details.url}`
+ );
+ browser.test.sendMessage(`event-received:${pageName}`);
+ },
+ { types: ["main_frame"], urls: ["http://example.com/*"] }
+ );
+ /* eslint-disable mozilla/balanced-listeners */
+ window.addEventListener("pageshow", () => {
+ browser.test.log(`Extension page "${pageName}" got a pageshow event`);
+ browser.test.sendMessage(`pageshow:${pageName}`);
+ });
+ window.addEventListener("pagehide", () => {
+ browser.test.log(`Extension page "${pageName}" got a pagehide event`);
+ browser.test.sendMessage(`pagehide:${pageName}`);
+ });
+ /* eslint-enable mozilla/balanced-listeners */
+ }})("${name}");`;
+}
+
+// Triggers a WebRequest listener registered by the test extensions by
+// opening a tab on the given web page URL and then closing it after
+// it did load.
+async function triggerWebRequestListener(webPageURL, pause) {
+ let webPageTab = await BrowserTestUtils.openNewForegroundTab(
+ {
+ gBrowser,
+ url: webPageURL,
+ },
+ true /* waitForLoad */,
+ true /* waitForStop */
+ );
+ BrowserTestUtils.removeTab(webPageTab);
+}
+
+// The following tests tasks are testing the expected behaviors related to same-process and cross-process
+// navigations for an extension page, similarly to test_ext_extension_page_navigated.js, but unlike its
+// xpcshell counterpart this tests are only testing that after navigating back to an extension page
+// previously stored in the BFCache the WebExtensions events subscribed are being received as expected.
+
+add_task(async function test_extension_page_sameprocess_navigation() {
+ const extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["webRequest", "http://example.com/*"],
+ },
+ files: {
+ "extpage1.html": createTestExtPage({ script: "extpage1.js" }),
+ "extpage1.js": createTestExtPageScript("extpage1"),
+ "extpage2.html": createTestExtPage({ script: "extpage2.js" }),
+ "extpage2.js": createTestExtPageScript("extpage2"),
+ },
+ });
+
+ await extension.startup();
+
+ const policy = WebExtensionPolicy.getByID(extension.id);
+
+ const extPageURL1 = policy.extension.baseURI.resolve("extpage1.html");
+ const extPageURL2 = policy.extension.baseURI.resolve("extpage2.html");
+
+ info("Opening extension page in a new tab");
+ const extPageTab = await BrowserTestUtils.addTab(gBrowser, extPageURL1);
+ let browser = gBrowser.getBrowserForTab(extPageTab);
+ info("Wait for the extension page to be loaded");
+ await extension.awaitMessage("pageshow:extpage1");
+
+ await triggerWebRequestListener("http://example.com");
+ await extension.awaitMessage("event-received:extpage1");
+ ok(true, "extpage1 got a webRequest event as expected");
+
+ info("Load a second extension page in the same tab");
+ BrowserTestUtils.loadURIString(browser, extPageURL2);
+
+ info("Wait extpage1 to receive a pagehide event");
+ await extension.awaitMessage("pagehide:extpage1");
+ info("Wait extpage2 to receive a pageshow event");
+ await extension.awaitMessage("pageshow:extpage2");
+
+ info(
+ "Trigger a web request event and expect extpage2 to be the only one receiving it"
+ );
+ await triggerWebRequestListener("http://example.com");
+ await extension.awaitMessage("event-received:extpage2");
+ ok(true, "extpage2 got a webRequest event as expected");
+
+ info(
+ "Navigating back to extpage1 and expect extpage2 to be the only one receiving the webRequest event"
+ );
+
+ browser.goBack();
+ info("Wait for extpage1 to receive a pageshow event");
+ await extension.awaitMessage("pageshow:extpage1");
+ info("Wait for extpage2 to receive a pagehide event");
+ await extension.awaitMessage("pagehide:extpage2");
+
+ // We only expect extpage1 to be able to receive API events.
+ await triggerWebRequestListener("http://example.com");
+ await extension.awaitMessage("event-received:extpage1");
+ ok(true, "extpage1 got a webRequest event as expected");
+
+ BrowserTestUtils.removeTab(extPageTab);
+ await extension.awaitMessage("pagehide:extpage1");
+
+ await extension.unload();
+});
+
+add_task(async function test_extension_page_context_navigated_to_web_page() {
+ const extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["webRequest", "http://example.com/*"],
+ },
+ files: {
+ "extpage.html": createTestExtPage({ script: "extpage.js" }),
+ "extpage.js": createTestExtPageScript("extpage"),
+ },
+ });
+
+ await extension.startup();
+
+ const policy = WebExtensionPolicy.getByID(extension.id);
+
+ const extPageURL = policy.extension.baseURI.resolve("extpage.html");
+ // NOTE: this test will navigate the extension page to a webpage url that
+ // isn't matching the match pattern the test extension is going to use
+ // in its webRequest event listener, otherwise the extension page being
+ // navigated will be intermittently able to receive an event before it
+ // is navigated to the webpage url (and moved into the BFCache or destroyed)
+ // and trigger an intermittent failure of this test.
+ const webPageURL = "http://anotherwebpage.org/";
+ const triggerWebRequestURL = "http://example.com/";
+
+ info("Opening extension page in a new tab");
+ const extPageTab1 = await BrowserTestUtils.addTab(gBrowser, extPageURL);
+ let browserForTab1 = gBrowser.getBrowserForTab(extPageTab1);
+ info("Wait for the extension page to be loaded");
+ await extension.awaitMessage("pageshow:extpage");
+
+ info("Navigate the tab from the extension page to a web page");
+ let promiseLoaded = BrowserTestUtils.browserLoaded(
+ browserForTab1,
+ false,
+ webPageURL
+ );
+ BrowserTestUtils.loadURIString(browserForTab1, webPageURL);
+ info("Wait the tab to have loaded the new webpage url");
+ await promiseLoaded;
+ info("Wait the extension page to receive a pagehide event");
+ await extension.awaitMessage("pagehide:extpage");
+
+ // Trigger a webRequest listener, the extension page is expected to
+ // not be active, if that isn't the case a test message will be queued
+ // and will trigger an explicit test failure.
+ await triggerWebRequestListener(triggerWebRequestURL);
+
+ info("Navigate back to the extension page");
+ browserForTab1.goBack();
+ info("Wait for extension page to receive a pageshow event");
+ await extension.awaitMessage("pageshow:extpage");
+
+ await triggerWebRequestListener(triggerWebRequestURL);
+ await extension.awaitMessage("event-received:extpage");
+ ok(
+ true,
+ "extpage got a webRequest event as expected after being restored from BFCache"
+ );
+
+ info("Cleanup and exit test");
+ BrowserTestUtils.removeTab(extPageTab1);
+
+ info("Wait the extension page to receive a pagehide event");
+ await extension.awaitMessage("pagehide:extpage");
+
+ await extension.unload();
+});