Skip to content

Commit

Permalink
[BFCache] Basic event tests + helpers
Browse files Browse the repository at this point in the history
Change-Id: I034f9f5376dc3f9f32ca0b936dbd06e458c9160b
  • Loading branch information
hiroshige-g authored and chromium-wpt-export-bot committed May 24, 2021
1 parent 3d3e869 commit ffbc29e
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 0 deletions.
18 changes: 18 additions & 0 deletions common/PrefixedLocalStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ PrefixedLocalStorage.prototype.setItem = function (baseKey, value) {
localStorage.setItem(this.prefixedKey(baseKey), value);
};

PrefixedLocalStorage.prototype.getItem = function (baseKey) {
return localStorage.getItem(this.prefixedKey(baseKey));
};

PrefixedLocalStorage.prototype.pushItem = function (baseKey, value) {
const array = this.getPushedItems(baseKey);
array.push(value);
this.setItem(baseKey, JSON.stringify(array));
};

PrefixedLocalStorage.prototype.getPushedItems = function (baseKey) {
const value = this.getItem(baseKey);
if (!value) {
return [];
}
return JSON.parse(value);
};

/**
* Listen for `storage` events pertaining to a particular key,
* prefixed with this object's prefix. Ignore when value is being set to null
Expand Down
12 changes: 12 additions & 0 deletions html/browsers/browsing-the-web/back-forward-cache/events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/PrefixedLocalStorage.js"></script>
<title>Events fired during BFCached back navigation (cross-site)</title>
<script>
const prefixedLocalStorage = new PrefixedLocalStorageTest();
fetch_tests_from_prefixed_local_storage(prefixedLocalStorage);
window.open(prefixedLocalStorage.url('resources/events.html'),
'_blank',
'noopener');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!DOCTYPE HTML>
<script>
window.onload = () => history.back();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<script src="/resources/testharness.js"></script>
<script src="/common/PrefixedLocalStorage.js"></script>
<script src="helper.sub.js"></script>
<script>
startRecordingEvents(['visibilitychange', 'pagehide', 'pageshow', 'load']);

const t = async_test('Events');
runTest(
t,
() => location.href = backUrl,
(isBFCached, observedEvents) => {
assert_implements_optional(isBFCached, 'Should be BFCached');
assert_array_equals(observedEvents, [
'window.load',
'window.pageshow',
'window.pagehide.persisted',
'document.visibilitychange.hidden',
'window.visibilitychange.hidden',
'document.visibilitychange.visible',
'window.visibilitychange.visible',
'window.pageshow.persisted']);
t.done();
}
);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// A helper script for simple A->B->A navigation scenarios like:
// 1. Initial navigation to `A.html`.
// 2. Navigation to `B.html`.
// 3. Back navigation to `A.html`, assuming `A.html` is (or is not) in BFCache.

// This script is loaded from `A.html`.

// `A.html` should be opened using `PrefixedLocalStorage.url()`, because
// `/common/PrefixedLocalStorage.js` is used to save states across navigations.

window.prefixedLocalStorage = new PrefixedLocalStorageResource({
close_on_cleanup: true
});

// Starts an A->B->A navigation test. This should be called on `A.html`.
// `onStart()` is called on the initial navigation, which is expected to
// initiate a navigation to a page (`B.html`) that will eventually back
// navigate to `A.html`.
// `onBackNavigated(isBFCached, observedEvents)` is called on back navigation.
// - `isBFCached` indicates whether the back navigation is from BFCache or not,
// based on events fired.
// - `observedEvents` is an array of event labels fired on `A.html`,
// if `startRecordingEvents()` is called.
function runTest(test, onStart, onBackNavigated) {
window.addEventListener('load', () => {
if (prefixedLocalStorage.getItem('state') === null) {
// Initial navigation.
prefixedLocalStorage.setItem('state', 'started');

// Call `onStart()` (and thus starting navigation) after this document
// is fully loaded.
// `step_timeout()` is used here because starting the navigation
// synchronously inside the window load event handler seems to
// cause back navigation to this page to fail on Firefox.
test.step_timeout(() => {
window.addEventListener('pageshow', (() => {
// Back navigation, from BFCache.
test.step(
onBackNavigated,
undefined,
true,
prefixedLocalStorage.getPushedItems('observedEvents'));
}));
test.step(onStart);
}, 0);
} else {
// Back navigation, not from BFCache.
test.step(
onBackNavigated,
undefined,
false,
prefixedLocalStorage.getPushedItems('observedEvents'));
}
});
}

// Records events fired on `window` and `document`, with names listed in
// `eventNames`.
// The recorded events are stored in localStorage and used later in the
// runTest() callback.
function startRecordingEvents(eventNames) {
window.testObservedEvents = [];
for (const eventName of eventNames) {
window.addEventListener(eventName, event => {
let result = eventName;
if (event.persisted) {
result += '.persisted';
}
if (eventName === 'visibilitychange') {
result += '.' + document.visibilityState;
}
prefixedLocalStorage.pushItem('observedEvents', 'window.' + result);
});
document.addEventListener(eventName, () => {
let result = eventName;
if (eventName === 'visibilitychange') {
result += '.' + document.visibilityState;
}
prefixedLocalStorage.pushItem('observedEvents', 'document.' + result);
});
}
}

const origin =
'http://{{hosts[alt][www]}}:{{ports[http][0]}}'; // cross-site

const backUrl =
origin +
'/html/browsers/browsing-the-web/back-forward-cache/resources/back.html';
41 changes: 41 additions & 0 deletions resources/testharness.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@
w.postMessage(message_arg, "*");
}
});
if (window.prefixedLocalStorage) {
window.prefixedLocalStorage.setItem('dispatched_messages.' + Math.random(),
JSON.stringify(message_arg));
}
};

WindowTestEnvironment.prototype._forEach_windows = function(callback) {
Expand Down Expand Up @@ -3168,6 +3172,25 @@
);
};

/*
* Constructs a RemoteContext that tracks tests from prefixed local storage.
* Test results from a window where
* - `window.prefixedLocalStorage` is defined using `/common/PrefixedLocalStorage.js`
* like `window.prefixedLocalStorage = new PrefixedLocalStorageResource();` and
* - testharness.js is loaded
* are received via `prefixedLocalStorage`.
*/
Tests.prototype.create_remote_prefixed_local_storage = function(prefixedLocalStorage) {
const channel = new MessageChannel();
// This receives the random keys prefixed by 'dispatched_messages' sent by the remote
// window's `WindowTestEnvironment.prototype._dispatch`.
prefixedLocalStorage.onSet('dispatched_messages', e => {
channel.port1.postMessage(JSON.parse(e.newValue));
});
channel.port2.start();
return new RemoteContext(null, channel.port2);
};

Tests.prototype.fetch_tests_from_worker = function(worker) {
if (this.phase >= this.phases.COMPLETE) {
return;
Expand Down Expand Up @@ -3196,6 +3219,24 @@
}
expose(fetch_tests_from_window, 'fetch_tests_from_window');


Tests.prototype.fetch_tests_from_prefixed_local_storage = function(prefixedLocalStorage) {
if (this.phase >= this.phases.COMPLETE) {
return;
}

var remoteContext = this.create_remote_prefixed_local_storage(prefixedLocalStorage);
this.pending_remotes.push(remoteContext);
return remoteContext.done.then(() => {
prefixedLocalStorage.cleanup();
});
};

function fetch_tests_from_prefixed_local_storage(prefixedLocalStorage) {
return tests.fetch_tests_from_prefixed_local_storage(prefixedLocalStorage);
}
expose(fetch_tests_from_prefixed_local_storage, 'fetch_tests_from_prefixed_local_storage');

function timeout() {
if (tests.timeout_length === null) {
tests.timeout();
Expand Down

0 comments on commit ffbc29e

Please sign in to comment.