diff options
Diffstat (limited to 'browser/base/content/test/tabs/browser_lastSeenActive.js')
-rw-r--r-- | browser/base/content/test/tabs/browser_lastSeenActive.js | 260 |
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(); +}); |