Skip to content

Commit a951ad5

Browse files
committed
gh-8309: wait for essential tab restoration
1 parent 503bf54 commit a951ad5

2 files changed

Lines changed: 135 additions & 4 deletions

File tree

src/browser/components/tabbrowser/content/tabbrowser-js.patch

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -833,9 +833,9 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
833833
aTab.closing ||
834834
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
835835
@@ -6834,7 +7037,48 @@
836-
* @param {object} [aOptions={}]
837-
* Key-value pairs that will be serialized into the features string.
838-
*/
836+
* @param {object} [aOptions={}]
837+
* Key-value pairs that will be serialized into the features string.
838+
*/
839839
- replaceTabWithWindow(aTab, aOptions = {}) {
840840
+ #normalizeDuplicatedEssentialTab(tab) {
841841
+ tab.removeAttribute("zen-essential");

src/zen/tests/pinned/browser_essential_move_to_window.js

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ add_task(async function test_Move_Essential_Tab_To_Window_Duplicates() {
2323
const essentialCount = gBrowser._numZenEssentials;
2424
const newWindowPromise = BrowserTestUtils.waitForNewWindow();
2525
const openedWindow = gBrowser.replaceTabWithWindow(tab);
26-
ok(openedWindow, "Moving an Essential tab opens a new window");
26+
is(openedWindow, null, "Moving an Essential tab is deferred until restored");
2727

2828
const newWindow = await newWindowPromise;
2929
await BrowserTestUtils.waitForCondition(
@@ -60,6 +60,137 @@ add_task(async function test_Move_Essential_Tab_To_Window_Duplicates() {
6060
await BrowserTestUtils.removeTab(tab);
6161
});
6262

63+
add_task(async function test_Move_Essential_Waits_For_Duplicate_Restore() {
64+
let newWindow;
65+
let windowOpened = false;
66+
const tab = await BrowserTestUtils.openNewForegroundTab(
67+
gBrowser,
68+
TEST_URL,
69+
true
70+
);
71+
const duplicate = await BrowserTestUtils.openNewForegroundTab(
72+
gBrowser,
73+
"https://example.org/",
74+
true
75+
);
76+
77+
gZenPinnedTabManager.addToEssentials(tab);
78+
const originalDuplicateTab = gBrowser.duplicateTab;
79+
gBrowser.duplicateTab = () => duplicate;
80+
81+
try {
82+
const newWindowPromise = BrowserTestUtils.waitForNewWindow().then(win => {
83+
windowOpened = true;
84+
return win;
85+
});
86+
87+
gBrowser.replaceTabWithWindow(tab);
88+
await TestUtils.waitForTick();
89+
ok(!windowOpened, "The new window waits for the duplicate to restore");
90+
91+
duplicate.dispatchEvent(new CustomEvent("SSTabRestored"));
92+
newWindow = await newWindowPromise;
93+
is(
94+
newWindow.gBrowser.selectedBrowser.currentURI.spec,
95+
"https://example.org/",
96+
"The restored duplicate is moved to the new window"
97+
);
98+
} finally {
99+
gBrowser.duplicateTab = originalDuplicateTab;
100+
if (newWindow && !newWindow.closed) {
101+
await BrowserTestUtils.closeWindow(newWindow);
102+
}
103+
for (const candidate of [tab, duplicate]) {
104+
if (candidate.isConnected && !candidate.closing) {
105+
await BrowserTestUtils.removeTab(candidate);
106+
}
107+
}
108+
}
109+
});
110+
111+
add_task(async function test_Move_Multiple_Essentials_Waits_For_Restore() {
112+
let newWindow;
113+
let windowOpened = false;
114+
const sourceTabs = [
115+
await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL, true),
116+
await BrowserTestUtils.openNewForegroundTab(
117+
gBrowser,
118+
"https://example.org/",
119+
true
120+
),
121+
];
122+
const duplicateTabs = [
123+
await BrowserTestUtils.openNewForegroundTab(
124+
gBrowser,
125+
"https://example.net/",
126+
true
127+
),
128+
await BrowserTestUtils.openNewForegroundTab(
129+
gBrowser,
130+
"https://example.com/?duplicate=2",
131+
true
132+
),
133+
];
134+
135+
for (const tab of sourceTabs) {
136+
gZenPinnedTabManager.addToEssentials(tab);
137+
gBrowser.addToMultiSelectedTabs(tab);
138+
}
139+
140+
const duplicatesBySource = new Map(
141+
sourceTabs.map((tab, index) => [tab, duplicateTabs[index]])
142+
);
143+
const originalDuplicateTab = gBrowser.duplicateTab;
144+
gBrowser.duplicateTab = tab => duplicatesBySource.get(tab);
145+
146+
try {
147+
const newWindowPromise = BrowserTestUtils.waitForNewWindow().then(win => {
148+
windowOpened = true;
149+
return win;
150+
});
151+
152+
gBrowser.replaceTabsWithWindow(sourceTabs[0]);
153+
duplicateTabs[0].dispatchEvent(new CustomEvent("SSTabRestored"));
154+
await TestUtils.waitForTick();
155+
ok(!windowOpened, "The new window waits for every duplicate to restore");
156+
157+
duplicateTabs[1].dispatchEvent(new CustomEvent("SSTabRestored"));
158+
newWindow = await newWindowPromise;
159+
const expectedURLs = [
160+
"https://example.net/",
161+
"https://example.com/?duplicate=2",
162+
];
163+
await BrowserTestUtils.waitForCondition(
164+
() =>
165+
expectedURLs.every(url =>
166+
newWindow.gBrowser.tabs.some(
167+
tab => tab.linkedBrowser.currentURI.spec == url
168+
)
169+
),
170+
"All restored duplicates moved to the new window"
171+
);
172+
173+
const movedURLs = newWindow.gBrowser.tabs
174+
.map(tab => tab.linkedBrowser.currentURI.spec)
175+
.filter(url => expectedURLs.includes(url));
176+
Assert.deepEqual(
177+
movedURLs,
178+
expectedURLs,
179+
"The restored duplicates keep their order and URLs"
180+
);
181+
} finally {
182+
gBrowser.duplicateTab = originalDuplicateTab;
183+
if (newWindow && !newWindow.closed) {
184+
await BrowserTestUtils.closeWindow(newWindow);
185+
}
186+
for (const candidate of [...sourceTabs, ...duplicateTabs]) {
187+
if (candidate.isConnected && !candidate.closing) {
188+
await BrowserTestUtils.removeTab(candidate);
189+
}
190+
}
191+
}
192+
});
193+
63194
add_task(async function test_Forced_Sync_Moves_Essential_Tab() {
64195
let newWindow;
65196
let duplicated = false;

0 commit comments

Comments
 (0)