Skip to content

Commit

Permalink
Prerender: Upstream session storage tests to WPT
Browse files Browse the repository at this point in the history
The test file is marked as "tentative" as the clone-and-swap flow is not
standardized yet. See comments in session-storage.tentative.html for
details.

Bug: 40199066
Change-Id: Ibe14540b26695cbb4c887fa7df1eb5bcbad9ddc9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5582794
Reviewed-by: Taiyo Mizuhashi <[email protected]>
Commit-Queue: Taiyo Mizuhashi <[email protected]>
Auto-Submit: Hiroki Nakagawa <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1307932}
  • Loading branch information
nhiroki authored and chromium-wpt-export-bot committed May 30, 2024
1 parent c8838c8 commit 5930e38
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="session-storage-utils.js"></script>
<script>
const params = new URLSearchParams(location.search);
const uid = params.get('uid');

RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
if (!isPrerendering) {
sessionStorage.setItem('set by initiator page', '1');
startPrerendering(url);
} else {
assert_equals(
getSessionStorageKeys(),
'set by initiator page',
'The session storage item set by the initiator page must be carried' +
' over to the prerendering page.');
done();
}
}, uid);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="session-storage-utils.js"></script>
<script>
const params = new URLSearchParams(location.search);
const uid = params.get('uid');

RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
if (!isPrerendering) {
startPrerendering(url);
// Wait for the message from the prerendering page.
assert_equals(
await getNextMessage(prerenderChannel),
'From prerendering page 1')

// Add an item to the session storage.
sessionStorage.setItem('set by initiator page', '1');

// Send the message to the prerendering page.
prerenderChannel.postMessage('From initiator page');

} else {
sessionStorage.setItem('set by prerendering page', '1');

// Send the message to the initiator page.
prerenderChannel.postMessage('From prerendering page 1');

// Wait for the message from the initiator page.
assert_equals(
await getNextMessage(prerenderChannel),
'From initiator page');

assert_equals(
getSessionStorageKeys(),
'set by prerendering page',
'The session storage item added by the initiator page after the ' +
'prerendering page accessed the session storage must not be visible ' +
'in the prerendering page.');
done();
}
}, uid);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="session-storage-utils.js"></script>
<script>
const params = new URLSearchParams(location.search);
const uid = params.get('uid');

RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
if (!isPrerendering) {
startPrerendering(url);

// Wait for the message from the prerendering page.
assert_equals(
await getNextMessage(prerenderChannel),
'From prerendering page')

assert_equals(
getSessionStorageKeys(),
'',
'The session storage item set by the prerendering page must not be ' +
'visible in the initiator page.');

done();
} else {
sessionStorage.setItem('set by prerendering page', '1');

assert_equals(
getSessionStorageKeys(),
'set by prerendering page',
'The session storage item must have been added by the prerendering' +
' page.');
// Send the message to the initiator page.
prerenderChannel.postMessage('From prerendering page');
}
}, uid);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="session-storage-utils.js"></script>
<script>
const params = new URLSearchParams(location.search);
const uid = params.get('uid');

RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
if (!isPrerendering) {
sessionStorage.setItem('set by initiator page 1', '1');
startPrerendering(url);
// Wait for the message from the prerendering page.
assert_equals(
await getNextMessage(prerenderChannel),
'From prerendering page 1')

// Add an item to the session storage.
sessionStorage.setItem('set by initiator page 2', '1');

// Send the message to the prerendering page.
prerenderChannel.postMessage('From initiator page');

// Wait for the message from the prerendering page.
assert_equals(
await getNextMessage(prerenderChannel),
'From prerendering page 2')

// Register beforeunload event handler which adds a new item in the
// session storage.
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('set by initiator page 3', '1');
});

