Skip to content

Commit

Permalink
Prerender: upstream wpt_internal/prerender/visibility-state.html
Browse files Browse the repository at this point in the history
This behavior is described in
https://jeremyroman.github.io/alternate-loading-modes/prerendering.html#interaction-with-visibility-state

Bug: 1253158
Change-Id: I70c36276c7e0a3c63d48b3adb4d8f8c857a83152
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3229327
Commit-Queue: Lingqi Chi <[email protected]>
Reviewed-by: Hiroki Nakagawa <[email protected]>
Cr-Commit-Position: refs/heads/main@{#932962}
  • Loading branch information
Clqsin45 authored and chromium-wpt-export-bot committed Oct 19, 2021
1 parent 6f59a0c commit bcd6e91
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 0 deletions.
1 change: 1 addition & 0 deletions lint.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ SET TIMEOUT: resources/testharness.js
SET TIMEOUT: scheduler/tentative/current-task-signal-async-abort.any.js
SET TIMEOUT: scheduler/tentative/current-task-signal-async-priority.any.js
SET TIMEOUT: speculation-rules/prerender/resources/activation-start.html
SET TIMEOUT: speculation-rules/prerender/resources/deferred-promise-utils.js
SET TIMEOUT: speculation-rules/prerender/resources/utils.js

# setTimeout use in reftests
Expand Down
72 changes: 72 additions & 0 deletions speculation-rules/prerender/resources/deferred-promise-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* 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_ = [];
}

// 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 BroadcastChannel('test-channel');
// Send the observed events back to the main test page.
testChannel.postMessage(this.eventsSeen_);
testChannel.close();
window.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 BroadcastChannel('prerender-channel');
// Inform the initiator page that this page is ready to be activated.
prerenderChannel.postMessage('readyToActivate');
prerenderChannel.close();
}, 0);
}
}
32 changes: 32 additions & 0 deletions speculation-rules/prerender/resources/visibility-state-check.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="utils.js"></script>
<script src="deferred-promise-utils.js"></script>
<script>
const params = new URLSearchParams(location.search);

// The main test page (visibility-state.html) loads the initiator page,
// then the initiator page will prerender itself with the `prerendering`
// parameter.
const isPrerendering = params.has('prerendering');

if (!isPrerendering) {
loadInitiatorPage();
} else {
const prerenderEventCollector = new PrerenderEventCollector();
const promise = new Promise((resolve) => {
prerenderEventCollector.addEvent(
'Initial visibilityState: ' + document.visibilityState);

document.addEventListener('prerenderingchange', () => {
prerenderEventCollector.addEvent(
'visibilityState after prerenderingchange: ' +
document.visibilityState);
resolve();
});
});
prerenderEventCollector.start(promise, 'visibilityState check');
}

</script>
53 changes: 53 additions & 0 deletions speculation-rules/prerender/visibility-state.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<title>visibilityState must be updated after prerendering</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/utils.js"></script>
<body>
<script>

setup(() => assertSpeculationRulesIsSupported());

promise_test(async t => {
const bc = new BroadcastChannel('test-channel');

const gotMessage = new Promise(resolve => {
bc.addEventListener('message', e => {
resolve(e.data);
}, {
once: true
});
});
const url = `resources/visibility-state-check.html`;
window.open(url, '_blank', 'noopener');

const result = await gotMessage;
const expected = [
{
event: 'Initial visibilityState: hidden',
prerendering: true
},
{
event: 'started waiting visibilityState check',
prerendering: true
},
{
event: 'visibilityState after prerenderingchange: visible',
prerendering: false
},
{
event: 'finished waiting visibilityState check',
prerendering: false
}
];
assert_equals(result.length, expected.length);
for (let i = 0; i < result.length; i++) {
assert_equals(result[i].event, expected[i].event, `event${i}`);
assert_equals(result[i].prerendering, expected[i].prerendering,
`prerendering${i}`);
}
}, 'The visibilityState must be updated after prerendering.');

</script>
</body>

0 comments on commit bcd6e91

Please sign in to comment.