Bug 1516022 - Regression test. r=Gijs
☠☠ backed out by 0b3a6c7175ca ☠ ☠
authorMike Conley <mconley@mozilla.com>
Wed, 16 Jan 2019 18:38:18 +0000
changeset 514116 4fae3add610fe59fec7d7a59faaca897409ac078
parent 514115 c683fbe0b9842988bbc6bff192072448d0e2fe14
child 514117 0be55928fcb7ed372ee3f6aca33e5c7516593a2d
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1516022
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1516022 - Regression test. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D16093
dom/base/test/browser_promiseDocumentFlushed.js
--- a/dom/base/test/browser_promiseDocumentFlushed.js
+++ b/dom/base/test/browser_promiseDocumentFlushed.js
@@ -17,41 +17,81 @@ function dirtyStyleAndLayout(factor = 1)
 
 /**
  * Dirties style of the current browser window, but NOT layout.
  */
 function dirtyStyle() {
   gNavToolbox.style.color = "red";
 }
 
-const gWindowUtils = window.windowUtils;
-
 /**
  * Asserts that no style or layout flushes are required by the
  * current window.
  */
-function assertNoFlushesRequired() {
-  Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+function assertNoFlushesRequired(win = window) {
+  Assert.ok(!win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
             "No style flushes are required.");
-  Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
+  Assert.ok(!win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
             "No layout flushes are required.");
 }
 
 /**
  * Asserts that the DOM has been dirtied, and so style and layout flushes
  * are required.
  */
-function assertFlushesRequired() {
-  Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+function assertFlushesRequired(win = window) {
+  Assert.ok(win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
             "Style flush required.");
-  Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
+  Assert.ok(win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
             "Layout flush required.");
 }
 
 /**
+ * Asserts that a window will not incur any layout flushes when
+ * running function fn.
+ *
+ * @param win (DOM window)
+ *        The window that we expect to not see any layout flushes for.
+ * @param fn (function)
+ *        The function to synchronously call while monitoring for
+ *        layout flushes.
+ */
+function assertFunctionDoesNotFlushLayout(win, fn) {
+  let sawReflow = false;
+
+  let observer = {
+    reflow(start, end) {
+      Assert.ok(false, "Saw a reflow when one was not expected");
+      dump("Stack: " + new Error().stack + "\n");
+      sawReflow = true;
+    },
+
+    reflowInterruptible(start, end) {
+      // Interruptible reflows are the reflows caused by the refresh
+      // driver ticking. These are fine.
+    },
+
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIReflowObserver,
+                                            Ci.nsISupportsWeakReference]),
+  };
+
+  let docShell = win.docShell;
+  docShell.addWeakReflowObserver(observer);
+
+  try {
+    fn();
+    if (!sawReflow) {
+      Assert.ok(true, "Did not see any reflows.");
+    }
+  } finally {
+    docShell.removeWeakReflowObserver(observer);
+  }
+}
+
+/**
  * Removes style changes from dirtyTheDOM() from the browser window,
  * and resolves once the refresh driver ticks.
  */
 async function cleanTheDOM() {
   gNavToolbox.style.padding = "";
   gNavToolbox.style.color = "";
   await window.promiseDocumentFlushed(() => {});
 }
@@ -238,9 +278,60 @@ add_task(async function test_execution_o
 
   Assert.equal(result.length, 8,
     "Should have run all callbacks and Promises.");
 
   for (let i = 0; i < result.length; ++i) {
     Assert.equal(result[i], i,
       "Callbacks and Promises should have run in the expected order.");
   }
+
+  await cleanTheDOM();
 });
+
+/**
+ * Tests that if there's a subframe that needs a layout
+ * flush, that promiseDocumentFlushed will detect it, and
+ * wait until it doesn't before calling the callback.
+ */
+add_task(async function test_subframe_flushes() {
+  const DUMMY_PAGE = getRootDirectory(gTestPath);
+  const PAGE_NAME = "parent-document-flushed";
+  const ABOUT_PAGE = `about:${PAGE_NAME}`;
+
+  // For simplicity, we're forcing a non-remote browser here. This is so
+  // that we can easily load some subframes that could theoretically
+  // cause a flush to occur in the parent process.
+  await BrowserTestUtils.registerAboutPage(registerCleanupFunction,
+                                           PAGE_NAME, DUMMY_PAGE, 0);
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: ABOUT_PAGE,
+  }, async browser => {
+    Assert.ok(!browser.isRemoteBrowser, "Should have a non-remote browser.");
+    // We'll nest a frame within a frame to test that promiseDocumentFlushed
+    // isn't just checking the associated windows immediate children.
+    let outerContent = browser.contentWindow;
+    let outerDoc = browser.contentDocument;
+    let iframe = outerDoc.createElement("iframe");
+    iframe.src = ABOUT_PAGE;
+    let loaded = BrowserTestUtils.waitForEvent(iframe, "load");
+    outerDoc.body.appendChild(iframe);
+    await loaded;
+
+    let innerContent = iframe.contentWindow;
+    let innerDoc = iframe.contentDocument;
+    let target = innerDoc.body;
+    Assert.ok(target);
+
+    assertNoFlushesRequired(outerContent);
+    await window.promiseDocumentFlushed(() => {});
+
+    target.style.width = "5px";
+    assertNoFlushesRequired(outerContent);
+    assertFlushesRequired(innerContent);
+    await window.promiseDocumentFlushed(() => {
+      assertFunctionDoesNotFlushLayout(innerContent, () => {
+        target.getBoundingClientRect();
+      });
+    });
+  });
+});