blob: 1ffb709db575f60abb4175550a3365806c985d93 [file] [edit]
<!DOCTYPE html>
<title>A prerender-until-script host is upgraded to a full prerender when a
matching prerender speculation rule is added for the same URL</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="../resources/utils.js"></script>
<body>
<script>
setup(() => assertSpeculationRulesIsSupported('prerender'));
const UPGRADE_TIMEOUT_MS = 30_000;
promise_test(async t => {
/*
Workflow:
1. The initiator (pus-upgrade-initiator-template.html) adds a
`prerender_until_script` rule for the target URL. A
prerender-until-script host starts loading the page with JavaScript
execution paused.
2. The prerendered page (pus-upgrade-page-template.html) starts loading.
Its async `<script src="...">` request confirms that the PUS host exists
before the upgrade rule is added. Fetching is allowed while script
execution is paused.
3. The server responds to the initiator's pending "pus-loaded" fetch.
4. The initiator then adds a regular `prerender` speculation rule for the
SAME URL. This triggers the upgrade: the existing prerender-until-
script host becomes a full prerender host, and its paused JavaScript
resumes.
5. The (previously paused) inline `<script>` on the prerendered page now
runs, captures `document.prerendering`, and posts the value back via
`PrerenderChannel`. The page also signals the server via the "js-ran"
stash key so the initiator can activate.
6. We assert the page reported `document.prerendering === true`, which
proves the inline script ran during prerendering (before activation),
i.e. the prerender-until-script host was upgraded.
*/
const uid = token();
const jsRanUid = token();
const channel = new PrerenderChannel('test-channel', uid);
t.add_cleanup(() => channel.close());
const gotMessage = new Promise((resolve, reject) => {
channel.addEventListener('message', e => {
// Surface initiator failures directly instead of reporting a misleading
// mismatch against the expected prerendering-state message.
if (typeof e.data === 'string' &&
e.data.startsWith('Initiator failure: ')) {
reject(new Error(e.data));
return;
}
resolve(e.data);
}, { once: true });
});
const url =
`resources/pus-upgrade-handler.py?type=main&uid=${uid}` +
`&js_uid=${jsRanUid}`;
window.open(url, '_blank', 'noopener');
// Fail with an upgrade-specific diagnostic before the harness times out.
const timedOut = new Promise((_, reject) => {
t.step_timeout(() => {
reject(new Error(
'Timed out waiting for the prerendered page to report its ' +
'`document.prerendering` value. The prerender-until-script ' +
'host was likely not upgraded, so its previously paused inline ' +
'JavaScript never ran.'));
}, UPGRADE_TIMEOUT_MS);
});
const result = await Promise.race([gotMessage, timedOut]);
assert_equals(
result,
'prerendering state when executing JS: true',
'inline JS on the upgraded prerender-until-script page must execute ' +
'during prerendering (before activation), proving the prerender-' +
'until-script host was upgraded to a full prerender host by the ' +
'matching prerender rule');
}, 'Adding a prerender rule for a URL that already has a prerender-until-' +
'script rule upgrades the existing prerender-until-script host and ' +
'resumes JavaScript execution during prerendering.');
</script>
</body>