Backed out changeset 7b2ffe9a4d06 (bug 1869605) for causing bc failures on browser_no...
[gecko.git] / browser / components / firefoxview / tests / browser / browser_recently_closed_tabs.js
blobe5613e3e73da2cccc55fe9322754ad6c6c71b168
1 /* Any copyright is dedicated to the Public Domain.
2    http://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
6 requestLongerTimeout(10);
8 /**
9  * Ensure that the add_new_tab, close_tab, and open_then_close
10  * functions are creating sessionstore entries associated with
11  * the correct window where the tests are run.
12  */
14 ChromeUtils.defineESModuleGetters(globalThis, {
15   SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
16 });
18 const RECENTLY_CLOSED_EVENT = [
19   ["firefoxview", "recently_closed", "tabs", undefined],
22 const CLOSED_TABS_OPEN_EVENT = [
23   ["firefoxview", "closed_tabs_open", "tabs", "false"],
26 const RECENTLY_CLOSED_DISMISS_EVENT = [
27   ["firefoxview", "dismiss_closed_tab", "tabs", undefined],
30 async function add_new_tab(URL) {
31   let tab = BrowserTestUtils.addTab(gBrowser, URL);
32   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
33   return tab;
36 async function close_tab(tab) {
37   const sessionStorePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
38   BrowserTestUtils.removeTab(tab);
39   await sessionStorePromise;
42 async function dismiss_tab(tab, content) {
43   info(`Dismissing tab ${tab.dataset.targeturi}`);
44   const closedObjectsChanged = () =>
45     TestUtils.topicObserved("sessionstore-closed-objects-changed");
46   let dismissButton = tab.querySelector(".closed-tab-li-dismiss");
47   EventUtils.synthesizeMouseAtCenter(dismissButton, {}, content);
48   await closedObjectsChanged();
51 add_setup(async function setup() {
52   // set updateTimeMs to 0 to prevent unexpected/unrelated DOM mutations during testing
53   await SpecialPowers.pushPrefEnv({
54     set: [["browser.tabs.firefox-view.updateTimeMs", 100000]],
55   });
56 });
58 add_task(async function test_empty_list() {
59   clearHistory();
61   await withFirefoxView({}, async browser => {
62     const { document } = browser.contentWindow;
63     let container = document.querySelector("#collapsible-tabs-container");
64     ok(
65       container.classList.contains("empty-container"),
66       "collapsible container should have correct styling when the list is empty"
67     );
69     Assert.ok(
70       document.getElementById("recently-closed-tabs-placeholder"),
71       "The empty message is displayed."
72     );
74     Assert.ok(
75       !document.querySelector("ol.closed-tabs-list"),
76       "The recently closed tabs list is not displayed."
77     );
79     const tab1 = await add_new_tab(URLs[0]);
81     await close_tab(tab1);
83     // The UI update happens asynchronously as we learn of the new closed tab.
84     await BrowserTestUtils.waitForMutationCondition(
85       container,
86       { attributeFilter: ["class"] },
87       () => !container.classList.contains("empty-container")
88     );
89     ok(
90       !container.classList.contains("empty-container"),
91       "collapsible container should have correct styling when the list is not empty"
92     );
94     Assert.ok(
95       !document.getElementById("recently-closed-tabs-placeholder"),
96       "The empty message is not displayed."
97     );
99     Assert.ok(
100       document.querySelector("ol.closed-tabs-list"),
101       "The recently closed tabs list is displayed."
102     );
104     is(
105       document.querySelector("ol.closed-tabs-list").children.length,
106       1,
107       "recently-closed-tabs-list should have one list item"
108     );
109   });
112 add_task(async function test_list_ordering() {
113   Services.obs.notifyObservers(null, "browser:purge-session-history");
114   is(
115     SessionStore.getClosedTabCount(),
116     0,
117     "Closed tab count after purging session history"
118   );
120   const closedObjectsChanged = () =>
121     TestUtils.topicObserved("sessionstore-closed-objects-changed");
123   const tab1 = await add_new_tab(URLs[0]);
124   const tab2 = await add_new_tab(URLs[1]);
125   const tab3 = await add_new_tab(URLs[2]);
127   gBrowser.selectedTab = tab3;
129   await close_tab(tab3);
130   await closedObjectsChanged();
132   await close_tab(tab2);
133   await closedObjectsChanged();
135   await close_tab(tab1);
136   await closedObjectsChanged();
138   await withFirefoxView({}, async browser => {
139     const { document } = browser.contentWindow;
140     const tabsList = document.querySelector("ol.closed-tabs-list");
141     await BrowserTestUtils.waitForMutationCondition(
142       tabsList,
143       { childList: true },
144       () => tabsList.children.length > 1
145     );
147     is(
148       document.querySelector("ol.closed-tabs-list").children.length,
149       3,
150       "recently-closed-tabs-list should have three list items"
151     );
153     // check that the ordering is correct when user navigates to another tab, and then closes multiple tabs.
154     ok(
155       document
156         .querySelector("ol.closed-tabs-list")
157         .children[0].textContent.includes("mochi.test"),
158       "first list item in recently-closed-tabs-list is in the correct order"
159     );
161     ok(
162       document
163         .querySelector("ol.closed-tabs-list")
164         .children[2].textContent.includes("example.net"),
165       "last list item in recently-closed-tabs-list is in the correct order"
166     );
168     let ele = document.querySelector("ol.closed-tabs-list").firstElementChild;
169     let uri = ele.getAttribute("data-targeturi");
170     await clearAllParentTelemetryEvents();
171     let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, uri);
172     ele.querySelector(".closed-tab-li-main").click();
173     await newTabPromise;
175     await TestUtils.waitForCondition(
176       () => {
177         let events = Services.telemetry.snapshotEvents(
178           Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
179           false
180         ).parent;
181         return events && events.length >= 1;
182       },
183       "Waiting for recently_closed firefoxview telemetry events.",
184       200,
185       100
186     );
188     TelemetryTestUtils.assertEvents(
189       RECENTLY_CLOSED_EVENT,
190       { category: "firefoxview" },
191       { clear: true, process: "parent" }
192     );
194     gBrowser.removeTab(gBrowser.selectedTab);
196     await clearAllParentTelemetryEvents();
198     await waitForElementVisible(
199       browser,
200       "#recently-closed-tabs-container > summary"
201     );
202     document.querySelector("#recently-closed-tabs-container > summary").click();
204     await TestUtils.waitForCondition(
205       () => {
206         let events = Services.telemetry.snapshotEvents(
207           Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
208           false
209         ).parent;
210         return events && events.length >= 1;
211       },
212       "Waiting for closed_tabs_open firefoxview telemetry event.",
213       200,
214       100
215     );
217     TelemetryTestUtils.assertEvents(
218       CLOSED_TABS_OPEN_EVENT,
219       { category: "firefoxview" },
220       { clear: true, process: "parent" }
221     );
222   });
225 add_task(async function test_max_list_items() {
226   Services.obs.notifyObservers(null, "browser:purge-session-history");
227   is(
228     SessionStore.getClosedTabCountForWindow(window),
229     0,
230     "Closed tab count after purging session history"
231   );
233   await open_then_close(URLs[0]);
234   await open_then_close(URLs[1]);
235   await open_then_close(URLs[2]);
237   // Seed the closed tabs count. We've assured that we've opened and
238   // closed at least three tabs because of the calls to open_then_close
239   // above.
240   let mockMaxTabsLength = 3;
242   await withFirefoxView({}, async browser => {
243     const { document } = browser.contentWindow;
245     // override this value for testing purposes
246     document.querySelector("recently-closed-tabs-list").maxTabsLength =
247       mockMaxTabsLength;
249     ok(
250       !document
251         .querySelector("#collapsible-tabs-container")
252         .classList.contains("empty-container"),
253       "collapsible container should have correct styling when the list is not empty"
254     );
256     Assert.ok(
257       !document.getElementById("recently-closed-tabs-placeholder"),
258       "The empty message is not displayed."
259     );
261     Assert.ok(
262       document.querySelector("ol.closed-tabs-list"),
263       "The recently closed tabs list is displayed."
264     );
266     is(
267       document.querySelector("ol.closed-tabs-list").children.length,
268       mockMaxTabsLength,
269       `recently-closed-tabs-list should have ${mockMaxTabsLength} list items`
270     );
272     const closedObjectsChanged = TestUtils.topicObserved(
273       "sessionstore-closed-objects-changed"
274     );
275     // add another tab
276     const tab = await add_new_tab(URLs[3]);
277     await close_tab(tab);
278     await closedObjectsChanged;
279     let firstListItem = document.querySelector("ol.closed-tabs-list")
280       .children[0];
281     await BrowserTestUtils.waitForMutationCondition(
282       firstListItem,
283       { characterData: true, childList: true, subtree: true },
284       () => firstListItem.textContent.includes(".org")
285     );
286     ok(
287       firstListItem.textContent.includes("example.org"),
288       "first list item in recently-closed-tabs-list should have been updated"
289     );
291     is(
292       document.querySelector("ol.closed-tabs-list").children.length,
293       mockMaxTabsLength,
294       `recently-closed-tabs-list should still have ${mockMaxTabsLength} list items`
295     );
296   });
299 add_task(async function test_time_updates_correctly() {
300   clearHistory();
301   is(
302     SessionStore.getClosedTabCountForWindow(window),
303     0,
304     "Closed tab count after purging session history"
305   );
307   // Set the closed tabs state to include one tab that was closed 2 seconds ago.
308   // This is well below the initial threshold for displaying the 'Just now' timestamp.
309   // It is also much greater than the 5ms threshold we use for the updated pref value,
310   // which results in the timestamp text changing after the pref value is changed.
311   const TAB_CLOSED_AGO_MS = 2000;
312   const TAB_UPDATE_TIME_MS = 5;
313   const TAB_CLOSED_STATE = {
314     windows: [
315       {
316         tabs: [{ entries: [] }],
317         _closedTabs: [
318           {
319             state: { entries: [{ url: "https://www.example.com/" }] },
320             closedId: 0,
321             closedAt: Date.now() - TAB_CLOSED_AGO_MS,
322             image: null,
323             title: "Example",
324           },
325         ],
326       },
327     ],
328   };
329   await SessionStore.setBrowserState(JSON.stringify(TAB_CLOSED_STATE));
331   is(
332     SessionStore.getClosedTabCountForWindow(window),
333     1,
334     "Closed tab count after setting browser state"
335   );
337   await withFirefoxView({}, async browser => {
338     const { document } = browser.contentWindow;
340     const tabsList = document.querySelector("ol.closed-tabs-list");
341     const numOfListItems = tabsList.children.length;
342     const lastListItem = tabsList.children[numOfListItems - 1];
343     const timeLabel = lastListItem.querySelector("span.closed-tab-li-time");
344     let initialTimeText = timeLabel.textContent;
345     Assert.stringContains(
346       initialTimeText,
347       "Just now",
348       "recently-closed-tabs list item time is 'Just now'"
349     );
351     await SpecialPowers.pushPrefEnv({
352       set: [["browser.tabs.firefox-view.updateTimeMs", TAB_UPDATE_TIME_MS]],
353     });
355     await BrowserTestUtils.waitForMutationCondition(
356       timeLabel,
357       { childList: true },
358       () => !timeLabel.textContent.includes("now")
359     );
361     isnot(
362       timeLabel.textContent,
363       initialTimeText,
364       "recently-closed-tabs list item time has updated"
365     );
367     await SpecialPowers.popPrefEnv();
368   });
369   // Cleanup recently closed tab data.
370   clearHistory();
373 add_task(async function test_list_maintains_focus_when_restoring_tab() {
374   await SpecialPowers.clearUserPref(RECENTLY_CLOSED_STATE_PREF);
375   Services.obs.notifyObservers(null, "browser:purge-session-history");
376   is(
377     SessionStore.getClosedTabCountForWindow(window),
378     0,
379     "Closed tab count after purging session history"
380   );
382   const sandbox = sinon.createSandbox();
383   let setupCompleteStub = sandbox.stub(
384     TabsSetupFlowManager,
385     "isTabSyncSetupComplete"
386   );
387   setupCompleteStub.returns(true);
389   await open_then_close(URLs[0]);
390   await open_then_close(URLs[1]);
391   await open_then_close(URLs[2]);
393   await withFirefoxView({}, async browser => {
394     let gBrowser = browser.getTabBrowser();
395     const { document } = browser.contentWindow;
396     const list = document.querySelectorAll(".closed-tab-li");
397     list[0].querySelector(".closed-tab-li-main").focus();
398     EventUtils.synthesizeKey("KEY_Enter");
399     let firefoxViewTab = gBrowser.tabs.find(tab => tab.label == "Firefox View");
400     await BrowserTestUtils.switchTab(gBrowser, firefoxViewTab);
401     Assert.ok(
402       document.activeElement.textContent.includes("mochitest index"),
403       "Focus should be on the first item in the recently closed list"
404     );
405   });
407   // clean up extra tabs
408   while (gBrowser.tabs.length > 1) {
409     BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
410   }
412   clearHistory();
413   await open_then_close(URLs[2]);
414   await withFirefoxView({}, async browser => {
415     let gBrowser = browser.getTabBrowser();
416     const { document } = browser.contentWindow;
417     let expectedFocusedElement = document.getElementById(
418       "recently-closed-tabs-header-section"
419     );
420     const list = document.querySelectorAll(".closed-tab-li");
421     list[0].querySelector(".closed-tab-li-main").focus();
422     EventUtils.synthesizeKey("KEY_Enter");
423     let firefoxViewTab = gBrowser.tabs.find(tab => tab.label == "Firefox View");
424     await BrowserTestUtils.switchTab(gBrowser, firefoxViewTab);
425     is(
426       document.activeElement,
427       expectedFocusedElement,
428       "Focus should be on the section header"
429     );
430   });
432   // clean up extra tabs
433   while (gBrowser.tabs.length > 1) {
434     BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
435   }
438 add_task(async function test_switch_before_closing() {
439   clearHistory();
441   const INITIAL_URL = "https://example.org/iwilldisappear";
442   const FINAL_URL = "https://example.com/ishouldappear";
443   await withFirefoxView({}, async function (browser) {
444     let gBrowser = browser.getTabBrowser();
445     let newTab = await BrowserTestUtils.openNewForegroundTab(
446       gBrowser,
447       INITIAL_URL
448     );
449     // Switch back to FxView:
450     await BrowserTestUtils.switchTab(
451       gBrowser,
452       gBrowser.getTabForBrowser(browser)
453     );
454     // Update the tab we opened to a different site:
455     let loadPromise = BrowserTestUtils.browserLoaded(
456       newTab.linkedBrowser,
457       null,
458       FINAL_URL
459     );
460     BrowserTestUtils.startLoadingURIString(newTab.linkedBrowser, FINAL_URL);
461     await loadPromise;
462     // Close the added tab
463     BrowserTestUtils.removeTab(newTab);
465     const { document } = browser.contentWindow;
466     await BrowserTestUtils.waitForMutationCondition(
467       document.querySelector("recently-closed-tabs-list"),
468       { childList: true, subtree: true },
469       () => document.querySelector("ol.closed-tabs-list")
470     );
471     const tabsList = document.querySelector("ol.closed-tabs-list");
472     info("A tab appeared in the list, ensure it has the right URL.");
473     let urlBit = tabsList.children[0].querySelector(".closed-tab-li-url");
474     await BrowserTestUtils.waitForMutationCondition(
475       urlBit,
476       { characterData: true, attributeFilter: ["title"] },
477       () => urlBit.textContent.includes(".com")
478     );
479     Assert.ok(
480       urlBit.textContent.includes("example.com"),
481       "Item should end up with the correct URL."
482     );
483   });
486 add_task(async function test_alt_click_no_launch() {
487   Services.obs.notifyObservers(null, "browser:purge-session-history");
488   is(
489     SessionStore.getClosedTabCountForWindow(window),
490     0,
491     "Closed tab count after purging session history"
492   );
494   await open_then_close(URLs[0]);
496   await withFirefoxView({}, async browser => {
497     let gBrowser = browser.getTabBrowser();
498     let originalTabsLength = gBrowser.tabs.length;
499     await BrowserTestUtils.synthesizeMouseAtCenter(
500       ".closed-tab-li .closed-tab-li-main",
501       { altKey: true },
502       browser
503     );
505     is(
506       gBrowser.tabs.length,
507       originalTabsLength,
508       `Opened tabs length should still be ${originalTabsLength}`
509     );
510   });
514  * Asserts that tabs that have been recently closed can be
515  * restored by clicking on them, using the Enter key,
516  * and using the Space bar.
517  */
518 add_task(async function test_restore_recently_closed_tabs() {
519   clearHistory();
521   await open_then_close(URLs[0]);
522   await open_then_close(URLs[1]);
523   await open_then_close(URLs[2]);
525   await EventUtils.synthesizeMouseAtCenter(
526     gBrowser.ownerDocument.getElementById("firefox-view-button"),
527     { type: "mousedown" },
528     window
529   );
530   // Wait for Firefox View to be loaded before interacting
531   // with the page.
532   await BrowserTestUtils.browserLoaded(
533     window.FirefoxViewHandler.tab.linkedBrowser
534   );
535   let { document } = gBrowser.contentWindow;
536   let tabRestored = BrowserTestUtils.waitForNewTab(gBrowser, URLs[2]);
537   EventUtils.synthesizeMouseAtCenter(
538     document.querySelector(".closed-tab-li"),
539     {},
540     gBrowser.contentWindow
541   );
543   await tabRestored;
544   ok(true, "Tab was restored by mouse click");
546   await EventUtils.synthesizeMouseAtCenter(
547     gBrowser.ownerDocument.getElementById("firefox-view-button"),
548     { type: "mousedown" },
549     window
550   );
552   tabRestored = BrowserTestUtils.waitForNewTab(gBrowser, URLs[1]);
553   document.querySelector(".closed-tab-li .closed-tab-li-main").focus();
554   EventUtils.synthesizeKey("KEY_Enter", {}, gBrowser.contentWindow);
556   await tabRestored;
557   ok(true, "Tab was restored by using the Enter key");
559   // clean up extra tabs
560   while (gBrowser.tabs.length > 1) {
561     BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
562   }
566  * Asserts that tabs are removed from Recently Closed tabs in
567  * Fx View when tabs are removed from latest closed tab data.
568  * Ex: Selecting "Reopen Closed Tab" from the tabs toolbar
569  * context menu
570  */
571 add_task(async function test_reopen_recently_closed_tabs() {
572   clearHistory();
574   await open_then_close(URLs[0]);
575   await open_then_close(URLs[1]);
576   await open_then_close(URLs[2]);
578   await EventUtils.synthesizeMouseAtCenter(
579     gBrowser.ownerDocument.getElementById("firefox-view-button"),
580     { type: "mousedown" },
581     window
582   );
583   // Wait for Firefox View to be loaded before interacting
584   // with the page.
585   await BrowserTestUtils.browserLoaded(
586     window.FirefoxViewHandler.tab.linkedBrowser
587   );
589   let { document } = gBrowser.contentWindow;
591   let tabReopened = BrowserTestUtils.waitForNewTab(gBrowser, URLs[2]);
592   SessionStore.undoCloseTab(window);
593   await tabReopened;
595   const tabsList = document.querySelector("ol.closed-tabs-list");
597   await EventUtils.synthesizeMouseAtCenter(
598     gBrowser.ownerDocument.getElementById("firefox-view-button"),
599     { type: "mousedown" },
600     window
601   );
603   await BrowserTestUtils.waitForMutationCondition(
604     tabsList,
605     { childList: true },
606     () => tabsList.children.length === 2
607   );
609   Assert.equal(
610     tabsList.children[0].dataset.targeturi,
611     URLs[1],
612     `First recently closed item should be ${URLs[1]}`
613   );
615   await close_tab(gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]);
617   await BrowserTestUtils.waitForMutationCondition(
618     tabsList,
619     { childList: true },
620     () => tabsList.children.length === 3
621   );
623   Assert.equal(
624     tabsList.children[0].dataset.targeturi,
625     URLs[2],
626     `First recently closed item should be ${URLs[2]}`
627   );
629   await dismiss_tab(tabsList.children[0], content);
631   await BrowserTestUtils.waitForMutationCondition(
632     tabsList,
633     { childList: true },
634     () => tabsList.children.length === 2
635   );
637   Assert.equal(
638     tabsList.children[0].dataset.targeturi,
639     URLs[1],
640     `First recently closed item should be ${URLs[1]}`
641   );
643   const contextMenu = gBrowser.ownerDocument.getElementById(
644     "contentAreaContextMenu"
645   );
646   const promisePopup = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
647   EventUtils.synthesizeMouseAtCenter(
648     tabsList.querySelector(".closed-tab-li-title"),
649     {
650       button: 2,
651       type: "contextmenu",
652     },
653     gBrowser.contentWindow
654   );
655   await promisePopup;
656   const promiseNewTab = BrowserTestUtils.waitForNewTab(gBrowser, URLs[1]);
657   contextMenu.activateItem(
658     gBrowser.ownerDocument.getElementById("context-openlinkintab")
659   );
660   await promiseNewTab;
662   await BrowserTestUtils.waitForMutationCondition(
663     tabsList,
664     { childList: true },
665     () => tabsList.children.length === 1
666   );
668   Assert.equal(
669     tabsList.children[0].dataset.targeturi,
670     URLs[0],
671     `First recently closed item should be ${URLs[0]}`
672   );
674   // clean up extra tabs
675   while (gBrowser.tabs.length > 1) {
676     BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
677   }
681  * Asserts that tabs that have been recently closed can be
682  * dismissed by clicking on their respective dismiss buttons.
683  */
684 add_task(async function test_dismiss_tab() {
685   const TAB_UPDATE_TIME_MS = 5;
686   Services.obs.notifyObservers(null, "browser:purge-session-history");
687   Assert.equal(
688     SessionStore.getClosedTabCountForWindow(window),
689     0,
690     "Closed tab count after purging session history"
691   );
692   await clearAllParentTelemetryEvents();
694   await withFirefoxView({}, async browser => {
695     const { document } = browser.contentWindow;
697     const closedObjectsChanged = () =>
698       TestUtils.topicObserved("sessionstore-closed-objects-changed");
700     const tab1 = await add_new_tab(URLs[0]);
701     const tab2 = await add_new_tab(URLs[1]);
702     const tab3 = await add_new_tab(URLs[2]);
704     await close_tab(tab3);
705     await closedObjectsChanged();
707     await close_tab(tab2);
708     await closedObjectsChanged();
710     await close_tab(tab1);
711     await closedObjectsChanged();
713     await clearAllParentTelemetryEvents();
715     const tabsList = document.querySelector("ol.closed-tabs-list");
716     const numOfListItems = tabsList.children.length;
717     const lastListItem = tabsList.children[numOfListItems - 1];
718     const timeLabel = lastListItem.querySelector("span.closed-tab-li-time");
719     let initialTimeText = timeLabel.textContent;
720     Assert.stringContains(
721       initialTimeText,
722       "Just now",
723       "recently-closed-tabs list item time is 'Just now'"
724     );
726     await SpecialPowers.pushPrefEnv({
727       set: [["browser.tabs.firefox-view.updateTimeMs", TAB_UPDATE_TIME_MS]],
728     });
730     await BrowserTestUtils.waitForMutationCondition(
731       timeLabel,
732       { childList: true },
733       () => !timeLabel.textContent.includes("Just now")
734     );
736     isnot(
737       timeLabel.textContent,
738       initialTimeText,
739       "recently-closed-tabs list item time has updated"
740     );
742     await dismiss_tab(tabsList.children[0], content);
744     await TestUtils.waitForCondition(
745       () => {
746         let events = Services.telemetry.snapshotEvents(
747           Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
748           false
749         ).parent;
750         return events && events.length >= 1;
751       },
752       "Waiting for dismiss_closed_tab firefoxview telemetry event.",
753       200,
754       100
755     );
757     TelemetryTestUtils.assertEvents(
758       RECENTLY_CLOSED_DISMISS_EVENT,
759       { category: "firefoxview" },
760       { clear: true, process: "parent" }
761     );
763     Assert.equal(
764       tabsList.children[0].dataset.targeturi,
765       URLs[1],
766       `First recently closed item should be ${URLs[1]}`
767     );
769     Assert.equal(
770       tabsList.children.length,
771       2,
772       "recently-closed-tabs-list should have two list items"
773     );
775     await clearAllParentTelemetryEvents();
777     await dismiss_tab(tabsList.children[0], content);
779     await TestUtils.waitForCondition(
780       () => {
781         let events = Services.telemetry.snapshotEvents(
782           Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
783           false
784         ).parent;
785         return events && events.length >= 1;
786       },
787       "Waiting for dismiss_closed_tab firefoxview telemetry event.",
788       200,
789       100
790     );
792     TelemetryTestUtils.assertEvents(
793       RECENTLY_CLOSED_DISMISS_EVENT,
794       { category: "firefoxview" },
795       { clear: true, process: "parent" }
796     );
798     Assert.equal(
799       tabsList.children[0].dataset.targeturi,
800       URLs[2],
801       `First recently closed item should be ${URLs[2]}`
802     );
804     Assert.equal(
805       tabsList.children.length,
806       1,
807       "recently-closed-tabs-list should have one list item"
808     );
810     await clearAllParentTelemetryEvents();
812     await dismiss_tab(tabsList.children[0], content);
814     await TestUtils.waitForCondition(
815       () => {
816         let events = Services.telemetry.snapshotEvents(
817           Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
818           false
819         ).parent;
820         return events && events.length >= 1;
821       },
822       "Waiting for dismiss_closed_tab firefoxview telemetry event.",
823       200,
824       100
825     );
827     TelemetryTestUtils.assertEvents(
828       RECENTLY_CLOSED_DISMISS_EVENT,
829       { category: "firefoxview" },
830       { clear: true, process: "parent" }
831     );
833     Assert.ok(
834       document.getElementById("recently-closed-tabs-placeholder"),
835       "The empty message is displayed."
836     );
838     Assert.ok(
839       !document.querySelector("ol.closed-tabs-list"),
840       "The recently closed tabs list is not displayed."
841     );
843     await SpecialPowers.popPrefEnv();
844   });
848  * Asserts that the actionable part of each list item is role="button".
849  * Discussion on why we want a button role can be seen here:
850  * https://bugzilla.mozilla.org/show_bug.cgi?id=1789875#c1
851  */
852 add_task(async function test_button_role() {
853   Services.obs.notifyObservers(null, "browser:purge-session-history");
854   Assert.equal(
855     SessionStore.getClosedTabCountForWindow(window),
856     0,
857     "Closed tab count after purging session history"
858   );
860   await withFirefoxView({}, async browser => {
861     const { document } = browser.contentWindow;
863     clearHistory();
865     await open_then_close(URLs[0]);
866     await open_then_close(URLs[1]);
867     await open_then_close(URLs[2]);
869     await EventUtils.synthesizeMouseAtCenter(
870       gBrowser.ownerDocument.getElementById("firefox-view-button"),
871       { type: "mousedown" },
872       window
873     );
875     const tabsList = document.querySelector("ol.closed-tabs-list");
877     Array.from(tabsList.children).forEach(tabItem => {
878       let actionableElement = tabItem.querySelector(".closed-tab-li-main");
879       Assert.ok(actionableElement.getAttribute("role"), "button");
880     });
881   });