Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
const REMOTE_URL = "https://www.example.com/";
const ABOUT_ROBOTS_URL = "about:robots";
const NO_TITLE_URL = "data:text/plain,foo";
const BACKUP_STATE = SessionStore.getBrowserState();
registerCleanupFunction(() => promiseBrowserState(BACKUP_STATE));
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["browser.sessionstore.restore_on_demand", true],
["browser.sessionstore.restore_tabs_lazily", true],
],
});
});
/**
* When implementing batch insertion of tabs as part of session restore,
* we started reversing the insertion order of pinned tabs (bug 1607441).
* This test checks we don't regress that again.
*/
add_task(async function test_pinned_tabs_order() {
// we expect 3 pinned tabs plus the selected tab get content restored.
let allTabsRestored = promiseSessionStoreLoads(4);
await promiseBrowserState({
windows: [
{
selected: 4, // SessionStore uses 1-based indexing.
tabs: [
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
},
{ entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
],
},
],
});
await allTabsRestored;
let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
ok(tab1.pinned, "First tab is pinned");
ok(tab2.pinned, "Second tab is pinned");
ok(tab3.pinned, "Third tab is pinned");
ok(!tab4.pinned, "Fourth tab is not pinned");
ok(!tab5.pinned, "Fifth tab is not pinned");
ok(tab4.selected, "Fourth tab is selected");
is(
tab1.linkedBrowser.currentURI.spec,
REMOTE_URL,
"First tab has matching URL"
);
is(
tab2.linkedBrowser.currentURI.spec,
ABOUT_ROBOTS_URL,
"Second tab has matching URL"
);
is(
tab3.linkedBrowser.currentURI.spec,
NO_TITLE_URL,
"Third tab has matching URL"
);
// Clean up for the next task.
await promiseBrowserState(BACKUP_STATE);
});
/**
* When fixing the previous regression, pinned tabs started disappearing out
* of sessions with selected pinned tabs. This test checks that case.
*/
add_task(async function test_selected_pinned_tab_dataloss() {
// we expect 3 pinned tabs (one of which is selected) get content restored.
let allTabsRestored = promiseSessionStoreLoads(3);
await promiseBrowserState({
windows: [
{
selected: 1, // SessionStore uses 1-based indexing.
tabs: [
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
},
{ entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
],
},
],
});
await allTabsRestored;
let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
ok(tab5, "Should have 5 tabs");
ok(tab1.pinned, "First tab is pinned");
ok(tab2.pinned, "Second tab is pinned");
ok(tab3.pinned, "Third tab is pinned");
ok(tab4 && !tab4.pinned, "Fourth tab is not pinned");
ok(tab5 && !tab5.pinned, "Fifth tab is not pinned");
ok(tab1 && tab1.selected, "First (pinned) tab is selected");
is(
tab1.linkedBrowser.currentURI.spec,
REMOTE_URL,
"First tab has matching URL"
);
is(
tab2.linkedBrowser.currentURI.spec,
ABOUT_ROBOTS_URL,
"Second tab has matching URL"
);
is(
tab3.linkedBrowser.currentURI.spec,
NO_TITLE_URL,
"Third tab has matching URL"
);
// Clean up for the next task.
await promiseBrowserState(BACKUP_STATE);
});
/**
* While we're here, it seems useful to have a test for mixed pinned and
* unpinned tabs in session store state, as well as userContextId.
*/
add_task(async function test_mixed_pinned_unpinned() {
// we expect 3 pinned tabs plus the selected tab get content restored.
let allTabsRestored = promiseSessionStoreLoads(4);
await promiseBrowserState({
windows: [
{
selected: 4, // SessionStore uses 1-based indexing.
tabs: [
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{ entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
{
pinned: true,
entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
},
{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
{
pinned: true,
entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
},
],
},
],
});
await allTabsRestored;
let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
ok(tab1.pinned, "First tab is pinned");
ok(tab2.pinned, "Second tab is pinned");
ok(tab3.pinned, "Third tab is pinned");
ok(!tab4.pinned, "Fourth tab is not pinned");
ok(!tab5.pinned, "Fifth tab is not pinned");
// This is confusing to read - the 4th entry in the session data is
// selected. But the 5th entry is pinned, so it moves to the start of the
// tabstrip, so when we fetch `gBrowser.tabs`, the 4th entry in the list
// is actually the 5th tab.
ok(tab5.selected, "Fifth tab is selected");
is(
tab1.linkedBrowser.currentURI.spec,
REMOTE_URL,
"First tab has matching URL"
);
is(
tab2.linkedBrowser.currentURI.spec,
ABOUT_ROBOTS_URL,
"Second tab has matching URL"
);
is(
tab3.linkedBrowser.currentURI.spec,
NO_TITLE_URL,
"Third tab has matching URL"
);
// Clean up for the next task.
await promiseBrowserState(BACKUP_STATE);
});
/**
* After session restore, if we crash an unpinned tab, we noticed pinned tabs
* created in the same process would lose all data (Bug 1624511). This test
* checks that case.
*/
add_task(async function test_pinned_tab_dataloss() {
// We do not run if there are no crash reporters to avoid
// problems with the intentional crash.
if (!AppConstants.MOZ_CRASHREPORTER) {
return;
}
// If we end up increasing the process count limit in future,
// we want to ensure that we don't stop testing this case
// of pinned tab data loss.
if (SpecialPowers.getIntPref("dom.ipc.processCount") > 8) {
ok(
false,
"Process count is greater than 8, update the number of pinned tabs in test."
);
}
// We expect 17 pinned tabs plus the selected tab get content restored.
// Given that the default process count is currently 8, we need this
// number of pinned tabs to reproduce the data loss. If this changes,
// please add more pinned tabs.
let allTabsRestored = promiseSessionStoreLoads(18);
await promiseBrowserState({
windows: [
{
selected: 18, // SessionStore uses 1-based indexing.
tabs: [
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{
pinned: true,
entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
},
{ entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
],
},
],
});
await allTabsRestored;
let tabs = gBrowser.tabs;
await BrowserTestUtils.crashFrame(tabs[17].linkedBrowser);
await TestUtils.topicObserved("sessionstore-state-write-complete");
for (let i = 0; i < tabs.length; i++) {
let tab = tabs[i];
is(
tab.linkedBrowser.currentURI.spec,
REMOTE_URL,
`Tab ${i + 1} should have matching URL`
);
}
// Clean up for the next task.
await promiseBrowserState(BACKUP_STATE);
});