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 --- .../browser_tabstrip_overflow_underflow.js | 200 +++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js (limited to 'browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js') diff --git a/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js b/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js new file mode 100644 index 0000000000..1fd33ed836 --- /dev/null +++ b/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js @@ -0,0 +1,200 @@ +"use strict"; + +/** + * WHOA THERE: We should never be adding new things to EXPECTED_*_REFLOWS. + * This is a (now empty) list of known reflows. + * Instead of adding more reflows to the lists, you should be modifying your + * code to avoid the reflow. + * + * See https://firefox-source-docs.mozilla.org/performance/bestpractices.html + * for tips on how to do that. + */ +const EXPECTED_OVERFLOW_REFLOWS = [ + /** + * Nothing here! Please don't add anything new! + */ +]; + +const EXPECTED_UNDERFLOW_REFLOWS = [ + /** + * Nothing here! Please don't add anything new! + */ +]; + +/** + * This test ensures that there are no unexpected uninterruptible reflows when + * opening a new tab that will cause the existing tabs to overflow and the tab + * strip to become scrollable. It also tests that there are no unexpected + * uninterruptible reflows when closing that tab, which causes the tab strip to + * underflow. + */ +add_task(async function () { + // Force-enable tab animations + gReduceMotionOverride = false; + + await ensureNoPreloadedBrowser(); + + // The test starts on about:blank and opens an about:blank + // tab which triggers opening the toolbar since + // ensureNoPreloadedBrowser sets AboutNewTab.newTabURL to about:blank. + await SpecialPowers.pushPrefEnv({ + set: [["browser.toolbars.bookmarks.visibility", "never"]], + }); + + const TAB_COUNT_FOR_OVERFLOW = computeMaxTabCount(); + + await createTabs(TAB_COUNT_FOR_OVERFLOW); + + gURLBar.focus(); + await disableFxaBadge(); + + let tabStripRect = + gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect(); + let textBoxRect = gURLBar + .querySelector("moz-input-box") + .getBoundingClientRect(); + + let ignoreTabstripRects = { + filter: rects => + rects.filter( + r => + !( + // We expect plenty of changed rects within the tab strip. + ( + r.y1 >= tabStripRect.top && + r.y2 <= tabStripRect.bottom && + r.x1 >= tabStripRect.left && + r.x2 <= tabStripRect.right + ) + ) + ), + exceptions: [ + { + name: "the urlbar placeolder moves up and down by a few pixels", + condition: r => + r.x1 >= textBoxRect.left && + r.x2 <= textBoxRect.right && + r.y1 >= textBoxRect.top && + r.y2 <= textBoxRect.bottom, + }, + { + name: "bug 1446449 - spurious tab switch spinner", + condition: r => + // In the content area + r.y1 >= + document.getElementById("appcontent").getBoundingClientRect().top, + }, + ], + }; + + await withPerfObserver( + async function () { + let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); + BrowserOpenTab(); + await BrowserTestUtils.waitForEvent( + gBrowser.selectedTab, + "TabAnimationEnd" + ); + await switchDone; + await TestUtils.waitForCondition(() => { + return gBrowser.tabContainer.arrowScrollbox.hasAttribute( + "scrolledtoend" + ); + }); + }, + { expectedReflows: EXPECTED_OVERFLOW_REFLOWS, frames: ignoreTabstripRects } + ); + + Assert.ok( + gBrowser.tabContainer.hasAttribute("overflow"), + "Tabs should now be overflowed." + ); + + // Now test that opening and closing a tab while overflowed doesn't cause + // us to reflow. + await withPerfObserver( + async function () { + let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); + BrowserOpenTab(); + await switchDone; + await TestUtils.waitForCondition(() => { + return gBrowser.tabContainer.arrowScrollbox.hasAttribute( + "scrolledtoend" + ); + }); + }, + { expectedReflows: [], frames: ignoreTabstripRects } + ); + + await withPerfObserver( + async function () { + let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); + BrowserTestUtils.removeTab(gBrowser.selectedTab, { animate: true }); + await switchDone; + }, + { expectedReflows: [], frames: ignoreTabstripRects } + ); + + // At this point, we have an overflowed tab strip, and we've got the last tab + // selected. This should mean that the first tab is scrolled out of view. + // Let's test that we don't reflow when switching to that first tab. + let lastTab = gBrowser.selectedTab; + let arrowScrollbox = gBrowser.tabContainer.arrowScrollbox; + + // First, we'll check that the first tab is actually scrolled + // at least partially out of view. + Assert.ok( + arrowScrollbox.scrollPosition > 0, + "First tab should be partially scrolled out of view." + ); + + // Now switch to the first tab. We shouldn't flush layout at all. + await withPerfObserver( + async function () { + let firstTab = gBrowser.tabs[0]; + await BrowserTestUtils.switchTab(gBrowser, firstTab); + await TestUtils.waitForCondition(() => { + return gBrowser.tabContainer.arrowScrollbox.hasAttribute( + "scrolledtostart" + ); + }); + }, + { expectedReflows: [], frames: ignoreTabstripRects } + ); + + // Okay, now close the last tab. The tabstrip should stay overflowed, but removing + // one more after that should underflow it. + BrowserTestUtils.removeTab(lastTab); + + Assert.ok( + gBrowser.tabContainer.hasAttribute("overflow"), + "Tabs should still be overflowed." + ); + + // Depending on the size of the window, it might take one or more tab + // removals to put the tab strip out of the overflow state, so we'll just + // keep testing removals until that occurs. + while (gBrowser.tabContainer.hasAttribute("overflow")) { + lastTab = gBrowser.tabs[gBrowser.tabs.length - 1]; + if (gBrowser.selectedTab !== lastTab) { + await BrowserTestUtils.switchTab(gBrowser, lastTab); + } + + // ... and make sure we don't flush layout when closing it, and exiting + // the overflowed state. + await withPerfObserver( + async function () { + let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); + BrowserTestUtils.removeTab(lastTab, { animate: true }); + await switchDone; + await TestUtils.waitForCondition(() => !lastTab.isConnected); + }, + { + expectedReflows: EXPECTED_UNDERFLOW_REFLOWS, + frames: ignoreTabstripRects, + } + ); + } + + await removeAllButFirstTab(); +}); -- cgit v1.2.3