summaryrefslogtreecommitdiffstats
path: root/browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js')
-rw-r--r--browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js319
1 files changed, 319 insertions, 0 deletions
diff --git a/browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js b/browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js
new file mode 100644
index 0000000000..081167acfa
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_closed_tabs_closed_windows.js
@@ -0,0 +1,319 @@
+/* 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/. */
+const { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+const TEST_URLS = [
+ "http://mochi.test:8888/browser/",
+ "https://www.example.com/",
+ "https://example.net/",
+ "https://example.org/",
+ "about:logo",
+ "about:robots",
+];
+const TOPIC_CLOSED_OBJECTS_CHANGED = "sessionstore-closed-objects-changed";
+var preparedClosedIds;
+
+add_setup(async function testSetup() {
+ registerCleanupFunction(async () => {
+ await promiseAllButPrimaryWindowClosed();
+ Services.obs.notifyObservers(null, "browser:purge-session-history");
+ });
+ preparedClosedIds = await prepareClosedData();
+ SimpleTest.promiseFocus(window);
+});
+
+async function prepareClosedData() {
+ // prepare some closed state
+ let closedIds = {};
+ await openAndCloseTab(window, TEST_URLS[0]);
+ closedIds.tab0 = SessionStore.getClosedTabDataForWindow(window)[0].closedId;
+
+ const testWindow1 = await BrowserTestUtils.openNewBrowserWindow();
+ // open a non-transitory, worth-keeping tab to ensure window data is saved on close
+ await BrowserTestUtils.openNewForegroundTab(
+ testWindow1.gBrowser,
+ "about:mozilla"
+ );
+ await openAndCloseTab(testWindow1, TEST_URLS[1]);
+ closedIds.tab1 =
+ SessionStore.getClosedTabDataForWindow(testWindow1)[0].closedId;
+
+ const testWindow2 = await BrowserTestUtils.openNewBrowserWindow();
+ // open a non-transitory, worth-keeping tab to ensure window data is saved on close
+ await BrowserTestUtils.openNewForegroundTab(
+ testWindow2.gBrowser,
+ "about:mozilla"
+ );
+ await openAndCloseTab(testWindow2, TEST_URLS[2]);
+ closedIds.tab2 =
+ SessionStore.getClosedTabDataForWindow(testWindow2)[0].closedId;
+ await openAndCloseTab(testWindow2, TEST_URLS[3]);
+ closedIds.tab3 =
+ SessionStore.getClosedTabDataForWindow(testWindow2)[0].closedId;
+
+ const testWindow3 = await BrowserTestUtils.openNewBrowserWindow();
+ // open a non-transitory, worth-keeping tab to ensure window data is saved on close
+ await BrowserTestUtils.openNewForegroundTab(
+ testWindow3.gBrowser,
+ "about:mozilla"
+ );
+ await openAndCloseTab(testWindow3, TEST_URLS[4]);
+ closedIds.tab4 =
+ SessionStore.getClosedTabDataForWindow(testWindow3)[0].closedId;
+
+ // open a private window
+ const privateWin = await BrowserTestUtils.openNewBrowserWindow({
+ private: true,
+ });
+ // open a non-transitory, worth-keeping tab to ensure window data is saved on close
+ await BrowserTestUtils.openNewForegroundTab(
+ privateWin.gBrowser,
+ "about:mozilla"
+ );
+ await openAndCloseTab(privateWin, TEST_URLS[5]);
+ closedIds.tab5 =
+ SessionStore.getClosedTabDataForWindow(privateWin)[0].closedId;
+
+ const testWindow6 = await BrowserTestUtils.openNewBrowserWindow();
+
+ const testWindow7 = await BrowserTestUtils.openNewBrowserWindow();
+ await openAndCloseTab(testWindow7, TEST_URLS[4]);
+
+ let closedTabsHistogram = TelemetryTestUtils.getAndClearHistogram(
+ "FX_SESSION_RESTORE_CLOSED_TABS_NOT_SAVED"
+ );
+
+ await BrowserTestUtils.closeWindow(testWindow1);
+ closedIds.testWindow1 = SessionStore.getClosedWindowData()[0].closedId;
+ await BrowserTestUtils.closeWindow(testWindow2);
+
+ closedIds.testWindow2 = SessionStore.getClosedWindowData()[0].closedId;
+ await BrowserTestUtils.closeWindow(testWindow3);
+
+ closedIds.testWindow3 = SessionStore.getClosedWindowData()[0].closedId;
+ await BrowserTestUtils.closeWindow(privateWin);
+ Assert.ok(
+ closedIds.testWindow2 > closedIds.testWindow1,
+ "We got the closedIds in the expected order"
+ );
+
+ await BrowserTestUtils.closeWindow(testWindow6);
+ TelemetryTestUtils.assertHistogram(closedTabsHistogram, 0, 1);
+ closedTabsHistogram.clear();
+
+ await BrowserTestUtils.closeWindow(testWindow7);
+ TelemetryTestUtils.assertHistogram(closedTabsHistogram, 1, 1);
+ closedTabsHistogram.clear();
+
+ return closedIds;
+}
+
+// The tasks need to be run sequentially. They are broken up so the different functions
+// under test and any stack traces are easier to find
+
+add_task(async function get_closed_tabs_from_closed_windows() {
+ Assert.equal(
+ SessionStore.getClosedTabCount({ closedTabsFromClosedWindows: false }),
+ 1,
+ "Expected closed tab count (in currently-open windows only)"
+ );
+ Assert.equal(
+ SessionStore.getClosedTabCount(),
+ 5,
+ "Expected closed tab count (in currently-open and closed windows)"
+ );
+ // We dont keep the closed tab from the private window
+ Assert.equal(
+ SessionStore.getClosedTabCountFromClosedWindows(),
+ 4,
+ "Expected closed tab count (from closed windows)"
+ );
+
+ // Closed tabs from closed windows aren't included in the list from getClosedTabData()
+ Assert.deepEqual(
+ SessionStore.getClosedTabData().map(td => td.state.entries[0].url),
+ ["http://mochi.test:8888/browser/"],
+ "Matched closed tab data from currently open windows"
+ );
+
+ // Closed tabs from open windows or closed private windows aren't included in the list
+ // from getClosedTabDataFromClosedWindows()
+ Assert.deepEqual(
+ SessionStore.getClosedTabDataFromClosedWindows().map(
+ td => td.state.entries[0].url
+ ),
+ [
+ "about:logo",
+ "https://example.org/",
+ "https://example.net/",
+ "https://www.example.com/",
+ ],
+ "Matched closed tab data from currently closed windows"
+ );
+});
+
+add_task(async function forget_closed_tabs_from_closed_windows() {
+ // forget the most recent tab we closed in testWindow1
+ let closedObjectsChanged = TestUtils.topicObserved(
+ TOPIC_CLOSED_OBJECTS_CHANGED
+ );
+ info(
+ "Calling forgetClosedTab with window sourceClosedId: " +
+ preparedClosedIds.testWindow1
+ );
+ SessionStore.forgetClosedTab(
+ { sourceClosedId: preparedClosedIds.testWindow1 },
+ 0
+ );
+ await closedObjectsChanged;
+ Assert.deepEqual(
+ SessionStore.getClosedTabDataFromClosedWindows().map(
+ td => td.state.entries[0].url
+ ),
+ [
+ "about:logo",
+ "https://example.org/",
+ "https://example.net/",
+ // "https://www.example.com/" from testWindow1 was forgotten and should be removed
+ ],
+ "Closed tab forgotten"
+ );
+
+ // forget a closed window that had closed tabs
+ let closedTabCount = SessionStore.getClosedTabCountFromClosedWindows();
+ closedObjectsChanged = TestUtils.topicObserved(TOPIC_CLOSED_OBJECTS_CHANGED);
+ SessionStore.forgetClosedWindowById(preparedClosedIds.testWindow3);
+ await closedObjectsChanged;
+ Assert.equal(
+ SessionStore.getClosedTabCountFromClosedWindows(),
+ closedTabCount - 1,
+ "The closed tab is gone when we forget the closed window it was in"
+ );
+});
+
+add_task(async function expected_exceptions_closed_tabs_from_closed_windows() {
+ // testWindow3 was forgotten, attempting to undoClose its tabs should throw
+ Assert.throws(
+ () =>
+ SessionStore.undoClosedTabFromClosedWindow(
+ { sourceClosedId: preparedClosedIds.testWindow3 },
+ preparedClosedIds.tab4
+ ),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ "Invalid window or source for undoClosedTabFromClosedWindow throws"
+ );
+ // tab1 was forgotten, attempting to undoClose it should throw
+ Assert.throws(
+ () =>
+ SessionStore.undoClosedTabFromClosedWindow(
+ { sourceClosedId: preparedClosedIds.testWindow1 },
+ preparedClosedIds.tab1
+ ),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ "Invalid tab closedId for undoClosedTabFromClosedWindow throws"
+ );
+
+ // testWindow3 was forgotten, attempting to forget its tabs should throw
+ Assert.throws(
+ () =>
+ SessionStore.forgetClosedTab(
+ { sourceClosedId: preparedClosedIds.testWindow3 },
+ preparedClosedIds.tab4
+ ),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ "Invalid window or source for forgetClosedTab throws"
+ );
+
+ // tab1 was forgotten, attempting to forget it again should throw
+ Assert.throws(
+ () =>
+ SessionStore.undoClosedTabFromClosedWindow(
+ { sourceClosedId: preparedClosedIds.testWindow3 },
+ preparedClosedIds.tab4
+ ),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ "Invalid window for undoClosedTabFromClosedWindow throws"
+ );
+});
+
+add_task(async function undo_closed_tabs_from_closed_windows() {
+ const openTabsCount = gBrowser.tabs.length;
+
+ // undo most recently closed tab from a closed window using a window closedId
+ let closedObjectsChanged = TestUtils.topicObserved(
+ TOPIC_CLOSED_OBJECTS_CHANGED
+ );
+ let restoredTab1 = SessionStore.undoCloseTab(
+ { sourceClosedId: preparedClosedIds.testWindow2 },
+ 0,
+ window
+ );
+ await BrowserTestUtils.waitForEvent(
+ window.gBrowser.tabContainer,
+ "SSTabRestored"
+ );
+ await closedObjectsChanged;
+ Assert.equal(
+ window.gBrowser.tabs.length,
+ openTabsCount + 1,
+ "The closed tab was restored"
+ );
+ Assert.equal(
+ restoredTab1.linkedBrowser.currentURI.spec,
+ "https://example.org/",
+ "The re-opened tab had the expected URL"
+ );
+ Assert.deepEqual(
+ SessionStore.getClosedTabDataFromClosedWindows().map(
+ td => td.state.entries[0].url
+ ),
+ [
+ "https://example.net/",
+ // "https://example.org/" from testWindow2 got reopened and should be removed
+ ],
+ "Re-opened tabs not listed in closed tabs"
+ );
+
+ // use undoClosedTabFromClosedWindows to reference the closed tab by closedId
+ closedObjectsChanged = TestUtils.topicObserved(TOPIC_CLOSED_OBJECTS_CHANGED);
+ let restoredTab2 = SessionStore.undoClosedTabFromClosedWindow(
+ { sourceClosedId: preparedClosedIds.testWindow2 },
+ preparedClosedIds.tab2,
+ window
+ );
+ await BrowserTestUtils.waitForEvent(
+ window.gBrowser.tabContainer,
+ "SSTabRestored"
+ );
+ await closedObjectsChanged;
+ Assert.equal(
+ window.gBrowser.tabs.length,
+ openTabsCount + 2,
+ "The closed tab was restored"
+ );
+ Assert.equal(
+ restoredTab2.linkedBrowser.currentURI.spec,
+ "https://example.net/",
+ "The re-opened tab had the expected URL"
+ );
+
+ Assert.deepEqual(
+ SessionStore.getClosedTabDataFromClosedWindows().map(
+ td => td.state.entries[0].url
+ ),
+ [
+ // "https://example.org/" from testWindow2 got reopened and should be removed
+ ],
+ "Re-opened tabs not listed in closed tabs"
+ );
+
+ // clean up the re-opened tabs
+ for (let tab of [restoredTab1, restoredTab2]) {
+ await TabStateFlusher.flush(tab.linkedBrowser);
+ let sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
+ BrowserTestUtils.removeTab(tab);
+ await sessionUpdatePromise;
+ }
+});