summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/performance/browser_windowopen.js
blob: 7c27a6e1440e556292394d6972bd2934ec4507bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* 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);
});