diff --git a/browser/base/content/test/performance/browser_appmenu_reflows.js b/browser/base/content/test/performance/browser_appmenu_reflows.js index 2d26c84c3da8..451b9da12d7c 100644 --- a/browser/base/content/test/performance/browser_appmenu_reflows.js +++ b/browser/base/content/test/performance/browser_appmenu_reflows.js @@ -118,7 +118,7 @@ add_task(async function() { BrowserTestUtils.waitForEvent(PanelUI.panel, "popuppositioned"); await PanelUI.show(); await popupPositioned; - }, EXPECTED_APPMENU_OPEN_REFLOWS); + }, EXPECTED_APPMENU_OPEN_REFLOWS, window, PanelUI.panel); // Now open a series of subviews, and then close the appmenu. We // should not reflow during any of this. @@ -160,5 +160,5 @@ add_task(async function() { let hidden = BrowserTestUtils.waitForEvent(PanelUI.panel, "popuphidden"); PanelUI.hide(); await hidden; - }, EXPECTED_APPMENU_SUBVIEW_REFLOWS); + }, EXPECTED_APPMENU_SUBVIEW_REFLOWS, window, PanelUI.panel); }); diff --git a/browser/base/content/test/performance/browser_tabclose_grow_reflows.js b/browser/base/content/test/performance/browser_tabclose_grow_reflows.js index 5ce742719687..e61898af97d2 100644 --- a/browser/base/content/test/performance/browser_tabclose_grow_reflows.js +++ b/browser/base/content/test/performance/browser_tabclose_grow_reflows.js @@ -36,6 +36,12 @@ add_task(async function() { const TAB_COUNT_FOR_GROWTH = computeMaxTabCount(); await createTabs(TAB_COUNT_FOR_GROWTH); + // Because the tab strip is a scrollable frame, we can't use the + // default dirtying function from withReflowObserver and reliably + // get reflows for the strip. Instead, we provide a node that's + // already in the scrollable frame to dirty - in this case, the + // original tab. + let origTab = gBrowser.selectedTab; let lastTab = gBrowser.tabs[gBrowser.tabs.length - 1]; await BrowserTestUtils.switchTab(gBrowser, lastTab); @@ -46,7 +52,7 @@ add_task(async function() { await BrowserTestUtils.waitForEvent(tab, "transitionend", false, e => e.propertyName === "max-width"); await switchDone; - }, EXPECTED_REFLOWS); + }, EXPECTED_REFLOWS, window, origTab); await removeAllButFirstTab(); }); diff --git a/browser/base/content/test/performance/browser_tabclose_reflows.js b/browser/base/content/test/performance/browser_tabclose_reflows.js index 85089ff533eb..bc4e1cb2bc08 100644 --- a/browser/base/content/test/performance/browser_tabclose_reflows.js +++ b/browser/base/content/test/performance/browser_tabclose_reflows.js @@ -22,6 +22,13 @@ const EXPECTED_REFLOWS = [ add_task(async function() { await ensureNoPreloadedBrowser(); + // Because the tab strip is a scrollable frame, we can't use the + // default dirtying function from withReflowObserver and reliably + // get reflows for the strip. Instead, we provide a node that's + // already in the scrollable frame to dirty - in this case, the + // original tab. + let origTab = gBrowser.selectedTab; + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); await BrowserTestUtils.waitForCondition(() => tab._fullyOpen); @@ -32,6 +39,6 @@ add_task(async function() { await BrowserTestUtils.waitForEvent(tab, "transitionend", false, e => e.propertyName === "max-width"); await switchDone; - }, EXPECTED_REFLOWS); + }, EXPECTED_REFLOWS, window, origTab); is(EXPECTED_REFLOWS.length, 0, "No reflows are expected when closing a tab"); }); diff --git a/browser/base/content/test/performance/browser_tabopen_reflows.js b/browser/base/content/test/performance/browser_tabopen_reflows.js index 1fe7363a5e9d..46c005674748 100644 --- a/browser/base/content/test/performance/browser_tabopen_reflows.js +++ b/browser/base/content/test/performance/browser_tabopen_reflows.js @@ -27,6 +27,13 @@ const EXPECTED_REFLOWS = [ add_task(async function() { await ensureNoPreloadedBrowser(); + // Because the tab strip is a scrollable frame, we can't use the + // default dirtying function from withReflowObserver and reliably + // get reflows for the strip. Instead, we provide a node that's + // already in the scrollable frame to dirty - in this case, the + // original tab. + let origTab = gBrowser.selectedTab; + // Add a reflow observer and open a new tab. await withReflowObserver(async function() { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); @@ -34,7 +41,7 @@ add_task(async function() { await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend", false, e => e.propertyName === "max-width"); await switchDone; - }, EXPECTED_REFLOWS); + }, EXPECTED_REFLOWS, window, origTab); let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); await BrowserTestUtils.removeTab(gBrowser.selectedTab); diff --git a/browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js b/browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js index 6776864c91a1..a1e555c44edb 100644 --- a/browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js +++ b/browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js @@ -33,13 +33,20 @@ add_task(async function() { await createTabs(TAB_COUNT_FOR_SQUEEZE); + // Because the tab strip is a scrollable frame, we can't use the + // default dirtying function from withReflowObserver and reliably + // get reflows for the strip. Instead, we provide a node that's + // already in the scrollable frame to dirty - in this case, the + // original tab. + let origTab = gBrowser.selectedTab; + await withReflowObserver(async function() { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); BrowserOpenTab(); await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend", false, e => e.propertyName === "max-width"); await switchDone; - }, EXPECTED_REFLOWS); + }, EXPECTED_REFLOWS, window, origTab); await removeAllButFirstTab(); }); diff --git a/browser/base/content/test/performance/browser_tabswitch_reflows.js b/browser/base/content/test/performance/browser_tabswitch_reflows.js index 1fe223d34057..6d7b0bd2a738 100644 --- a/browser/base/content/test/performance/browser_tabswitch_reflows.js +++ b/browser/base/content/test/performance/browser_tabswitch_reflows.js @@ -32,7 +32,13 @@ add_task(async function() { Assert.equal(EXPECTED_REFLOWS.length, 0, "We shouldn't have added any new expected reflows."); + // Because the tab strip is a scrollable frame, we can't use the + // default dirtying function from withReflowObserver and reliably + // get reflows for the strip. Instead, we provide a node that's + // already in the scrollable frame to dirty - in this case, the + // original tab. let origTab = gBrowser.selectedTab; + let firstSwitchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); let otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser); await firstSwitchDone; @@ -41,7 +47,7 @@ add_task(async function() { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); gBrowser.selectedTab = origTab; await switchDone; - }, EXPECTED_REFLOWS); + }, EXPECTED_REFLOWS, window, origTab); await BrowserTestUtils.removeTab(otherTab); }); diff --git a/browser/base/content/test/performance/head.js b/browser/base/content/test/performance/head.js index 32198cb9146a..650f5d41df71 100644 --- a/browser/base/content/test/performance/head.js +++ b/browser/base/content/test/performance/head.js @@ -65,17 +65,20 @@ * it defaults to the empty Array, meaning no reflows are expected. * @param window (browser window, optional) * The browser window to monitor. Defaults to the current window. + * @param elemToDirty (DOM node, optional) + * Callers can provide a custom DOM node to change some layout style + * on in the event that the action being tested is occurring within + * a scrollable frame. Otherwise, withReflowObserver defaults to dirtying + * the first element child of the window. */ -async function withReflowObserver(testFn, expectedStacks = [], win = window) { - let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - let dirtyFrameFn = () => { - try { - dwu.ensureDirtyRootFrame(); - } catch (e) { - // If this fails, we should probably make note of it, but it's not fatal. - info("Note: ensureDirtyRootFrame threw an exception."); - } +async function withReflowObserver(testFn, expectedStacks = [], win = window, elemToDirty) { + if (!elemToDirty) { + elemToDirty = win.document.firstElementChild; + } + + let i = 0; + let dirtyFrameFn = (e) => { + elemToDirty.style.margin = (++i % 4) + "px"; }; let els = Cc["@mozilla.org/eventlistenerservice;1"] @@ -117,9 +120,7 @@ async function withReflowObserver(testFn, expectedStacks = [], win = window) { }, reflowInterruptible(start, end) { - // We're not interested in interruptible reflows, but might as well take the - // opportuntiy to dirty the root frame. - dirtyFrameFn(); + // We're not interested in interruptible reflows. }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, @@ -147,6 +148,8 @@ async function withReflowObserver(testFn, expectedStacks = [], win = window) { els.removeListenerForAllEvents(win, dirtyFrameFn, true); docShell.removeWeakReflowObserver(observer); + + elemToDirty.style.margin = ""; } }