fune/browser/components/firefoxview/tests/browser/browser_opentabs_recency.js

409 lines
13 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/*
This test checks the recent-browsing view of open tabs in about:firefoxview next
presents the correct tab data in the correct order.
*/
const tabURL1 = "data:,Tab1";
const tabURL2 = "data:,Tab2";
const tabURL3 = "data:,Tab3";
const tabURL4 = "data:,Tab4";
let gInitialTab;
let gInitialTabURL;
const { NonPrivateTabs } = ChromeUtils.importESModule(
"resource:///modules/OpenTabs.sys.mjs"
);
add_setup(function () {
gInitialTab = gBrowser.selectedTab;
gInitialTabURL = tabUrl(gInitialTab);
});
function tabUrl(tab) {
return tab.linkedBrowser.currentURI?.spec;
}
async function minimizeWindow(win) {
let promiseSizeModeChange = BrowserTestUtils.waitForEvent(
win,
"sizemodechange"
);
win.minimize();
await promiseSizeModeChange;
ok(
!win.gBrowser.selectedTab.linkedBrowser.docShellIsActive,
"Docshell should be Inactive"
);
ok(win.document.hidden, "Top level window should be hidden");
}
async function restoreWindow(win) {
ok(win.document.hidden, "Top level window should be hidden");
let promiseSizeModeChange = BrowserTestUtils.waitForEvent(
win,
"sizemodechange"
);
// Check if we also need to wait for occlusion to be updated.
let promiseOcclusion;
let willWaitForOcclusion = win.isFullyOccluded;
if (willWaitForOcclusion) {
// Not only do we need to wait for the occlusionstatechange event,
// we also have to wait *one more event loop* to ensure that the
// other listeners to the occlusionstatechange events have fired.
// Otherwise, our browsing context might not have become active
// at the point where we receive the occlusionstatechange event.
promiseOcclusion = BrowserTestUtils.waitForEvent(
win,
"occlusionstatechange"
).then(() => new Promise(resolve => SimpleTest.executeSoon(resolve)));
} else {
promiseOcclusion = Promise.resolve();
}
info("Calling window.restore");
win.restore();
// From browser/base/content/test/general/browser_minimize.js:
// On Ubuntu `window.restore` doesn't seem to work, use a timer to make the
// test fail faster and more cleanly than with a test timeout.
info(
`Waiting for sizemodechange ${
willWaitForOcclusion ? "and occlusionstatechange " : ""
}event`
);
let timer;
await Promise.race([
Promise.all([promiseSizeModeChange, promiseOcclusion]),
new Promise((resolve, reject) => {
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
timer = setTimeout(() => {
reject(
`timed out waiting for sizemodechange sizemodechange ${
willWaitForOcclusion ? "and occlusionstatechange " : ""
}event`
);
}, 5000);
}),
]);
clearTimeout(timer);
ok(
win.gBrowser.selectedTab.linkedBrowser.docShellIsActive,
"Docshell should be active again"
);
ok(!win.document.hidden, "Top level window should be visible");
}
async function prepareOpenTabs(urls, win = window) {
const reusableTabURLs = ["about:newtab", "about:blank"];
const gBrowser = win.gBrowser;
for (let url of urls) {
if (
gBrowser.visibleTabs.length == 1 &&
reusableTabURLs.includes(gBrowser.selectedBrowser.currentURI.spec)
) {
// we'll load into this tab rather than opening a new one
info(
`Loading ${url} into blank tab: ${gBrowser.selectedBrowser.currentURI.spec}`
);
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url);
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, null, url);
} else {
info(`Loading ${url} into new tab`);
await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
}
await new Promise(res => win.requestAnimationFrame(res));
}
Assert.equal(
gBrowser.visibleTabs.length,
urls.length,
`Prepared ${urls.length} tabs as expected`
);
Assert.equal(
tabUrl(gBrowser.selectedTab),
urls[urls.length - 1],
"The selectedTab is the last of the URLs given as expected"
);
}
async function cleanup(...windowsToClose) {
await Promise.all(
windowsToClose.map(win => BrowserTestUtils.closeWindow(win))
);
while (gBrowser.visibleTabs.length > 1) {
await SessionStoreTestUtils.closeTab(gBrowser.tabs.at(-1));
}
if (gBrowser.selectedBrowser.currentURI.spec !== gInitialTabURL) {
BrowserTestUtils.startLoadingURIString(
gBrowser.selectedBrowser,
gInitialTabURL
);
await BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
null,
gInitialTabURL
);
}
}
function getOpenTabsComponent(browser) {
return browser.contentDocument.querySelector(
"view-recentbrowsing view-opentabs"
);
}
async function checkTabList(browser, expected) {
const tabsView = getOpenTabsComponent(browser);
const openTabsCard = tabsView.shadowRoot.querySelector("view-opentabs-card");
await tabsView.updateComplete;
const tabList = openTabsCard.shadowRoot.querySelector("fxview-tab-list");
await tabList.getUpdateComplete();
Assert.ok(tabList, "Found the tab list element");
await TestUtils.waitForCondition(() => tabList.rowEls.length);
let actual = Array.from(tabList.rowEls).map(row => row.url);
Assert.deepEqual(
actual,
expected,
"Tab list has items with URLs in the expected order"
);
}
add_task(async function test_single_window_tabs() {
await prepareOpenTabs([tabURL1, tabURL2]);
await openFirefoxViewTab(window).then(async viewTab => {
const browser = viewTab.linkedBrowser;
await checkTabList(browser, [tabURL2, tabURL1]);
// switch to the first tab
let promiseHidden = BrowserTestUtils.waitForEvent(
browser.contentDocument,
"visibilitychange"
);
let tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await BrowserTestUtils.switchTab(gBrowser, gBrowser.visibleTabs[0]);
await promiseHidden;
await tabChangeRaised;
});
// and check the results in the open tabs section of Recent Browsing
await openFirefoxViewTab(window).then(async viewTab => {
const browser = viewTab.linkedBrowser;
await checkTabList(browser, [tabURL1, tabURL2]);
});
await cleanup();
});
add_task(async function test_multiple_window_tabs() {
const fxViewURL = getFirefoxViewURL();
const win1 = window;
let tabChangeRaised;
await prepareOpenTabs([tabURL1, tabURL2]);
const win2 = await BrowserTestUtils.openNewBrowserWindow();
await prepareOpenTabs([tabURL3, tabURL4], win2);
// to avoid confusing the results by activating different windows,
// check fxview in the current window - which is win2
info("Switching to fxview tab in win2");
await openFirefoxViewTab(win2).then(async viewTab => {
const browser = viewTab.linkedBrowser;
await checkTabList(browser, [tabURL4, tabURL3, tabURL2, tabURL1]);
Assert.equal(
tabUrl(win2.gBrowser.selectedTab),
fxViewURL,
`The selected tab in window 2 is ${fxViewURL}`
);
info("Switching to first tab (tab3) in win2");
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
let promiseHidden = BrowserTestUtils.waitForEvent(
browser.contentDocument,
"visibilitychange"
);
await BrowserTestUtils.switchTab(
win2.gBrowser,
win2.gBrowser.visibleTabs[0]
);
Assert.equal(
tabUrl(win2.gBrowser.selectedTab),
tabURL3,
`The selected tab in window 2 is ${tabURL3}`
);
await tabChangeRaised;
await promiseHidden;
});
info("Opening fxview in win2 to confirm tab3 is most recent");
await openFirefoxViewTab(win2).then(async viewTab => {
const browser = viewTab.linkedBrowser;
info("Check result of selecting 1ist tab in window 2");
await checkTabList(browser, [tabURL3, tabURL4, tabURL2, tabURL1]);
});
info("Focusing win1, where tab2 should be selected");
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await SimpleTest.promiseFocus(win1);
await tabChangeRaised;
Assert.equal(
tabUrl(win1.gBrowser.selectedTab),
tabURL2,
`The selected tab in window 1 is ${tabURL2}`
);
info("Opening fxview in win1 to confirm tab2 is most recent");
await openFirefoxViewTab(win1).then(async viewTab => {
const browser = viewTab.linkedBrowser;
info(
"In fxview, check result of activating window 1, where tab 2 is selected"
);
await checkTabList(browser, [tabURL2, tabURL3, tabURL4, tabURL1]);
let promiseHidden = BrowserTestUtils.waitForEvent(
browser.contentDocument,
"visibilitychange"
);
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
info("Switching to first visible tab (tab1) in win1");
await BrowserTestUtils.switchTab(
win1.gBrowser,
win1.gBrowser.visibleTabs[0]
);
await promiseHidden;
await tabChangeRaised;
});
// check result in the fxview in the 1st window
info("Opening fxview in win1 to confirm tab1 is most recent");
await openFirefoxViewTab(win1).then(async viewTab => {
const browser = viewTab.linkedBrowser;
info("Check result of selecting 1st tab in win1");
await checkTabList(browser, [tabURL1, tabURL2, tabURL3, tabURL4]);
});
await cleanup(win2);
});
add_task(async function test_windows_activation() {
const win1 = window;
await prepareOpenTabs([tabURL1], win1);
let fxViewTab;
let tabChangeRaised;
info("switch to firefox-view and leave it selected");
await openFirefoxViewTab(win1).then(tab => (fxViewTab = tab));
const win2 = await BrowserTestUtils.openNewBrowserWindow();
await prepareOpenTabs([tabURL2], win2);
const win3 = await BrowserTestUtils.openNewBrowserWindow();
await prepareOpenTabs([tabURL3], win3);
await tabChangeRaised;
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await SimpleTest.promiseFocus(win1);
await tabChangeRaised;
const browser = fxViewTab.linkedBrowser;
await checkTabList(browser, [tabURL3, tabURL2, tabURL1]);
info("switch to win2 and confirm its selected tab becomes most recent");
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await SimpleTest.promiseFocus(win2);
await tabChangeRaised;
await checkTabList(browser, [tabURL2, tabURL3, tabURL1]);
await cleanup(win2, win3);
});
add_task(async function test_minimize_restore_windows() {
const win1 = window;
let tabChangeRaised;
await prepareOpenTabs([tabURL1, tabURL2]);
const win2 = await BrowserTestUtils.openNewBrowserWindow();
await prepareOpenTabs([tabURL3, tabURL4], win2);
// to avoid confusing the results by activating different windows,
// check fxview in the current window - which is win2
info("Opening fxview in win2 to confirm tab4 is most recent");
await openFirefoxViewTab(win2).then(async viewTab => {
const browser = viewTab.linkedBrowser;
await checkTabList(browser, [tabURL4, tabURL3, tabURL2, tabURL1]);
let promiseHidden = BrowserTestUtils.waitForEvent(
browser.contentDocument,
"visibilitychange"
);
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
info("Switching to the first tab (tab3) in 2nd window");
await BrowserTestUtils.switchTab(
win2.gBrowser,
win2.gBrowser.visibleTabs[0]
);
await promiseHidden;
await tabChangeRaised;
});
// then minimize the window, focusing the 1st window
info("Minimizing win2, leaving tab 3 selected");
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await minimizeWindow(win2);
info("Focusing win1, where tab2 is selected - making it most recent");
await SimpleTest.promiseFocus(win1);
await tabChangeRaised;
Assert.equal(
tabUrl(win1.gBrowser.selectedTab),
tabURL2,
`The selected tab in window 1 is ${tabURL2}`
);
info("Opening fxview in win1 to confirm tab2 is most recent");
await openFirefoxViewTab(win1).then(async viewTab => {
const browser = viewTab.linkedBrowser;
await checkTabList(browser, [tabURL2, tabURL3, tabURL4, tabURL1]);
info(
"Restoring win2 and focusing it - which should make its selected tab most recent"
);
tabChangeRaised = BrowserTestUtils.waitForEvent(
NonPrivateTabs,
"TabRecencyChange"
);
await restoreWindow(win2);
await SimpleTest.promiseFocus(win2);
await tabChangeRaised;
info(
"Checking tab order in fxview in win1, to confirm tab3 is most recent"
);
await checkTabList(browser, [tabURL3, tabURL2, tabURL4, tabURL1]);
});
await cleanup(win2);
});