summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/tabs/browser_lastSeenActive.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/tabs/browser_lastSeenActive.js')
-rw-r--r--browser/base/content/test/tabs/browser_lastSeenActive.js260
1 files changed, 260 insertions, 0 deletions
diff --git a/browser/base/content/test/tabs/browser_lastSeenActive.js b/browser/base/content/test/tabs/browser_lastSeenActive.js
new file mode 100644
index 0000000000..d6bba57d93
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_lastSeenActive.js
@@ -0,0 +1,260 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { SessionStoreTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/SessionStoreTestUtils.sys.mjs"
+);
+
+const triggeringPrincipal_base64 = E10SUtils.SERIALIZED_SYSTEMPRINCIPAL;
+
+SessionStoreTestUtils.init(this, window);
+// take a state snapshot we can restore to after each test
+const ORIG_STATE = SessionStore.getBrowserState();
+
+const SECOND_MS = 1000;
+const DAY_MS = 24 * 60 * 60 * 1000;
+const today = new Date().getTime();
+const yesterday = new Date(Date.now() - DAY_MS).getTime();
+
+function tabEntry(url, lastAccessed) {
+ return {
+ entries: [{ url, triggeringPrincipal_base64 }],
+ lastAccessed,
+ };
+}
+
+/**
+ * Make the given window focused and active
+ */
+async function switchToWindow(win) {
+ info("switchToWindow, waiting for promiseFocus");
+ await SimpleTest.promiseFocus(win);
+ info("switchToWindow, waiting for correct Services.focus.activeWindow");
+ await BrowserTestUtils.waitForCondition(
+ () => Services.focus.activeWindow == win
+ );
+}
+
+async function changeSizeMode(win, mode) {
+ let promise = BrowserTestUtils.waitForEvent(win, "sizemodechange");
+ win[mode]();
+ await promise;
+}
+
+async function cleanup() {
+ await switchToWindow(window);
+ await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
+ is(
+ BrowserWindowTracker.orderedWindows.length,
+ 1,
+ "One window at the end of test cleanup"
+ );
+ info("cleanup, browser state restored");
+}
+
+function deltaTime(time, expectedTime) {
+ return Math.abs(expectedTime - time);
+}
+
+function getWindowUrl(win) {
+ return win.gBrowser.selectedBrowser?.currentURI?.spec;
+}
+
+function getWindowByTabUrl(url) {
+ return BrowserWindowTracker.orderedWindows.find(
+ win => getWindowUrl(win) == url
+ );
+}
+
+add_task(async function restoredTabs() {
+ const now = Date.now();
+ await SessionStoreTestUtils.promiseBrowserState({
+ windows: [
+ {
+ tabs: [
+ tabEntry("data:,Window0-Tab0", yesterday),
+ tabEntry("data:,Window0-Tab1", yesterday),
+ ],
+ selected: 2,
+ },
+ ],
+ });
+ is(
+ gBrowser.visibleTabs[1],
+ gBrowser.selectedTab,
+ "The selected tab is the 2nd visible tab"
+ );
+ is(
+ getWindowUrl(window),
+ "data:,Window0-Tab1",
+ "The expected tab is selected"
+ );
+ Assert.greaterOrEqual(
+ gBrowser.selectedTab.lastSeenActive,
+ now,
+ "The selected tab's lastSeenActive is now"
+ );
+ Assert.greaterOrEqual(
+ gBrowser.selectedTab.lastAccessed,
+ now,
+ "The selected tab's lastAccessed is now"
+ );
+
+ // tab restored from session but never seen or active
+ is(
+ gBrowser.visibleTabs[0].lastSeenActive,
+ yesterday,
+ "The restored tab's lastSeenActive is yesterday"
+ );
+ await cleanup();
+});
+
+add_task(async function switchingTabs() {
+ let now = Date.now();
+ let initialTab = gBrowser.selectedTab;
+ let applicationStart = Services.startup.getStartupInfo().start.getTime();
+ let openedTab = BrowserTestUtils.addTab(gBrowser, "data:,Tab1");
+ await BrowserTestUtils.browserLoaded(openedTab.linkedBrowser);
+
+ ok(!openedTab.selected, "The background tab we opened isn't selected");
+ Assert.greaterOrEqual(
+ initialTab.selected && initialTab.lastSeenActive,
+ now,
+ "The initial tab is selected and last seen now"
+ );
+
+ is(
+ openedTab.lastSeenActive,
+ applicationStart,
+ `Background tab got default lastSeenActive value, delta: ${deltaTime(
+ openedTab.lastSeenActive,
+ applicationStart
+ )}`
+ );
+
+ now = Date.now();
+ await BrowserTestUtils.switchTab(gBrowser, openedTab);
+ Assert.greaterOrEqual(
+ openedTab.lastSeenActive,
+ now,
+ "The tab we switched to is last seen now"
+ );
+
+ await cleanup();
+});
+
+add_task(async function switchingWindows() {
+ info("Restoring to the test browser state");
+ await SessionStoreTestUtils.promiseBrowserState({
+ windows: [
+ {
+ tabs: [tabEntry("data:,Window1-Tab0", yesterday)],
+ selected: 1,
+ sizemodeBeforeMinimized: "normal",
+ sizemode: "maximized",
+ zIndex: 1, // this will be the selected window
+ },
+ {
+ tabs: [tabEntry("data:,Window2-Tab0", yesterday)],
+ selected: 1,
+ sizemodeBeforeMinimized: "normal",
+ sizemode: "maximized",
+ zIndex: 2,
+ },
+ ],
+ });
+ info("promiseBrowserState resolved");
+ info(
+ `BrowserWindowTracker.pendingWindows: ${BrowserWindowTracker.pendingWindows.size}`
+ );
+ await Promise.all(
+ Array.from(BrowserWindowTracker.pendingWindows.values()).map(
+ win => win.deferred.promise
+ )
+ );
+ info("All the pending windows are resolved");
+ info("Waiting for the firstBrowserLoaded in each of the windows");
+ await Promise.all(
+ BrowserWindowTracker.orderedWindows.map(win => {
+ const selectedUrl = getWindowUrl(win);
+ if (selectedUrl && selectedUrl !== "about:blank") {
+ return Promise.resolve();
+ }
+ return BrowserTestUtils.firstBrowserLoaded(win, false);
+ })
+ );
+ let expectedTabURLs = ["data:,Window1-Tab0", "data:,Window2-Tab0"];
+ let [win1, win2] = expectedTabURLs.map(url => getWindowByTabUrl(url));
+ if (BrowserWindowTracker.getTopWindow() !== win1) {
+ info("Switch to win1 which isn't active/top after restoring session");
+ // In theory the zIndex values in the session state should make win1 active
+ // But in practice that isn't always true. To ensure we're testing from a known state,
+ // ensure the first window is active before proceeding with the test
+ await switchToWindow(win1);
+ [win1, win2] = expectedTabURLs.map(url => getWindowByTabUrl(url));
+ }
+
+ let actualTabURLs = Array.from(BrowserWindowTracker.orderedWindows).map(win =>
+ getWindowUrl(win)
+ );
+ Assert.deepEqual(
+ actualTabURLs,
+ expectedTabURLs,
+ "Both windows are open with selected tab URLs in the expected order"
+ );
+
+ let lastSeenTimes = [win1, win2].map(
+ win => win.gBrowser.selectedTab.lastSeenActive
+ );
+
+ info("Focusing the other window");
+ await switchToWindow(win2);
+ // wait a little so the timestamps will differ and then check again
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(res => setTimeout(res, 100));
+ Assert.greater(
+ win2.gBrowser.selectedTab.lastSeenActive,
+ lastSeenTimes[1],
+ "The foreground window selected tab is last seen more recently than it was before being focused"
+ );
+ Assert.greater(
+ win2.gBrowser.selectedTab.lastSeenActive,
+ win1.gBrowser.selectedTab.lastSeenActive,
+ "The foreground window selected tab is last seen more recently than the backgrounded one"
+ );
+
+ lastSeenTimes = [win1, win2].map(
+ win => win.gBrowser.selectedTab.lastSeenActive
+ );
+ // minimize the foreground window and focus the other
+ let promiseSizeModeChange = BrowserTestUtils.waitForEvent(
+ win2,
+ "sizemodechange"
+ );
+ win2.minimize();
+ info("Waiting for the sizemodechange on minimized window");
+ await promiseSizeModeChange;
+ await switchToWindow(win1);
+
+ ok(
+ !win2.gBrowser.selectedTab.linkedBrowser.docShellIsActive,
+ "Docshell should be Inactive"
+ );
+ ok(win2.document.hidden, "Minimized windows's document should be hidden");
+
+ // wait a little so the timestamps will differ and then check again
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(res => setTimeout(res, 100));
+ Assert.greater(
+ win1.gBrowser.selectedTab.lastSeenActive,
+ win2.gBrowser.selectedTab.lastSeenActive,
+ "The foreground window selected tab is last seen more recently than the minimized one"
+ );
+ Assert.greater(
+ win1.gBrowser.selectedTab.lastSeenActive,
+ lastSeenTimes[0],
+ "The foreground window selected tab is last seen more recently than it was before being focused"
+ );
+
+ await cleanup();
+});