Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
-
CI results over the last 21 days
- Manifest: browser/components/sessionstore/test/browser.toml
/* Any copyright is dedicated to the Public Domain.
"use strict";
// Tests the session_restore.restore_page_outcome event recorded by
// about:sessionrestore and about:welcomeback.
function makeTab(url) {
return { entries: [{ url, triggeringPrincipal_base64 }] };
}
const ONE_WINDOW_STATE = {
windows: [{ tabs: [makeTab("about:mozilla"), makeTab("about:robots")] }],
};
const TWO_WINDOW_STATE = {
windows: [
{ tabs: [makeTab("about:mozilla"), makeTab("about:robots")] },
{ tabs: [makeTab("about:about")] },
],
};
/**
* Opens and selects a tab showing a restore page.
*
* @param {string} [url]
* "about:sessionrestore" (the default) or "about:welcomeback".
* @param {object} [formdataIds]
* The formdata `id` values to restore into the page, if any.
*/
async function openRestorePage(url = "about:sessionrestore", formdataIds) {
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
let browser = tab.linkedBrowser;
await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" });
await BrowserTestUtils.switchTab(gBrowser, tab);
let tabState = makeTab(url);
if (formdataIds) {
tabState.formdata = { url, id: formdataIds };
}
ss.setTabState(tab, JSON.stringify(tabState));
let loaded = BrowserTestUtils.browserLoaded(browser, { wantLoad: url });
await promiseTabRestored(tab);
await loaded;
return tab;
}
async function showTabList(tab) {
let win = tab.linkedBrowser.contentWindow;
let doc = win.document;
if (doc.getElementById("tabsToggle")) {
doc.getElementById("tabsToggle").click();
} else {
doc.getElementById("radioRestoreChoose").click();
}
await TestUtils.waitForCondition(
() => win.gTreeInitialized,
"Waiting for the tab list to be initialized"
);
}
async function clickRestoreAndCloseNewWindow(tab) {
let newWindowOpened = BrowserTestUtils.waitForNewWindow();
tab.linkedBrowser.contentDocument.getElementById("errorTryAgain").click();
let win = await newWindowOpened;
if (tab.isConnected) {
BrowserTestUtils.removeTab(tab);
}
await BrowserTestUtils.closeWindow(win);
ss.forgetClosedWindow(0);
}
function assertSingleOutcome(expected, message) {
let events = Glean.sessionRestore.restorePageOutcome.testGetValue();
Assert.equal(events?.length, 1, "One outcome event was recorded");
let expectedExtra = Object.fromEntries(
Object.entries(expected).map(([key, value]) => [key, String(value)])
);
Assert.deepEqual(events[0].extra, expectedExtra, message);
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [["browser.startup.page", 0]],
});
});
add_task(async function test_restore_all() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore", {
sessionData: ONE_WINDOW_STATE,
showReason: "many_crashes",
});
await clickRestoreAndCloseNewWindow(tab);
assertSingleOutcome(
{
outcome: "restore_all",
show_reason: "many_crashes",
windows_offered: 1,
windows_selected: 1,
tabs_offered: 2,
tabs_selected: 2,
single_tabs_restored: 0,
},
"Restoring without opening the tab list restores everything"
);
});
add_task(async function test_restore_subset() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore", {
sessionData: TWO_WINDOW_STATE,
showReason: "old_session",
});
await showTabList(tab);
// Rows are: window 1, its two tabs, window 2, its tab.
let win = tab.linkedBrowser.contentWindow;
win.toggleRowChecked(2);
win.toggleRowChecked(3);
await clickRestoreAndCloseNewWindow(tab);
assertSingleOutcome(
{
outcome: "restore_subset",
show_reason: "old_session",
windows_offered: 2,
windows_selected: 1,
tabs_offered: 3,
tabs_selected: 1,
single_tabs_restored: 0,
},
"Unchecked windows and tabs are not counted as selected"
);
});
add_task(async function test_restore_with_hidden_tab_list() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore", {
sessionData: ONE_WINDOW_STATE,
showReason: "old_session",
});
await showTabList(tab);
let win = tab.linkedBrowser.contentWindow;
win.toggleRowChecked(1);
win.document.getElementById("tabsToggle").click();
await clickRestoreAndCloseNewWindow(tab);
assertSingleOutcome(
{
outcome: "restore_all",
show_reason: "old_session",
windows_offered: 1,
windows_selected: 1,
tabs_offered: 2,
tabs_selected: 2,
single_tabs_restored: 0,
},
"Everything is restored, and counted, when the tab list is hidden"
);
});
add_task(async function test_start_new_session() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore", {
sessionData: TWO_WINDOW_STATE,
showReason: "safe_mode",
});
let browser = tab.linkedBrowser;
let loaded = BrowserTestUtils.browserLoaded(browser, {
wantLoad: "about:blank",
});
browser.contentDocument.getElementById("errorCancel").click();
await loaded;
BrowserTestUtils.removeTab(tab);
assertSingleOutcome(
{
outcome: "start_new_session",
show_reason: "safe_mode",
windows_offered: 2,
windows_selected: 2,
tabs_offered: 3,
tabs_selected: 3,
single_tabs_restored: 0,
},
"Starting a new session is recorded, and not followed by abandoned"
);
});
add_task(async function test_no_data() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore");
ok(
tab.linkedBrowser.contentDocument.getElementById("errorTryAgain").disabled,
"The restore button is disabled without session data"
);
BrowserTestUtils.removeTab(tab);
assertSingleOutcome(
{ outcome: "no_data", single_tabs_restored: 0 },
"A page without session data records no_data, with no counts or reason"
);
});
add_task(async function test_abandoned_after_single_tab_restores() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:sessionrestore", {
sessionData: ONE_WINDOW_STATE,
showReason: "old_session",
});
await showTabList(tab);
let tabsBefore = new Set(gBrowser.tabs);
let win = tab.linkedBrowser.contentWindow;
win.restoreSingleTab(1, false);
win.restoreSingleTab(2, false);
for (let newTab of gBrowser.tabs.filter(t => !tabsBefore.has(t))) {
BrowserTestUtils.removeTab(newTab);
}
Assert.equal(
Glean.sessionRestore.restorePageOutcome.testGetValue(),
null,
"Restoring single tabs doesn't record an outcome"
);
BrowserTestUtils.removeTab(tab);
assertSingleOutcome(
{
outcome: "abandoned",
show_reason: "old_session",
windows_offered: 1,
windows_selected: 1,
tabs_offered: 2,
tabs_selected: 2,
single_tabs_restored: 2,
},
"Closing the page records abandoned, with the single tab restores"
);
});
add_task(async function test_welcomeback_restore_subset() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:welcomeback", {
sessionData: ONE_WINDOW_STATE,
showReason: "profile_refresh",
});
await showTabList(tab);
tab.linkedBrowser.contentWindow.toggleRowChecked(1);
await clickRestoreAndCloseNewWindow(tab);
assertSingleOutcome(
{
outcome: "restore_subset",
show_reason: "profile_refresh",
windows_offered: 1,
windows_selected: 1,
tabs_offered: 2,
tabs_selected: 1,
single_tabs_restored: 0,
},
"about:welcomeback records its outcome with the profile_refresh reason"
);
});
add_task(async function test_welcomeback_restore_nothing_selected() {
Services.fog.testResetFOG();
let tab = await openRestorePage("about:welcomeback", {
sessionData: ONE_WINDOW_STATE,
showReason: "profile_refresh",
});
let browser = tab.linkedBrowser;
await showTabList(tab);
browser.contentWindow.toggleRowChecked(0);
let loaded = BrowserTestUtils.browserLoaded(browser, {
wantLoad: "about:blank",
});
browser.contentDocument.getElementById("errorTryAgain").click();
await loaded;
BrowserTestUtils.removeTab(tab);
assertSingleOutcome(
{
outcome: "start_new_session",
show_reason: "profile_refresh",
windows_offered: 1,
windows_selected: 0,
tabs_offered: 2,
tabs_selected: 0,
single_tabs_restored: 0,
},
"Restoring with nothing selected starts a new session"
);
});