Source code

Revision control

Copy as Markdown

Other Tools

/**
* This file co-works with a html file and utils.js to test a promise that
* should be deferred during prerendering.
*
* Usage example:
* Suppose the html is "prerender-promise-test.html"
* On prerendering page, prerender-promise-test.html?prerendering:
* const prerenderEventCollector = new PrerenderEventCollector();
* const promise = {a promise that should be deferred during prerendering};
* prerenderEventCollector.start(promise, {promise name});
*
* On the initiator page, prerender-promise-test.html:
* execute
* `loadInitiatorPage();`
*/
// Collects events that happen relevant to a prerendering page.
// An event is added when:
// 1. start() is called.
// 2. a prerenderingchange event is dispatched on this document.
// 3. the promise passed to start() is resolved.
// 4. addEvent() is called manually.
class PrerenderEventCollector {
constructor() {
this.eventsSeen_ = [];
new PrerenderChannel('close').addEventListener('message', () => {
window.close();
});
}
// Adds an event to `eventsSeen_` along with the prerendering state of the
// page.
addEvent(eventMessage) {
this.eventsSeen_.push(
{event: eventMessage, prerendering: document.prerendering});
}
// Starts collecting events until the promise resolves. Triggers activation by
// telling the initiator page that it is ready for activation.
async start(promise, promiseName) {
assert_true(document.prerendering);
this.addEvent(`started waiting ${promiseName}`);
promise
.then(
() => {
this.addEvent(`finished waiting ${promiseName}`);
},
(error) => {
if (error instanceof Error)
error = error.name;
this.addEvent(`${promiseName} rejected: ${error}`);
})
.finally(() => {
// Used to communicate with the main test page.
const testChannel = new PrerenderChannel('test-channel');
// Send the observed events back to the main test page.
testChannel.postMessage(this.eventsSeen_);
testChannel.close();
});
document.addEventListener('prerenderingchange', () => {
this.addEvent('prerendering change');
});
// Post a task to give the implementation a chance to fail in case it
// resolves a promise without waiting for activation.
setTimeout(() => {
// Used to communicate with the initiator page.
const prerenderChannel = new PrerenderChannel('prerender-channel');
// Inform the initiator page that this page is ready to be activated.
prerenderChannel.postMessage('readyToActivate');
prerenderChannel.close();
}, 0);
}
}