зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1434376 - Add basic tests for window.promiseDocumentFlushed. r=Paolo
MozReview-Commit-ID: KmyqaupJRtw --HG-- extra : rebase_source : f7bc5281f194f28a7c0d36f6d6dfd87428c60cf1
This commit is contained in:
Родитель
24b3c1ade3
Коммит
93c1ada2a4
|
@ -48,6 +48,7 @@ skip-if = !e10s # this only makes sense with e10s-multi
|
|||
[browser_messagemanager_unload.js]
|
||||
[browser_pagehide_on_tab_close.js]
|
||||
skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
|
||||
[browser_promiseDocumentFlushed.js]
|
||||
[browser_state_notifications.js]
|
||||
skip-if = true # Bug 1271028
|
||||
[browser_use_counters.js]
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Dirties style and layout on the current browser window.
|
||||
*
|
||||
* @param {Number} Optional factor by which to modify the DOM. Useful for
|
||||
* when multiple calls to dirtyTheDOM may occur, and you need them
|
||||
* to dirty the DOM differently from one another. If you only need
|
||||
* to dirty the DOM once, this can be omitted.
|
||||
*/
|
||||
function dirtyStyleAndLayout(factor = 1) {
|
||||
gNavToolbox.style.padding = factor + "px";
|
||||
}
|
||||
|
||||
/**
|
||||
* Dirties style of the current browser window, but NOT layout.
|
||||
*/
|
||||
function dirtyStyle() {
|
||||
gNavToolbox.style.color = "red";
|
||||
}
|
||||
|
||||
const gWindowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
/**
|
||||
* Asserts that no style or layout flushes are required by the
|
||||
* current window.
|
||||
*/
|
||||
function assertNoFlushesRequired() {
|
||||
Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
|
||||
"No 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_LAYOUT),
|
||||
"Style and layout flushes are required.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(() => {});
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
registerCleanupFunction(cleanTheDOM);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that if the DOM is dirty, that promiseDocumentFlushed will
|
||||
* resolve once layout and style have been flushed.
|
||||
*/
|
||||
add_task(async function test_basic() {
|
||||
dirtyStyleAndLayout();
|
||||
assertFlushesRequired();
|
||||
|
||||
await window.promiseDocumentFlushed(() => {});
|
||||
assertNoFlushesRequired();
|
||||
|
||||
dirtyStyle();
|
||||
assertFlushesRequired();
|
||||
|
||||
await window.promiseDocumentFlushed(() => {});
|
||||
assertNoFlushesRequired();
|
||||
|
||||
// The DOM should be clean already, but we'll do this anyway to isolate
|
||||
// failures from other tests.
|
||||
await cleanTheDOM();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that values returned by the callback passed to promiseDocumentFlushed
|
||||
* get passed down through the Promise resolution.
|
||||
*/
|
||||
add_task(async function test_can_get_results_from_callback() {
|
||||
const NEW_PADDING = "2px";
|
||||
|
||||
gNavToolbox.style.padding = NEW_PADDING;
|
||||
|
||||
assertFlushesRequired();
|
||||
|
||||
let paddings = await window.promiseDocumentFlushed(() => {
|
||||
let style = window.getComputedStyle(gNavToolbox);
|
||||
return {
|
||||
left: style.paddingLeft,
|
||||
right: style.paddingRight,
|
||||
top: style.paddingTop,
|
||||
bottom: style.paddingBottom,
|
||||
};
|
||||
});
|
||||
|
||||
for (let prop in paddings) {
|
||||
Assert.equal(paddings[prop], NEW_PADDING,
|
||||
"Got expected padding");
|
||||
}
|
||||
|
||||
await cleanTheDOM();
|
||||
|
||||
gNavToolbox.style.padding = NEW_PADDING;
|
||||
|
||||
assertFlushesRequired();
|
||||
|
||||
let rect = await window.promiseDocumentFlushed(() => {
|
||||
let observer = {
|
||||
reflow() {
|
||||
Assert.ok(false, "A reflow should not have occurred.");
|
||||
},
|
||||
reflowInterruptible() {},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
|
||||
let toolboxRect = gNavToolbox.getBoundingClientRect();
|
||||
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
return toolboxRect;
|
||||
});
|
||||
|
||||
// The actual values of this rect aren't super important for
|
||||
// the purposes of this test - we just want to know that a valid
|
||||
// rect was returned, so checking for properties being greater than
|
||||
// 0 is sufficient.
|
||||
for (let property of ["width", "height"]) {
|
||||
Assert.ok(rect[property] > 0, `Rect property ${property} > 0 (${rect[property]})`);
|
||||
}
|
||||
|
||||
await cleanTheDOM();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that if promiseDocumentFlushed is requested on a window
|
||||
* that closes before it gets a chance to do a refresh driver
|
||||
* tick, the promiseDocumentFlushed Promise is still resolved, and
|
||||
* the callback is still called.
|
||||
*/
|
||||
add_task(async function test_resolved_in_window_close() {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
await win.promiseDocumentFlushed(() => {});
|
||||
|
||||
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell);
|
||||
docShell.contentViewer.pausePainting();
|
||||
|
||||
win.gNavToolbox.style.padding = "5px";
|
||||
|
||||
const EXPECTED = 1234;
|
||||
let promise = win.promiseDocumentFlushed(() => {
|
||||
// Despite the window not painting before closing, this
|
||||
// callback should be fired when the window gets torn
|
||||
// down and should stil be able to return a result.
|
||||
return EXPECTED;
|
||||
});
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
Assert.equal(await promise, EXPECTED);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that re-entering promiseDocumentFlushed is not possible
|
||||
* from within a promiseDocumentFlushed callback. Doing so will
|
||||
* result in the outer Promise rejecting with NS_ERROR_FAILURE.
|
||||
*/
|
||||
add_task(async function test_reentrancy() {
|
||||
dirtyStyleAndLayout();
|
||||
assertFlushesRequired();
|
||||
|
||||
let promise = window.promiseDocumentFlushed(() => {
|
||||
return window.promiseDocumentFlushed(() => {
|
||||
Assert.ok(false, "Should never run this.");
|
||||
});
|
||||
});
|
||||
|
||||
await Assert.rejects(promise, ex => ex.result == Cr.NS_ERROR_FAILURE);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the expected execution order of a series of promiseDocumentFlushed
|
||||
* calls, their callbacks, and the resolutions of their Promises.
|
||||
*
|
||||
* When multiple promiseDocumentFlushed callbacks are queued, the callbacks
|
||||
* should always been run first before any of the Promises are resolved.
|
||||
*
|
||||
* The callbacks should run in the order that they were queued in via
|
||||
* promiseDocumentFlushed. The Promise resolutions should similarly run
|
||||
* in the order that promiseDocumentFlushed was called in.
|
||||
*/
|
||||
add_task(async function test_execution_order() {
|
||||
let result = [];
|
||||
|
||||
dirtyStyleAndLayout(1);
|
||||
let promise1 = window.promiseDocumentFlushed(() => {
|
||||
result.push(0);
|
||||
}).then(() => {
|
||||
result.push(2);
|
||||
});
|
||||
|
||||
let promise2 = window.promiseDocumentFlushed(() => {
|
||||
result.push(1);
|
||||
}).then(() => {
|
||||
result.push(3);
|
||||
});
|
||||
|
||||
await Promise.all([promise1, promise2]);
|
||||
|
||||
Assert.equal(result.length, 4,
|
||||
"Should have run all callbacks and Promises.");
|
||||
|
||||
let promise3 = window.promiseDocumentFlushed(() => {
|
||||
result.push(4);
|
||||
}).then(() => {
|
||||
result.push(6);
|
||||
});
|
||||
|
||||
let promise4 = window.promiseDocumentFlushed(() => {
|
||||
result.push(5);
|
||||
}).then(() => {
|
||||
result.push(7);
|
||||
});
|
||||
|
||||
await Promise.all([promise3, promise4]);
|
||||
|
||||
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.");
|
||||
}
|
||||
});
|
Загрузка…
Ссылка в новой задаче