summaryrefslogtreecommitdiffstats
path: root/browser/components/firefoxview/tests/browser/browser_opentabs_recency.js
blob: e5beb4700a337c2b563e914a9f5500381ebae258 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/* 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.getUpdateComplete();
  const tabList = openTabsCard.shadowRoot.querySelector("fxview-tab-list");
  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);
});