Bug 1597253 - [remote] Implement Page.lifecycleEvent. r=remote-protocol-reviewers,maja_zf

Differential Revision: https://phabricator.services.mozilla.com/D53827

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Henrik Skupin 2019-11-19 22:08:05 +00:00
Родитель 88538854d7
Коммит e02cc0bfe1
4 изменённых файлов: 197 добавлений и 1 удалений

Просмотреть файл

@ -157,8 +157,16 @@ class Page extends ContentProcessDomain {
});
}
emitLifecycleEvent(frameId, loaderId, name, timestamp) {
if (this.lifecycleEnabled) {
this.emit("Page.lifecycleEvent", { frameId, loaderId, name, timestamp });
}
}
handleEvent({ type, target }) {
if (target.defaultView != this.content) {
const isFrame = target.defaultView != this.content;
if (isFrame) {
// Ignore iframes for now
return;
}
@ -170,18 +178,44 @@ class Page extends ContentProcessDomain {
switch (type) {
case "DOMContentLoaded":
this.emit("Page.domContentEventFired", { timestamp });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"DOMContentLoaded",
timestamp
);
}
break;
case "pagehide":
// Maybe better to bound to "unload" once we can register for this event
this.emit("Page.frameStartedLoading", { frameId });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"init",
timestamp
);
}
break;
case "pageshow":
this.emit("Page.loadEventFired", { timestamp });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"load",
timestamp
);
}
// XXX this should most likely be sent differently
this.emit("Page.navigatedWithinDocument", { frameId, url });
this.emit("Page.frameStoppedLoading", { frameId });
break;
}
}

Просмотреть файл

@ -178,3 +178,12 @@ function getContentProperty(prop) {
_prop => content[_prop]
);
}
/**
* Return a new promise, which resolves after ms have been elapsed
*/
function timeoutPromise(ms) {
return new Promise(resolve => {
window.setTimeout(resolve, ms);
});
}

Просмотреть файл

@ -14,5 +14,6 @@ support-files =
[browser_javascriptDialog_confirm.js]
[browser_javascriptDialog_otherTarget.js]
[browser_javascriptDialog_prompt.js]
[browser_lifecycleEvent.js]
[browser_reload.js]
[browser_runtimeEvents.js]

Просмотреть файл

@ -0,0 +1,152 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the Page lifecycle events
const DOC = toDataURL("default-test-page");
add_task(async function noInitialEvents({ Page }) {
await Page.enable();
info("Page domain has been enabled");
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events are not enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId, timeout: 1000 });
});
add_task(async function noEventsAfterDisable({ Page }) {
await Page.enable();
info("Page domain has been enabled");
await Page.setLifecycleEventsEnabled({ enabled: true });
await Page.setLifecycleEventsEnabled({ enabled: false });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events are not enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId, timeout: 1000 });
});
add_task(async function navigateEvents({ Page }) {
await Page.enable();
info("Page domain has been enabled");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
add_task(async function navigateEventsOnReload({ Page }) {
await Page.enable();
info("Page domain has been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("Initial page has been loaded");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
pageLoaded = Page.loadEventFired();
await Page.reload();
await pageLoaded;
info("The page has been reloaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
add_task(async function navigateEventsOnNavigateToSameURL({ Page }) {
await Page.enable();
info("Page domain has been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("Initial page has been loaded");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
pageLoaded = Page.loadEventFired();
await Page.navigate({ url: DOC });
await pageLoaded;
info("The page has been reloaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
function recordPromises(Page, names) {
return new Promise(resolve => {
const resolutions = new Map();
const unsubscribe = Page.lifecycleEvent(event => {
info(`Received Page.lifecycleEvent for ${event.name}`);
resolutions.set(event.name, event);
if (event.name == names[names.length - 1]) {
unsubscribe();
resolve(resolutions);
}
});
});
}
async function assertNavigationLifecycleEvents({ promise, frameId, timeout }) {
// Wait for all the promises to resolve
const promises = [promise];
if (timeout) {
promises.push(timeoutPromise(timeout));
}
const resolutions = await Promise.race(promises);
if (timeout) {
is(resolutions, undefined, "No lifecycle events have been recorded");
return;
}
// Assert the order in which they resolved
const expectedResolutions = ["init", "DOMContentLoaded", "load"];
Assert.deepEqual(
[...resolutions.keys()],
expectedResolutions,
"Received various lifecycle events in the expected order"
);
// Now assert the data exposed by each of these events
const frameStartedLoading = resolutions.get("init");
is(frameStartedLoading.frameId, frameId, "init frameId is the same one");
const DOMContentLoaded = resolutions.get("DOMContentLoaded");
is(
DOMContentLoaded.frameId,
frameId,
"DOMContentLoaded frameId is the same one"
);
const load = resolutions.get("load");
is(load.frameId, frameId, "load frameId is the same one");
}