summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/browser/browser_ext_tabs_discarded.js')
-rw-r--r--browser/components/extensions/test/browser/browser_ext_tabs_discarded.js386
1 files changed, 386 insertions, 0 deletions
diff --git a/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js b/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
new file mode 100644
index 0000000000..48c57b5a05
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
@@ -0,0 +1,386 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+/* global gBrowser SessionStore */
+"use strict";
+
+const triggeringPrincipal_base64 = E10SUtils.SERIALIZED_SYSTEMPRINCIPAL;
+
+let lazyTabState = {
+ entries: [
+ {
+ url: "http://example.com/",
+ triggeringPrincipal_base64,
+ title: "Example Domain",
+ },
+ ],
+};
+
+add_task(async function test_discarded() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs", "webNavigation"],
+ },
+
+ background() {
+ browser.webNavigation.onCompleted.addListener(
+ async details => {
+ browser.test.log(`webNav onCompleted received for ${details.tabId}`);
+ let updatedTab = await browser.tabs.get(details.tabId);
+ browser.test.assertEq(
+ false,
+ updatedTab.discarded,
+ "lazy to non-lazy update discard property"
+ );
+ browser.test.notifyPass("test-finished");
+ },
+ { url: [{ hostContains: "example.com" }] }
+ );
+
+ browser.tabs.onCreated.addListener(function (tab) {
+ browser.test.assertEq(
+ true,
+ tab.discarded,
+ "non-lazy tab onCreated discard property"
+ );
+ browser.tabs.update(tab.id, { active: true });
+ });
+ },
+ });
+
+ await extension.startup();
+
+ let testTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
+ createLazyBrowser: true,
+ });
+ SessionStore.setTabState(testTab, lazyTabState);
+
+ await extension.awaitFinish("test-finished");
+ await extension.unload();
+
+ BrowserTestUtils.removeTab(testTab);
+});
+
+// Regression test for Bug 1819794.
+add_task(async function test_create_discarded_with_cookieStoreId() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["contextualIdentities", "cookies"],
+ },
+ async background() {
+ const [{ cookieStoreId }] = await browser.contextualIdentities.query({});
+ browser.test.assertEq(
+ "firefox-container-1",
+ cookieStoreId,
+ "Got expected cookieStoreId"
+ );
+ await browser.tabs.create({
+ url: `http://example.com/#${cookieStoreId}`,
+ cookieStoreId,
+ discarded: true,
+ });
+ await browser.tabs.create({
+ url: `http://example.com/#no-container`,
+ discarded: true,
+ });
+ },
+ // Needed by ExtensionSettingsStore (as a side-effect of contextualIdentities permission).
+ useAddonManager: "temporary",
+ });
+
+ const tabContainerPromise = BrowserTestUtils.waitForEvent(
+ window,
+ "TabOpen",
+ false,
+ evt => {
+ return evt.target.getAttribute("usercontextid", "1");
+ }
+ ).then(evt => evt.target);
+ const tabDefaultPromise = BrowserTestUtils.waitForEvent(
+ window,
+ "TabOpen",
+ false,
+ evt => {
+ return !evt.target.hasAttribute("usercontextid");
+ }
+ ).then(evt => evt.target);
+
+ await extension.startup();
+
+ const tabContainer = await tabContainerPromise;
+ ok(
+ tabContainer.hasAttribute("pending"),
+ "new container tab should be discarded"
+ );
+ const tabContainerState = SessionStore.getTabState(tabContainer);
+ is(
+ JSON.parse(tabContainerState).userContextId,
+ 1,
+ `Expect a userContextId associated to the new discarded container tab: ${tabContainerState}`
+ );
+
+ const tabDefault = await tabDefaultPromise;
+ ok(
+ tabDefault.hasAttribute("pending"),
+ "new non-container tab should be discarded"
+ );
+ const tabDefaultState = SessionStore.getTabState(tabDefault);
+ is(
+ JSON.parse(tabDefaultState).userContextId,
+ 0,
+ `Expect userContextId 0 associated to the new discarded non-container tab: ${tabDefaultState}`
+ );
+
+ BrowserTestUtils.removeTab(tabContainer);
+ BrowserTestUtils.removeTab(tabDefault);
+ await extension.unload();
+});
+
+// If discard is called immediately after creating a new tab, the new tab may not have loaded,
+// and the sessionstore for that tab is not ready for discarding. The result was a corrupted
+// sessionstore for the tab, which when the tab was activated, resulted in a tab with partial
+// state.
+add_task(async function test_create_then_discard() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs", "webNavigation"],
+ },
+
+ background: async function () {
+ let createdTab;
+
+ browser.tabs.onUpdated.addListener((tabId, updatedInfo) => {
+ if (!updatedInfo.discarded) {
+ return;
+ }
+
+ browser.webNavigation.onCompleted.addListener(
+ async details => {
+ browser.test.assertEq(
+ createdTab.id,
+ details.tabId,
+ "created tab navigation is completed"
+ );
+ let activeTab = await browser.tabs.get(details.tabId);
+ browser.test.assertEq(
+ "http://example.com/",
+ details.url,
+ "created tab url is correct"
+ );
+ browser.test.assertEq(
+ "http://example.com/",
+ activeTab.url,
+ "created tab url is correct"
+ );
+ browser.tabs.remove(details.tabId);
+ browser.test.notifyPass("test-finished");
+ },
+ { url: [{ hostContains: "example.com" }] }
+ );
+
+ browser.tabs.update(tabId, { active: true });
+ });
+
+ createdTab = await browser.tabs.create({
+ url: "http://example.com/",
+ active: false,
+ });
+ browser.tabs.discard(createdTab.id);
+ },
+ });
+ await extension.startup();
+ await extension.awaitFinish("test-finished");
+ await extension.unload();
+});
+
+add_task(async function test_create_discarded() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs", "webNavigation"],
+ },
+
+ background() {
+ let tabOpts = {
+ url: "http://example.com/",
+ active: false,
+ discarded: true,
+ title: "discarded tab",
+ };
+
+ browser.webNavigation.onCompleted.addListener(
+ async details => {
+ let activeTab = await browser.tabs.get(details.tabId);
+ browser.test.assertEq(
+ tabOpts.url,
+ activeTab.url,
+ "restored tab url matches active tab url"
+ );
+ browser.test.assertEq(
+ "mochitest index /",
+ activeTab.title,
+ "restored tab title is correct"
+ );
+ browser.tabs.remove(details.tabId);
+ browser.test.notifyPass("test-finished");
+ },
+ { url: [{ hostContains: "example.com" }] }
+ );
+
+ browser.tabs.onCreated.addListener(tab => {
+ browser.test.assertEq(
+ tabOpts.active,
+ tab.active,
+ "lazy tab is not active"
+ );
+ browser.test.assertEq(
+ tabOpts.discarded,
+ tab.discarded,
+ "lazy tab is discarded"
+ );
+ browser.test.assertEq(tabOpts.url, tab.url, "lazy tab url is correct");
+ browser.test.assertEq(
+ tabOpts.title,
+ tab.title,
+ "lazy tab title is correct"
+ );
+ browser.tabs.update(tab.id, { active: true });
+ });
+
+ browser.tabs.create(tabOpts);
+ },
+ });
+ await extension.startup();
+ await extension.awaitFinish("test-finished");
+ await extension.unload();
+});
+
+add_task(async function test_discarded_private_tab_restored() {
+ let extension = ExtensionTestUtils.loadExtension({
+ incognitoOverride: "spanning",
+
+ background() {
+ let isDiscarding = false;
+ browser.tabs.onUpdated.addListener(
+ async function listener(tabId, changeInfo, tab) {
+ const { active, discarded, incognito } = tab;
+ if (!incognito || active || discarded || isDiscarding) {
+ return;
+ }
+ // Remove the onUpdated listener to prevent intermittent failure
+ // to be hit if the listener gets called again for unrelated
+ // tabs.onUpdated events that may get fired after the test case got
+ // the tab-discarded test message that was expecting.
+ isDiscarding = true;
+ browser.tabs.onUpdated.removeListener(listener);
+ browser.test.log(
+ `Test extension discarding ${tabId}: ${JSON.stringify(changeInfo)}`
+ );
+ await browser.tabs.discard(tabId);
+ browser.test.sendMessage("tab-discarded");
+ },
+ { properties: ["status"] }
+ );
+ },
+ });
+
+ // Open a private browsing window.
+ const privateWin = await BrowserTestUtils.openNewBrowserWindow({
+ private: true,
+ });
+
+ await extension.startup();
+
+ const newTab = await BrowserTestUtils.addTab(
+ privateWin.gBrowser,
+ "https://example.com/"
+ );
+ await extension.awaitMessage("tab-discarded");
+ is(newTab.getAttribute("pending"), "true", "private tab should be discarded");
+
+ const promiseTabLoaded = BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
+
+ info("Switching to the discarded background tab");
+ await BrowserTestUtils.switchTab(privateWin.gBrowser, newTab);
+
+ info("Wait for the restored tab to complete loading");
+ await promiseTabLoaded;
+ is(
+ newTab.hasAttribute("pending"),
+ false,
+ "discarded private tab should have been restored"
+ );
+
+ is(
+ newTab.linkedBrowser.currentURI.spec,
+ "https://example.com/",
+ "Got the expected url on the restored tab"
+ );
+
+ await extension.unload();
+ await BrowserTestUtils.closeWindow(privateWin);
+});
+
+add_task(async function test_update_discarded() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs", "<all_urls>"],
+ },
+
+ background() {
+ browser.test.onMessage.addListener(async msg => {
+ let [tab] = await browser.tabs.query({ url: "http://example.com/" });
+ if (msg == "update") {
+ await browser.tabs.update(tab.id, { url: "https://example.com/" });
+ } else {
+ browser.test.fail(`Unexpected message received: ${msg}`);
+ }
+ });
+ browser.test.sendMessage("ready");
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitMessage("ready");
+
+ let lazyTab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {
+ createLazyBrowser: true,
+ lazyTabTitle: "Example Domain",
+ });
+
+ let tabBrowserInsertedPromise = BrowserTestUtils.waitForEvent(
+ lazyTab,
+ "TabBrowserInserted"
+ );
+
+ SimpleTest.waitForExplicitFinish();
+ let waitForConsole = new Promise(resolve => {
+ SimpleTest.monitorConsole(resolve, [
+ {
+ message:
+ /Lazy browser prematurely inserted via 'loadURI' property access:/,
+ forbid: true,
+ },
+ ]);
+ });
+
+ extension.sendMessage("update");
+ await tabBrowserInsertedPromise;
+
+ await BrowserTestUtils.waitForBrowserStateChange(
+ lazyTab.linkedBrowser,
+ "https://example.com/",
+ stateFlags => {
+ return (
+ stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
+ stateFlags & Ci.nsIWebProgressListener.STATE_STOP
+ );
+ }
+ );
+
+ await TestUtils.waitForTick();
+ BrowserTestUtils.removeTab(lazyTab);
+
+ await extension.unload();
+
+ SimpleTest.endMonitorConsole();
+ await waitForConsole;
+});