From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_ext_tabs_hide.js | 375 +++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 browser/components/extensions/test/browser/browser_ext_tabs_hide.js (limited to 'browser/components/extensions/test/browser/browser_ext_tabs_hide.js') diff --git a/browser/components/extensions/test/browser/browser_ext_tabs_hide.js b/browser/components/extensions/test/browser/browser_ext_tabs_hide.js new file mode 100644 index 0000000000..89c50db692 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_tabs_hide.js @@ -0,0 +1,375 @@ +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + ExtensionControlledPopup: + "resource:///modules/ExtensionControlledPopup.sys.mjs", + SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", + TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs", +}); + +const triggeringPrincipal_base64 = E10SUtils.SERIALIZED_SYSTEMPRINCIPAL; + +async function doorhangerTest(testFn) { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["tabs", "tabHide"], + icons: { + 48: "addon-icon.png", + }, + }, + background() { + browser.test.onMessage.addListener(async (msg, data) => { + let tabs = await browser.tabs.query(data); + await browser.tabs[msg](tabs.map(t => t.id)); + browser.test.sendMessage("done"); + }); + }, + useAddonManager: "temporary", + }); + + await extension.startup(); + + // Open some tabs so we can hide them. + let firstTab = gBrowser.selectedTab; + let tabs = [ + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://example.com/?one", + true, + true + ), + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://example.com/?two", + true, + true + ), + ]; + gBrowser.selectedTab = firstTab; + + await testFn(extension); + + BrowserTestUtils.removeTab(tabs[0]); + BrowserTestUtils.removeTab(tabs[1]); + + await extension.unload(); +} + +add_task(function test_doorhanger_keep() { + return doorhangerTest(async function (extension) { + is(gBrowser.visibleTabs.length, 3, "There are 3 visible tabs"); + + // Hide the first tab, expect the doorhanger. + let panel = ExtensionControlledPopup._getAndMaybeCreatePanel(document); + let popupShown = promisePopupShown(panel); + extension.sendMessage("hide", { url: "*://*/?one" }); + await extension.awaitMessage("done"); + await popupShown; + + is(gBrowser.visibleTabs.length, 2, "There are 2 visible tabs now"); + is( + panel.anchorNode.closest("toolbarbutton").id, + "alltabs-button", + "The doorhanger is anchored to the all tabs button" + ); + + // Click the Keep Tabs Hidden button. + let popupnotification = document.getElementById( + "extension-tab-hide-notification" + ); + let popupHidden = promisePopupHidden(panel); + popupnotification.button.click(); + await popupHidden; + + // Hide another tab and ensure the popup didn't open. + extension.sendMessage("hide", { url: "*://*/?two" }); + await extension.awaitMessage("done"); + is(panel.state, "closed", "The popup is still closed"); + is(gBrowser.visibleTabs.length, 1, "There's one visible tab now"); + + extension.sendMessage("show", {}); + await extension.awaitMessage("done"); + }); +}); + +add_task(function test_doorhanger_disable() { + return doorhangerTest(async function (extension) { + is(gBrowser.visibleTabs.length, 3, "There are 3 visible tabs"); + + // Hide the first tab, expect the doorhanger. + let panel = ExtensionControlledPopup._getAndMaybeCreatePanel(document); + let popupShown = promisePopupShown(panel); + extension.sendMessage("hide", { url: "*://*/?one" }); + await extension.awaitMessage("done"); + await popupShown; + + is(gBrowser.visibleTabs.length, 2, "There are 2 visible tabs now"); + is( + panel.anchorNode.closest("toolbarbutton").id, + "alltabs-button", + "The doorhanger is anchored to the all tabs button" + ); + + // verify the contents of the description. + let popupnotification = document.getElementById( + "extension-tab-hide-notification" + ); + let description = popupnotification.querySelector( + "#extension-tab-hide-notification-description" + ); + let addon = await AddonManager.getAddonByID(extension.id); + ok( + description.textContent.includes(addon.name), + "The extension name is in the description" + ); + let images = Array.from(description.querySelectorAll("image")); + is(images.length, 2, "There are two images"); + ok( + images.some(img => img.src.includes("addon-icon.png")), + "There's an icon for the extension" + ); + ok( + images.some(img => + getComputedStyle(img).backgroundImage.includes("arrow-down.svg") + ), + "There's an icon for the all tabs menu" + ); + + // Click the Disable Extension button. + let popupHidden = promisePopupHidden(panel); + popupnotification.secondaryButton.click(); + await popupHidden; + await new Promise(executeSoon); + + is(gBrowser.visibleTabs.length, 3, "There are 3 visible tabs again"); + is(addon.userDisabled, true, "The extension is now disabled"); + }); +}); + +add_task(async function test_tabs_showhide() { + async function background() { + browser.test.onMessage.addListener(async (msg, data) => { + switch (msg) { + case "hideall": { + let tabs = await browser.tabs.query({ hidden: false }); + browser.test.assertEq(tabs.length, 5, "got 5 tabs"); + let ids = tabs.map(tab => tab.id); + browser.test.log(`working with ids ${JSON.stringify(ids)}`); + + let hidden = await browser.tabs.hide(ids); + browser.test.assertEq(hidden.length, 3, "hid 3 tabs"); + tabs = await browser.tabs.query({ hidden: true }); + ids = tabs.map(tab => tab.id); + browser.test.assertEq( + JSON.stringify(hidden.sort()), + JSON.stringify(ids.sort()), + "hidden tabIds match" + ); + + browser.test.sendMessage("hidden", { hidden }); + break; + } + case "showall": { + let tabs = await browser.tabs.query({ hidden: true }); + for (let tab of tabs) { + browser.test.assertTrue(tab.hidden, "tab is hidden"); + } + let ids = tabs.map(tab => tab.id); + browser.tabs.show(ids); + browser.test.sendMessage("shown"); + break; + } + } + }); + } + + let extdata = { + manifest: { permissions: ["tabs", "tabHide"] }, + background, + useAddonManager: "temporary", // So the doorhanger can find the addon. + }; + let extension = ExtensionTestUtils.loadExtension(extdata); + await extension.startup(); + + let sessData = { + windows: [ + { + tabs: [ + { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] }, + { + entries: [ + { url: "https://example.com/", triggeringPrincipal_base64 }, + ], + }, + { + entries: [ + { url: "https://mochi.test:8888/", triggeringPrincipal_base64 }, + ], + }, + ], + }, + { + tabs: [ + { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] }, + { + entries: [ + { url: "http://test1.example.com/", triggeringPrincipal_base64 }, + ], + }, + ], + }, + ], + }; + + // Set up a test session with 2 windows and 5 tabs. + let oldState = SessionStore.getBrowserState(); + let restored = TestUtils.topicObserved("sessionstore-browser-state-restored"); + SessionStore.setBrowserState(JSON.stringify(sessData)); + await restored; + + if (!Services.prefs.getBoolPref("browser.tabs.tabmanager.enabled")) { + for (let win of BrowserWindowIterator()) { + let allTabsButton = win.document.getElementById("alltabs-button"); + is( + getComputedStyle(allTabsButton).display, + "none", + "The all tabs button is hidden" + ); + } + } + + // Attempt to hide all the tabs, however the active tab in each window cannot + // be hidden, so the result will be 3 hidden tabs. + extension.sendMessage("hideall"); + await extension.awaitMessage("hidden"); + + // We have 2 windows in this session. Otherwin is the non-current window. + // In each window, the first tab will be the selected tab and should not be + // hidden. The rest of the tabs should be hidden at this point. Hidden + // status was already validated inside the extension, this double checks + // from chrome code. + let otherwin; + for (let win of BrowserWindowIterator()) { + if (win != window) { + otherwin = win; + } + let tabs = Array.from(win.gBrowser.tabs); + ok(!tabs[0].hidden, "first tab not hidden"); + for (let i = 1; i < tabs.length; i++) { + ok(tabs[i].hidden, "tab hidden value is correct"); + let id = SessionStore.getCustomTabValue(tabs[i], "hiddenBy"); + is(id, extension.id, "tab hiddenBy value is correct"); + await TabStateFlusher.flush(tabs[i].linkedBrowser); + } + + let allTabsButton = win.document.getElementById("alltabs-button"); + isnot( + getComputedStyle(allTabsButton).display, + "none", + "The all tabs button is visible" + ); + } + + // Close the other window then restore it to test that the tabs are + // restored with proper hidden state, and the correct extension id. + await BrowserTestUtils.closeWindow(otherwin); + + otherwin = SessionStore.undoCloseWindow(0); + await BrowserTestUtils.waitForEvent(otherwin, "load"); + let tabs = Array.from(otherwin.gBrowser.tabs); + ok(!tabs[0].hidden, "first tab not hidden"); + for (let i = 1; i < tabs.length; i++) { + ok(tabs[i].hidden, "tab hidden value is correct"); + let id = SessionStore.getCustomTabValue(tabs[i], "hiddenBy"); + is(id, extension.id, "tab hiddenBy value is correct"); + } + + // Test closing the last visible tab, the next tab which is hidden should become + // the selectedTab and will be visible. + ok(!otherwin.gBrowser.selectedTab.hidden, "selected tab is not hidden"); + BrowserTestUtils.removeTab(otherwin.gBrowser.selectedTab); + ok(!otherwin.gBrowser.selectedTab.hidden, "tab was unhidden"); + + // Showall will unhide any remaining hidden tabs. + extension.sendMessage("showall"); + await extension.awaitMessage("shown"); + + // Check from chrome code that all tabs are visible again. + for (let win of BrowserWindowIterator()) { + let tabs = Array.from(win.gBrowser.tabs); + for (let i = 0; i < tabs.length; i++) { + ok(!tabs[i].hidden, "tab hidden value is correct"); + } + } + + // Close second window. + await BrowserTestUtils.closeWindow(otherwin); + + await extension.unload(); + + // Restore pre-test state. + restored = TestUtils.topicObserved("sessionstore-browser-state-restored"); + SessionStore.setBrowserState(oldState); + await restored; +}); + +// Test our shutdown handling. Currently this means any hidden tabs will be +// shown when a tabHide extension is shutdown. We additionally test the +// tabs.onUpdated listener gets called with hidden state changes. +add_task(async function test_tabs_shutdown() { + let tabs = [ + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://example.com/", + true, + true + ), + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://mochi.test:8888/", + true, + true + ), + ]; + + async function background() { + let tabs = await browser.tabs.query({ url: "http://example.com/" }); + let testTab = tabs[0]; + + browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if ("hidden" in changeInfo) { + browser.test.assertEq(tabId, testTab.id, "correct tab was hidden"); + browser.test.assertTrue(changeInfo.hidden, "tab is hidden"); + browser.test.assertEq(tab.url, testTab.url, "tab has correct URL"); + browser.test.sendMessage("changeInfo"); + } + }); + + let hidden = await browser.tabs.hide(testTab.id); + browser.test.assertEq(hidden[0], testTab.id, "tab was hidden"); + tabs = await browser.tabs.query({ hidden: true }); + browser.test.assertEq(tabs[0].id, testTab.id, "tab was hidden"); + browser.test.sendMessage("ready"); + } + + let extdata = { + manifest: { permissions: ["tabs", "tabHide"] }, + useAddonManager: "temporary", // For testing onShutdown. + background, + }; + let extension = ExtensionTestUtils.loadExtension(extdata); + await extension.startup(); + + // test onUpdated + await Promise.all([ + extension.awaitMessage("ready"), + extension.awaitMessage("changeInfo"), + ]); + Assert.ok(tabs[0].hidden, "Tab is hidden by extension"); + + await extension.unload(); + + Assert.ok(!tabs[0].hidden, "Tab is not hidden after unloading extension"); + BrowserTestUtils.removeTab(tabs[0]); + BrowserTestUtils.removeTab(tabs[1]); +}); -- cgit v1.2.3