Skip to content

Commit

Permalink
Prerender: Clean up arguments of create_prerendered_page() used in WPTs
Browse files Browse the repository at this point in the history
This CL cleans up create_prerendered_page() helper used in WPTs to
trigger prerendering. This is a preparation for adding No-Vary-Search
(NVS) header WPTs with speculation rules prerendering.

This CL merges `opt` and `init_opt` arguments on
create_prerendered_page() into one `params` Object argument. This object
contains `initiator`, `prerendering`, and `activating` keys, and their
values are URLSearchParams. These search params are attached to
initiator navigation, prerendering navigation, and activating navigation
respectively. In this CL, `activating` is actually not used, but this
will be necessary for NVS header WPTs to be added by follow-up CLs so
that the tests can specify varied search params.

This CL also repurposes `opt` argument for controlling behavior of the
helper. Before this CL, the helper checked `init_opt.prefetch` to decide
if prefetch should be triggered before prerendering. This was confusing
as `init_opt` was also used for specifying search params of the
initiator page. After this CL, `opt` is specialized for controlling such
behavior and `prefetch` is specified there. This should be less
confusing.

Change-Id: I158724c6bf996cfcc03a353133267809ea1e4999
Bug: 340928303
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5550431
Reviewed-by: Domenic Denicola <[email protected]>
Commit-Queue: Hiroki Nakagawa <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1303551}
  • Loading branch information
nhiroki authored and chromium-wpt-export-bot committed May 21, 2024
1 parent a05ac39 commit 495da8a
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 40 deletions.
5 changes: 2 additions & 3 deletions speculation-rules/prerender/fetch-blob.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
setup(() => assertSpeculationRulesIsSupported());

promise_test(async t => {
const opt = {};
const init_opt = {};
const rule_extras = {'target_hint': getTargetHint()};
const {exec} = await create_prerendered_page(t, opt, init_opt, rule_extras);
const {exec} = await create_prerendered_page(
t, undefined, undefined, rule_extras);
const result = await exec(async () => {
const blob = await (await fetch('cache.txt')).blob();
const reader = new FileReader();
Expand Down
5 changes: 2 additions & 3 deletions speculation-rules/prerender/local-storage.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@
}, { once: true });
});

const opt = {};
const init_opt = {};
const rule_extras = {'target_hint': getTargetHint()};

window.localStorage.setItem('initial', uid1);
const {exec} = await create_prerendered_page(t, opt, init_opt, rule_extras);
const {exec} = await create_prerendered_page(
t, undefined, undefined, rule_extras);
const result = await exec(uid2 => {
window.localStorage.setItem('prerender', uid2);
return window.localStorage.getItem('initial');
Expand Down
87 changes: 59 additions & 28 deletions speculation-rules/prerender/resources/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,20 @@ function createFrame(url) {
});
}

