browser_windowopen.js (6746B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. 8 * Instead of adding reflows to the list, you should be modifying your code to 9 * avoid the reflow. 10 * 11 * See https://firefox-source-docs.mozilla.org/performance/bestpractices.html 12 * for tips on how to do that. 13 */ 14 const EXPECTED_REFLOWS = [ 15 /** 16 * Nothing here! Please don't add anything new! 17 */ 18 ]; 19 20 add_setup(async function setup() { 21 SpecialPowers.pushPrefEnv({ 22 set: [["ui.prefersReducedMotion", 1]], 23 }); 24 }); 25 26 const SIDEBAR_REVAMP = Services.prefs.getBoolPref("sidebar.revamp"); 27 28 /* 29 * This test ensures that there are no unexpected 30 * uninterruptible reflows or flickering areas when opening new windows. 31 */ 32 add_task(async function () { 33 // Flushing all caches helps to ensure that we get consistent 34 // behaviour when opening a new window, even if windows have been 35 // opened in previous tests. 36 Services.obs.notifyObservers(null, "startupcache-invalidate"); 37 Services.obs.notifyObservers(null, "chrome-flush-caches"); 38 39 let bookmarksToolbarRect = await getBookmarksToolbarRect(); 40 41 let win = window.openDialog( 42 AppConstants.BROWSER_CHROME_URL, 43 "_blank", 44 "chrome,all,dialog=no,remote,suppressanimation", 45 "about:home" 46 ); 47 48 await disableFxaBadge(); 49 50 let alreadyFocused = false; 51 let inRange = (val, min, max) => min <= val && val <= max; 52 let tabBoundingRect = undefined; 53 let urlbarBoundingRect = undefined; 54 let expectations = { 55 expectedReflows: EXPECTED_REFLOWS, 56 frames: { 57 filter(rects, frame) { 58 // The first screenshot we get in OSX / Windows shows an unfocused browser 59 // window for some reason. See bug 1445161. 60 if (!alreadyFocused && isLikelyFocusChange(rects, frame)) { 61 todo( 62 false, 63 "bug 1445161 - the window should be focused at first paint, " + 64 rects.toSource() 65 ); 66 return []; 67 } 68 alreadyFocused = true; 69 return rects; 70 }, 71 exceptions: [ 72 { 73 name: "bug 1421463 - reload toolbar icon shouldn't flicker", 74 condition: r => { 75 // sidebar.revamp places the sidebar button in the toolbar, 76 // which offsets the position of the reload button by about 36px. 77 const xOffset = SIDEBAR_REVAMP ? 36 : 0; 78 return ( 79 inRange(r.h, 13, 14) && 80 inRange(r.w, 14, 16) && // icon size 81 inRange(r.y1, 40, 80) && // in the toolbar 82 inRange(r.x1, 65 + xOffset, 100 + xOffset) // near the left side of the screen 83 ); 84 }, 85 }, 86 { 87 name: "bug 1555842 - the urlbar shouldn't flicker", 88 condition: r => { 89 let inputFieldRect = win.gURLBar.inputField.getBoundingClientRect(); 90 91 return ( 92 (!AppConstants.DEBUG || 93 (AppConstants.platform == "linux" && AppConstants.ASAN)) && 94 r.x1 >= inputFieldRect.left && 95 r.x2 <= inputFieldRect.right && 96 r.y1 >= inputFieldRect.top && 97 r.y2 <= inputFieldRect.bottom 98 ); 99 }, 100 }, 101 { 102 name: "Pixel snapping on urlbar bottom border on MacOS & Windows", 103 condition(r) { 104 if (!urlbarBoundingRect) { 105 urlbarBoundingRect = document 106 .getElementById("urlbar") 107 .getBoundingClientRect(); 108 } 109 return rectMatchesBottomBorder(r, urlbarBoundingRect); 110 }, 111 }, 112 { 113 name: "Initial bookmark icon appearing after startup", 114 condition: r => 115 r.w == 16 && 116 r.h == 16 && // icon size 117 inRange( 118 r.y1, 119 bookmarksToolbarRect.top, 120 bookmarksToolbarRect.top + bookmarksToolbarRect.height / 2 121 ) && // in the toolbar 122 inRange(r.x1, 11, 13), // very close to the left of the screen 123 }, 124 { 125 // Note that the length and x values here are a bit weird because on 126 // some fonts, we appear to detect the two words separately. 127 name: "Initial bookmark text ('Getting Started' or 'Get Involved') appearing after startup", 128 condition: r => 129 inRange(r.w, 25, 120) && // length of text 130 inRange(r.h, 9, 15) && // height of text 131 inRange( 132 r.y1, 133 bookmarksToolbarRect.top, 134 bookmarksToolbarRect.top + bookmarksToolbarRect.height / 2 135 ) && // in the toolbar 136 inRange(r.x1, 30, 90), // close to the left of the screen 137 }, 138 { 139 name: "Shadow around active tab should not flicker on macOS (bug 1960967)", 140 condition(r) { 141 const tabRect = tabBoundingRect 142 ? tabBoundingRect 143 : (tabBoundingRect = gBrowser.tabContainer 144 .querySelector("tab[selected=true] .tab-background") 145 .getBoundingClientRect()); 146 return ( 147 inRange(r.x1, tabRect.x - 2, tabRect.x + 2) && 148 inRange(r.y1, tabRect.y - 2, tabRect.y + 2) && 149 inRange(r.w, tabRect.width - 4, tabRect.width + 4) && 150 inRange(r.h, tabRect.height - 4, tabRect.height + 4) 151 ); 152 }, 153 }, 154 ], 155 }, 156 }; 157 158 await withPerfObserver( 159 async function () { 160 // Avoid showing the remotecontrol UI. 161 await new Promise(resolve => { 162 win.addEventListener( 163 "DOMContentLoaded", 164 () => { 165 delete win.Marionette; 166 win.Marionette = { running: false }; 167 resolve(); 168 }, 169 { once: true } 170 ); 171 }); 172 173 await TestUtils.topicObserved( 174 "browser-delayed-startup-finished", 175 subject => subject == win 176 ); 177 178 let promises = [ 179 BrowserTestUtils.firstBrowserLoaded(win, false), 180 BrowserTestUtils.browserStopped( 181 win.gBrowser.selectedBrowser, 182 "about:home" 183 ), 184 ]; 185 186 await Promise.all(promises); 187 188 await new Promise(resolve => { 189 // 10 is an arbitrary value here, it needs to be at least 2 to avoid 190 // races with code initializing itself using idle callbacks. 191 (function waitForIdle(count = 10) { 192 if (!count) { 193 resolve(); 194 return; 195 } 196 Services.tm.idleDispatchToMainThread(() => { 197 waitForIdle(count - 1); 198 }); 199 })(); 200 }); 201 }, 202 expectations, 203 win 204 ); 205 206 await BrowserTestUtils.closeWindow(win); 207 });