// Navigate to the prerenderered page.
window.location = url;
} else {
const prerenderingchangePromise =
new Promise(resolve => {
document.addEventListener('prerenderingchange', () => {
sessionStorage.setItem('set by activated page', 1);
resolve();
});
});

sessionStorage.setItem('set by prerendering page', '1');

// Send the message to the initiator page.
prerenderChannel.postMessage('From prerendering page 1');

// Wait for the message from the initiator page.
assert_equals(await getNextMessage(prerenderChannel),
'From initiator page');

assert_equals(
getSessionStorageKeys(),
'set by initiator page 1, set by prerendering page',
'The session storage item added by the initiator page after ' +
'starting prerendering must not be visible in the prerendering ' +
'page.');

// Send the message to the initiator page.
prerenderChannel.postMessage('From prerendering page 2');

// Wait until activated.
await prerenderingchangePromise;

assert_equals(
getSessionStorageKeys(),
'set by activated page, set by initiator page 1, ' +
'set by initiator page 2, set by initiator page 3',
'The all session storage items added by the initiator page and ' +
'the item added by the activated page must be visible in the ' +
'activated page.');
done();
}
}, uid);
</script>
72 changes: 72 additions & 0 deletions speculation-rules/prerender/resources/session-storage-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
function getSessionStorageKeys() {
let keys = [];
let txt = '';
for (let i = 0; i < sessionStorage.length; ++i) {
keys.push(sessionStorage.key(i));
}
keys.sort();
keys.forEach((key) => {
if (txt.length) {
txt += ', ';
}
txt += key;
});
return txt;
}

function getNextMessage(channel) {
return new Promise(resolve => {
channel.addEventListener('message', e => {
resolve(e.data);
}, {once: true});
});
}

// session_storage_test() is a utility function for running session storage
// related tests that open a initiator page using window.open().
function session_storage_test(testPath, uid) {
promise_test(async t => {
const testChannel = new PrerenderChannel('test-channel', uid);
t.add_cleanup(() => {
testChannel.close();
});
const gotMessage = getNextMessage(testChannel);
const url = 'resources/' + testPath + '?uid=' + uid;
window.open(url, '_blank', 'noopener');
assert_equals(await gotMessage, 'Done');
}, testPath);
}

// RunSessionStorageTest() is a utility function for running session storage
// related tests that requires coordinated code execution on both the initiator
// page and the prerendering page. The passed |func| function will be called
// with the following arguments:
// - isPrerendering: Whether the |func| is called in the prerendering page.
// - url: The URL of the prerendering page. |func| should call
// startPrerendering(url) when |isPrerendering| is false to start the
// prerendering.
// - channel: A PrerenderChannel which can be used to coordinate the code
// execution on the initiator page and the prerendering page.
// - done: A function that should be called when the test completes
// successfully.
async function RunSessionStorageTest(func, uid) {
const url = new URL(document.URL);
url.searchParams.set('prerendering', '');
const params = new URLSearchParams(location.search);
// The main test page loads the initiator page, then the initiator page will
// prerender itself with the `prerendering` parameter.
const isPrerendering = params.has('prerendering');
const prerenderChannel = new PrerenderChannel('prerender-channel', uid);
const testChannel = new PrerenderChannel('test-channel', uid);
window.addEventListener('pagehide', () => {
prerenderChannel.close();
testChannel.close();
});
try {
await func(isPrerendering, url.toString(), prerenderChannel, () => {
testChannel.postMessage('Done');
})
} catch (e) {
testChannel.postMessage(e.toString());
}
}
30 changes: 30 additions & 0 deletions speculation-rules/prerender/session-storage.tentative.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<!--
This file is marked as "tentative" until:
* The "clone & swap" mechanism for session storage in prerendering described in
https://github.com/whatwg/storage/issues/119 is added to the specification.
-->
<title>Same-origin prerendering can access sessionStorage</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="resources/utils.js"></script>
<script src="resources/session-storage-utils.js"></script>
<body>
<script>
const uid = token();

session_storage_test(
'session-storage-carry-over-to-prerender-page.html', uid);

session_storage_test(
'session-storage-no-leak-to-initiator-page.html', uid);

session_storage_test(
'session-storage-isolated-while-prerendering.html', uid);

session_storage_test(
'session-storage-swap-after-activate.html', uid);
</script>
</body>

0 comments on commit 5930e38

Please sign in to comment.