Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

add_task(async function test() {
const tabs = [gBrowser.selectedTab];
for (let i = 0; i < 6; ++i) {
tabs.push(BrowserTestUtils.addTab(gBrowser));
}
// Check that setSuccessor works.
gBrowser.setSuccessor(tabs[0], tabs[2]);
is(tabs[0].successor, tabs[2], "setSuccessor sets successor");
ok(tabs[2].predecessors.has(tabs[0]), "setSuccessor adds predecessor");
BrowserTestUtils.removeTab(tabs[0]);
is(
gBrowser.selectedTab,
tabs[2],
"When closing a selected tab, select its successor"
);
// Check that the successor of a hidden tab becomes the successor of the
// tab's predecessors.
gBrowser.setSuccessor(tabs[1], tabs[2]);
gBrowser.setSuccessor(tabs[3], tabs[1]);
ok(!tabs[2].predecessors.has(tabs[3]));
gBrowser.hideTab(tabs[1]);
is(
tabs[3].successor,
tabs[2],
"A predecessor of a hidden tab should take as its successor the hidden tab's successor"
);
ok(tabs[2].predecessors.has(tabs[3]));
gBrowser.showTab(tabs[1]);
// Check that the successor of a closed tab also becomes the successor of the
// tab's predecessors.
gBrowser.setSuccessor(tabs[1], tabs[2]);
gBrowser.setSuccessor(tabs[3], tabs[1]);
ok(!tabs[2].predecessors.has(tabs[3]));
BrowserTestUtils.removeTab(tabs[1]);
is(
tabs[3].successor,
tabs[2],
"A predecessor of a closed tab should take as its successor the closed tab's successor"
);
ok(tabs[2].predecessors.has(tabs[3]));
// Check that clearing a successor makes the browser fall back to selecting
// the owner or next tab.
await BrowserTestUtils.switchTab(gBrowser, tabs[3]);
gBrowser.setSuccessor(tabs[3], null);
is(tabs[3].successor, null, "setSuccessor(..., null) should clear successor");
ok(
!tabs[2].predecessors.has(tabs[3]),
"setSuccessor(..., null) should remove the old successor from predecessors"
);
BrowserTestUtils.removeTab(tabs[3]);
is(
gBrowser.selectedTab,
tabs[4],
"When the active tab is closed and its successor has been cleared, select the next tab"
);
// Like closing or hiding a tab, moving a tab to another window should also
// result in its successor becoming the successor of the moved tab's
// predecessors.
gBrowser.setSuccessor(tabs[4], tabs[2]);
gBrowser.setSuccessor(tabs[2], tabs[5]);
const secondWin = gBrowser.replaceTabsWithWindow(tabs[2]);
await TestUtils.waitForCondition(
() => tabs[2].closing,
"Wait for tab to be transferred"
);
is(
tabs[4].successor,
tabs[5],
"A predecessor of a tab moved to another window should take as its successor the moved tab's successor"
);
// Trying to set a successor across windows should fail.
let threw = false;
try {
gBrowser.setSuccessor(tabs[4], secondWin.gBrowser.selectedTab);
} catch (ex) {
threw = true;
}
ok(threw, "No cross window successors");
is(tabs[4].successor, tabs[5], "Successor should remain unchanged");
threw = false;
try {
secondWin.gBrowser.setSuccessor(tabs[4], null);
} catch (ex) {
threw = true;
}
ok(threw, "No setting successors for another window's tab");
is(tabs[4].successor, tabs[5], "Successor should remain unchanged");
BrowserTestUtils.closeWindow(secondWin);
// A tab can't be its own successor
gBrowser.setSuccessor(tabs[4], tabs[4]);
is(
tabs[4].successor,
null,
"Successor should be cleared instead of pointing to itself"
);
gBrowser.setSuccessor(tabs[4], tabs[5]);
gBrowser.setSuccessor(tabs[5], tabs[4]);
is(
tabs[4].successor,
tabs[5],
"Successors can form cycles of length > 1 [a]"
);
is(
tabs[5].successor,
tabs[4],
"Successors can form cycles of length > 1 [b]"
);
BrowserTestUtils.removeTab(tabs[5]);
is(
tabs[4].successor,
null,
"Successor should be cleared instead of pointing to itself"
);
gBrowser.removeTab(tabs[4]);
});