/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; /** * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. * Instead of adding reflows to the list, 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_REFLOWS = [ /** * Nothing here! Please don't add anything new! */ ]; // We'll assume the changes we are seeing are due to this focus change if // there are at least 5 areas that changed near the top of the screen, or if // the toolbar background is involved on OSX, but will only ignore this once. function isLikelyFocusChange(rects) { if (rects.length > 5 && rects.every(r => r.y2 < 100)) { return true; } if ( Services.appinfo.OS == "Darwin" && rects.length == 2 && rects.every(r => r.y1 == 0 && r.h == 33) ) { return true; } return false; } /* * This test ensures that there are no unexpected * uninterruptible reflows or flickering areas when opening new windows. */ add_task(async function () { // Flushing all caches helps to ensure that we get consistent // behaviour when opening a new window, even if windows have been // opened in previous tests. Services.obs.notifyObservers(null, "startupcache-invalidate"); Services.obs.notifyObservers(null, "chrome-flush-caches"); let bookmarksToolbarRect = await getBookmarksToolbarRect(); let win = window.openDialog( AppConstants.BROWSER_CHROME_URL, "_blank", "chrome,all,dialog=no,remote,suppressanimation", "about:home" ); await disableFxaBadge(); let alreadyFocused = false; let inRange = (val, min, max) => min <= val && val <= max; let expectations = { expectedReflows: EXPECTED_REFLOWS, frames: { filter(rects, frame, previousFrame) { // The first screenshot we get in OSX / Windows shows an unfocused browser // window for some reason. See bug 1445161. if (!alreadyFocused && isLikelyFocusChange(rects)) { alreadyFocused = true; todo( false, "bug 1445161 - the window should be focused at first paint, " + rects.toSource() ); return []; } return rects; }, exceptions: [ { name: "bug 1421463 - reload toolbar icon shouldn't flicker", condition: r => inRange(r.h, 13, 14) && inRange(r.w, 14, 16) && // icon size inRange(r.y1, 40, 80) && // in the toolbar inRange(r.x1, 65, 100), // near the left side of the screen }, { name: "bug 1555842 - the urlbar shouldn't flicker", condition: r => { let inputFieldRect = win.gURLBar.inputField.getBoundingClientRect(); return ( (!AppConstants.DEBUG || (AppConstants.platform == "linux" && AppConstants.ASAN)) && r.x1 >= inputFieldRect.left && r.x2 <= inputFieldRect.right && r.y1 >= inputFieldRect.top && r.y2 <= inputFieldRect.bottom ); }, }, { name: "Initial bookmark icon appearing after startup", condition: r => r.w == 16 && r.h == 16 && // icon size inRange( r.y1, bookmarksToolbarRect.top, bookmarksToolbarRect.top + bookmarksToolbarRect.height / 2 ) && // in the toolbar inRange(r.x1, 11, 13), // very close to the left of the screen }, { // Note that the length and x values here are a bit weird because on // some fonts, we appear to detect the two words separately. name: "Initial bookmark text ('Getting Started' or 'Get Involved') appearing after startup", condition: r => inRange(r.w, 25, 120) && // length of text inRange(r.h, 9, 15) && // height of text inRange( r.y1, bookmarksToolbarRect.top, bookmarksToolbarRect.top + bookmarksToolbarRect.height / 2 ) && // in the toolbar inRange(r.x1, 30, 90), // close to the left of the screen }, ], }, }; await withPerfObserver( async function () { // Avoid showing the remotecontrol UI. await new Promise(resolve => { win.addEventListener( "DOMContentLoaded", () => { delete win.Marionette; win.Marionette = { running: false }; resolve(); }, { once: true } ); }); await TestUtils.topicObserved( "browser-delayed-startup-finished", subject => subject == win ); let promises = [ BrowserTestUtils.firstBrowserLoaded(win, false), BrowserTestUtils.browserStopped( win.gBrowser.selectedBrowser, "about:home" ), ]; await Promise.all(promises); await new Promise(resolve => { // 10 is an arbitrary value here, it needs to be at least 2 to avoid // races with code initializing itself using idle callbacks. (function waitForIdle(count = 10) { if (!count) { resolve(); return; } Services.tm.idleDispatchToMainThread(() => { waitForIdle(count - 1); }); })(); }); }, expectations, win ); await BrowserTestUtils.closeWindow(win); });