// `opt` provides additional query params for the prerendered URL.
// `init_opt` provides additional query params for the page that triggers
// the prerender. If `init_opt.prefetch` is set to true, prefetch is also
// triggered before the prerendering.
// `rule_extras` provides additional parameters for the speculation rule used
// to trigger prerendering.
async function create_prerendered_page(t, opt = {}, init_opt = {}, rule_extras = {}) {
/**
* Creates a prerendered page.
* @param {Object} params - Additional query params for navigations.
* @param {URLSearchParams} [params.initiator] - For the page that triggers
* prerendering.
* @param {URLSearchParams} [params.prerendering] - For prerendering navigation.
* @param {URLSearchParams} [params.activating] - For activating navigation.
* @param {Object} opt - Controls creation of prerendered pages.
* @param {boolean} [opt.prefetch] - When this is true, prefetch is also
* triggered before prerendering.
* @param {Object} rule_extras - Additional params for the speculation rule used
* to trigger prerendering.
*/
async function create_prerendered_page(t, params = {}, opt = {}, rule_extras = {}) {
const baseUrl = '/speculation-rules/prerender/resources/exec.py';
const init_uuid = token();
const prerender_uuid = token();
Expand All @@ -213,44 +220,68 @@ async function create_prerendered_page(t, opt = {}, init_opt = {}, rule_extras =

const init_params = new URLSearchParams();
init_params.set('uuid', init_uuid);
for (const p in init_opt)
init_params.set(p, init_opt[p]);
if ('initiator' in params) {
for (const [key, value] of params.initiator.entries()) {
init_params.set(key, value);
}
}
window.open(`${baseUrl}?${init_params.toString()}&init`, '_blank', 'noopener');

const params = new URLSearchParams();
params.set('uuid', prerender_uuid);
params.set('discard_uuid', discard_uuid);
for (const p in opt)
params.set(p, opt[p]);
const url = `${baseUrl}?${params.toString()}`;
// Construct a URL for prerendering.
const prerendering_params = new URLSearchParams();
prerendering_params.set('uuid', prerender_uuid);
prerendering_params.set('discard_uuid', discard_uuid);
if ('prerendering' in params) {
for (const [key, value] of params.prerendering.entries()) {
prerendering_params.set(key, value);
}
}
const prerendering_url = `${baseUrl}?${prerendering_params.toString()}`;

// Construct a URL for activation. If `params.activating` is provided, the
// URL is constructed with the params. Otherwise, the URL is the same as
// `prerendering_url`.
const activating_url = (() => {
if ('activating' in params) {
const activating_params = new URLSearchParams();
activating_params.set('uuid', prerender_uuid);
activating_params.set('discard_uuid', discard_uuid);
for (const [key, value] of params.activating.entries()) {
activating_params.set(key, value);
}
return `${baseUrl}?${activating_params.toString()}`;
} else {
return prerendering_url;
}
})();

if (init_opt.prefetch) {
await init_remote.execute_script((url, rule_extras) => {
if (opt.prefetch) {
await init_remote.execute_script((prerendering_url, rule_extras) => {
const a = document.createElement('a');
a.href = url;
a.href = prerendering_url;
a.innerText = 'Activate (prefetch)';
document.body.appendChild(a);
const rules = document.createElement('script');
rules.type = "speculationrules";
rules.text = JSON.stringify(
{prefetch: [{source: 'list', urls: [url], ...rule_extras}]});
{prefetch: [{source: 'list', urls: [prerendering_url], ...rule_extras}]});
document.head.appendChild(rules);
}, [url, rule_extras]);
}, [prerendering_url, rule_extras]);

// Wait for the completion of the prefetch.
await new Promise(resolve => t.step_timeout(resolve, 3000));
}

await init_remote.execute_script((url, rule_extras) => {
await init_remote.execute_script((prerendering_url, rule_extras) => {
const a = document.createElement('a');
a.href = url;
a.href = prerendering_url;
a.innerText = 'Activate';
document.body.appendChild(a);
const rules = document.createElement('script');
rules.type = "speculationrules";
rules.text = JSON.stringify({prerender: [{source: 'list', urls: [url], ...rule_extras}]});
rules.text = JSON.stringify({prerender: [{source: 'list', urls: [prerendering_url], ...rule_extras}]});
document.head.appendChild(rules);
}, [url, rule_extras]);
}, [prerendering_url, rule_extras]);

await Promise.any([
prerender_remote.execute_script(() => {
Expand Down Expand Up @@ -278,9 +309,9 @@ async function create_prerendered_page(t, opt = {}, init_opt = {}, rule_extras =

const discarded = discard_remote.execute_script(() => Promise.resolve('discarded'));

init_remote.execute_script(url => {
location.href = url;
}, [url]);
init_remote.execute_script(activating_url => {
location.href = activating_url;
}, [activating_url]);
return Promise.any([prerendering, discarded]);
}

Expand All @@ -292,7 +323,7 @@ async function create_prerendered_page(t, opt = {}, init_opt = {}, rule_extras =

// Get the number of network requests for the prerendered page URL.
async function getNetworkRequestCount() {
return await (await fetch(url + '&get-fetch-count')).text();
return await (await fetch(prerendering_url + '&get-fetch-count')).text();
}

return {
Expand Down
8 changes: 5 additions & 3 deletions speculation-rules/prerender/response-code-non-successful.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
setup(() => assertSpeculationRulesIsSupported());

const params = new URLSearchParams(window.location.search);
const code = params.get('code');

promise_test(async t => {
const {exec, tryToActivate} = await create_prerendered_page(t, {code});
// Pass the `code` search param so that a prerendered page is served with the
// response code.
const {exec, tryToActivate} =
await create_prerendered_page(t, {'prerendering': params});
const result = await tryToActivate();
assert_equals(result, 'discarded');
},`Responses with code ${code} should be discarded`);
},`Responses with code ${params.get('code')} should be discarded`);
</script>
8 changes: 5 additions & 3 deletions speculation-rules/prerender/response-code-successful.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
setup(() => assertSpeculationRulesIsSupported());

const params = new URLSearchParams(window.location.search);
const code = params.get('code');

promise_test(async t => {
const {exec, tryToActivate} = await create_prerendered_page(t, {code});
// Pass the `code` search param so that a prerendered page is served with the
// response code.
const {exec, tryToActivate} =
await create_prerendered_page(t, {'prerendering': params});
const result = await tryToActivate();
assert_equals(result, 'activated');
},`Responses with code ${code} should be activated`);
},`Responses with code ${params.get('code')} should be activated`);
</script>

0 comments on commit 495da8a

Please sign in to comment.