From a90a5cba08fdf6c0ceb95101c275108a152a3aed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:37 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- browser/base/content/test/tabs/browser.toml | 4 + .../content/test/tabs/browser_blank_tab_label.js | 49 ++++++ ...rowser_multiselect_tabs_close_duplicate_tabs.js | 178 +++++++++++++++++++++ .../base/content/test/tabs/browser_tab_preview.js | 94 +++++++++++ .../test/tabs/browser_visibleTabs_contextMenu.js | 19 +-- 5 files changed, 333 insertions(+), 11 deletions(-) create mode 100644 browser/base/content/test/tabs/browser_blank_tab_label.js create mode 100644 browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js (limited to 'browser/base/content/test/tabs') diff --git a/browser/base/content/test/tabs/browser.toml b/browser/base/content/test/tabs/browser.toml index fa77a8b1a4..8a95c87a6e 100644 --- a/browser/base/content/test/tabs/browser.toml +++ b/browser/base/content/test/tabs/browser.toml @@ -30,6 +30,8 @@ skip-if = [ ["browser_bfcache_exemption_about_pages.js"] skip-if = ["!fission"] +["browser_blank_tab_label.js"] + ["browser_bug580956.js"] ["browser_bug_1387976_restore_lazy_tab_browser_muted_state.js"] @@ -140,6 +142,8 @@ support-files = [ ["browser_multiselect_tabs_close.js"] +["browser_multiselect_tabs_close_duplicate_tabs.js"] + ["browser_multiselect_tabs_close_other_tabs.js"] ["browser_multiselect_tabs_close_tabs_to_the_left.js"] diff --git a/browser/base/content/test/tabs/browser_blank_tab_label.js b/browser/base/content/test/tabs/browser_blank_tab_label.js new file mode 100644 index 0000000000..9fe5f6b1b0 --- /dev/null +++ b/browser/base/content/test/tabs/browser_blank_tab_label.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Ensure that we don't use an entirely-blank (non-printable) document title + * as the tab label. + */ +add_task(async function test_ensure_printable_label() { + const TEST_DOC = ` + + + +  &%23x0301;&%23x061C; + Is my title blank?`; + + let newTab; + function tabLabelChecker() { + Assert.stringMatches( + newTab.label, + /\p{L}|\p{N}|\p{P}|\p{S}/u, + "Tab label should contain printable character." + ); + } + let mutationObserver = new MutationObserver(tabLabelChecker); + registerCleanupFunction(() => mutationObserver.disconnect()); + + gBrowser.tabContainer.addEventListener( + "TabOpen", + event => { + newTab = event.target; + tabLabelChecker(); + mutationObserver.observe(newTab, { + attributeFilter: ["label"], + }); + }, + { once: true } + ); + + await BrowserTestUtils.withNewTab("data:text/html," + TEST_DOC, async () => { + // Wait another longer-than-tick to ensure more mutation observer things have + // come in. + await new Promise(executeSoon); + + // Check one last time for good measure, for the final label: + tabLabelChecker(); + }); +}); diff --git a/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js b/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js new file mode 100644 index 0000000000..d18795447f --- /dev/null +++ b/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js @@ -0,0 +1,178 @@ +const PREF_WARN_ON_CLOSE = "browser.tabs.warnOnCloseOtherTabs"; +const PREF_SHOWN_DUPE_DIALOG = + "browser.tabs.haveShownCloseAllDuplicateTabsWarning"; + +add_task(async function setPref() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_WARN_ON_CLOSE, false], + [PREF_SHOWN_DUPE_DIALOG, true], + ], + }); +}); + +add_task(async function withAMultiSelectedTab() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab(); + let tab2 = await addTab(); + let tab3 = await addTab(); + let tab4 = await addTab(); + + is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs"); + + await triggerClickOn(tab1, { ctrlKey: true }); + + let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned"); + gBrowser.pinTab(tab4); + await tab4Pinned; + + ok(initialTab.multiselected, "InitialTab is multiselected"); + ok(tab1.multiselected, "Tab1 is multiselected"); + ok(!tab2.multiselected, "Tab2 is not multiselected"); + ok(!tab3.multiselected, "Tab3 is not multiselected"); + ok(!tab4.multiselected, "Tab4 is not multiselected"); + ok(tab4.pinned, "Tab4 is pinned"); + is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs"); + is(gBrowser.selectedTab, initialTab, "InitialTab is the active tab"); + + let closingTabs = [tab2, tab3]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + gBrowser.removeDuplicateTabs(tab1); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(!tab1.closing, "Tab1 is not closing"); + ok(tab2.closing, "Tab2 is closing"); + ok(tab3.closing, "Tab3 is closing"); + ok(!tab4.closing, "Tab4 is not closing"); + is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs"); + is(gBrowser.selectedTab, initialTab, "InitialTab is still the active tab"); + + gBrowser.clearMultiSelectedTabs(); + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab4); +}); + +add_task(async function withNotAMultiSelectedTab() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab("http://mochi.test:8888/"); + let tab2 = await addTab("http://mochi.test:8888/"); + let tab3 = await addTab("http://mochi.test:8888/"); + let tab4 = await addTab("http://mochi.test:8888/"); + let tab5 = await addTab("http://mochi.test:8888/"); + let tab6 = await addTab("http://mochi.test:8888/", { userContextId: 1 }); + + is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs"); + + await BrowserTestUtils.switchTab(gBrowser, tab1); + await triggerClickOn(tab2, { ctrlKey: true }); + await triggerClickOn(tab5, { ctrlKey: true }); + + let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned"); + gBrowser.pinTab(tab4); + await tab4Pinned; + + let tab5Pinned = BrowserTestUtils.waitForEvent(tab5, "TabPinned"); + gBrowser.pinTab(tab5); + await tab5Pinned; + + ok(!initialTab.multiselected, "InitialTab is not multiselected"); + ok(tab1.multiselected, "Tab1 is multiselected"); + ok(tab2.multiselected, "Tab2 is multiselected"); + ok(!tab3.multiselected, "Tab3 is not multiselected"); + ok(!tab4.multiselected, "Tab4 is not multiselected"); + ok(tab4.pinned, "Tab4 is pinned"); + ok(tab5.multiselected, "Tab5 is multiselected"); + ok(tab5.pinned, "Tab5 is pinned"); + ok(!tab6.multiselected, "Tab6 is not multiselected"); + ok(!tab6.pinned, "Tab6 is not pinned"); + is(gBrowser.multiSelectedTabsCount, 3, "Three multiselected tabs"); + is(gBrowser.selectedTab, tab1, "Tab1 is the active tab"); + + let closingTabs = [tab1, tab2]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + await BrowserTestUtils.switchTab( + gBrowser, + gBrowser.removeDuplicateTabs(tab3) + ); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(tab1.closing, "Tab1 is closing"); + ok(tab2.closing, "Tab2 is closing"); + ok(!tab3.closing, "Tab3 is not closing"); + ok(!tab4.closing, "Tab4 is not closing"); + ok(!tab5.closing, "Tab5 is not closing"); + ok(!tab6.closing, "Tab6 is not closing"); + is( + gBrowser.multiSelectedTabsCount, + 0, + "Zero multiselected tabs, selection is cleared" + ); + is(gBrowser.selectedTab, tab3, "tab3 is the active tab now"); + + for (let tab of [tab3, tab4, tab5, tab6]) { + BrowserTestUtils.removeTab(tab); + } +}); + +add_task(async function closeAllDuplicateTabs() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab("http://mochi.test:8888/one"); + let tab2 = await addTab("http://mochi.test:8888/two", { userContextId: 1 }); + let tab3 = await addTab("http://mochi.test:8888/one"); + let tab4 = await addTab("http://mochi.test:8888/two"); + let tab5 = await addTab("http://mochi.test:8888/one"); + let tab6 = await addTab("http://mochi.test:8888/two"); + + let tab1Pinned = BrowserTestUtils.waitForEvent(tab1, "TabPinned"); + gBrowser.pinTab(tab1); + await tab1Pinned; + + // So we have 1p,2c,1,2,1,2 + // We expect 1p,2c,X,2,X,X because the pinned 1 will dupe the other two 1, + // but the 2c's userContextId makes it unique against the other two 2, + // but one of the other two 2 will close. + + // Ensure tab4 remains by making it active more recently than tab6. + tab4._lastSeenActive = Date.now(); // as recent as it gets. + + // Assert some preconditions: + ok(tab1.pinned, "Tab1 is pinned"); + Assert.greater(tab4.lastSeenActive, tab6.lastSeenActive); + + let closingTabs = [tab3, tab5, tab6]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + await BrowserTestUtils.switchTab( + gBrowser, + gBrowser.removeAllDuplicateTabs(initialTab) + ); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(!tab1.closing, "Tab1 is not closing"); + ok(!tab2.closing, "Tab2 is not closing"); + ok(tab3.closing, "Tab3 is closing"); + ok(!tab4.closing, "Tab4 is not closing"); + ok(tab5.closing, "Tab5 is closing"); + ok(tab6.closing, "Tab6 is closing"); + + for (let tab of [tab1, tab2, tab4]) { + BrowserTestUtils.removeTab(tab); + } +}); diff --git a/browser/base/content/test/tabs/browser_tab_preview.js b/browser/base/content/test/tabs/browser_tab_preview.js index 0f83b1e28c..19ba85b9f8 100644 --- a/browser/base/content/test/tabs/browser_tab_preview.js +++ b/browser/base/content/test/tabs/browser_tab_preview.js @@ -34,6 +34,7 @@ add_setup(async function () { set: [ ["browser.tabs.cardPreview.enabled", true], ["browser.tabs.cardPreview.showThumbnails", false], + ["browser.tabs.tooltipsShowPidAndActiveness", false], ["ui.tooltip.delay_ms", 0], ], }); @@ -81,6 +82,99 @@ add_task(async function hoverTests() { }); }); +/** + * Verify that the pid and activeness statuses are not shown + * when the flag is not enabled. + */ +add_task(async function pidAndActivenessHiddenByDefaultTests() { + const tabUrl1 = + "data:text/html,First New TabHello"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const previewContainer = document.getElementById("tab-preview-panel"); + + await openPreview(tab1); + Assert.equal( + previewContainer.querySelector(".tab-preview-pid").innerText, + "", + "Tab PID is not shown" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "", + "Tab activeness is not shown" + ); + + await closePreviews(); + + BrowserTestUtils.removeTab(tab1); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); +}); + +add_task(async function pidAndActivenessTests() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.tabs.tooltipsShowPidAndActiveness", true]], + }); + + const tabUrl1 = + "data:text/html,Single process tabHello"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const tabUrl2 = `data:text/html, + + Multi-process tab + + + + + `; + const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); + const previewContainer = document.getElementById("tab-preview-panel"); + + await openPreview(tab1); + Assert.stringMatches( + previewContainer.querySelector(".tab-preview-pid").innerText, + /^pid: \d+$/, + "Tab PID is shown on single process tab" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "", + "Tab activeness is not shown on inactive tab" + ); + await closePreviews(); + + await openPreview(tab2); + Assert.stringMatches( + previewContainer.querySelector(".tab-preview-pid").innerText, + /^pids: \d+, \d+$/, + "Tab PIDs are shown on multi-process tab" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "[A]", + "Tab activeness is shown on active tab" + ); + await closePreviews(); + + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab2); + await SpecialPowers.popPrefEnv(); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); +}); + /** * Verify that non-selected tabs display a thumbnail in their preview * when browser.tabs.cardPreview.showThumbnails is set to true, diff --git a/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js b/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js index 202c43ce47..06fdd27d9c 100644 --- a/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js +++ b/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js @@ -2,11 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const remoteClientsFixture = [ - { id: 1, name: "Foo" }, - { id: 2, name: "Bar" }, -]; - add_task(async function test() { // There should be one tab when we start the test let [origTab] = gBrowser.visibleTabs; @@ -16,9 +11,8 @@ add_task(async function test() { // Check the context menu with two tabs updateTabContextMenu(origTab); - is( - document.getElementById("context_closeTab").disabled, - false, + ok( + !document.getElementById("context_closeTab").disabled, "Close Tab is enabled" ); @@ -29,11 +23,14 @@ add_task(async function test() { // Check the context menu with one tab. updateTabContextMenu(testTab); - is( - document.getElementById("context_closeTab").disabled, - false, + ok( + !document.getElementById("context_closeTab").disabled, "Close Tab is enabled when more than one tab exists" ); + ok( + !document.getElementById("context_closeDuplicateTabs").disabled, + "Close duplicate tabs is enabled when more than one tab with the same URL exists" + ); // Add a tab that will get pinned // So now there's one pinned tab, one visible unpinned tab, and one hidden tab -- cgit v1.2.3