Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /service-workers/service-worker/fetch-waits-for-activate.https.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<title>Service Worker: Fetch Event Waits for Activate Event</title>
<meta name=timeout content=long>
<script src="/resources/testharness.js"></script>
<script src="resources/testharness-helpers.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
const worker_url = 'resources/fetch-waits-for-activate-worker.js';
const normalized_worker_url = normalizeURL(worker_url);
const worker_scope = 'resources/fetch-waits-for-activate/';
// Resolves with the Service Worker's registration once it's reached the
// "activating" state. (The Service Worker should remain "activating" until
// explicitly told advance to the "activated" state).
async function registerAndWaitForActivating(t) {
const registration = await service_worker_unregister_and_register(
t, worker_url, worker_scope);
t.add_cleanup(() => service_worker_unregister(t, worker_scope));
await wait_for_state(t, registration.installing, 'activating');
return registration;
}
// Attempts to ensure that the "Handle Fetch" algorithm has reached the step
//
// "If activeWorker’s state is "activating", wait for activeWorker’s state to
// become "activated"."
//
// by waiting for some time to pass.
//
// WARNING: whether the algorithm has reached that step isn't directly
// observable, so this is best effort and can race. Note that this can only
// result in false positives (where the algorithm hasn't reached that step yet
// and any functional events haven't actually been handled by the Service
// Worker).
async function ensureFunctionalEventsAreWaiting(registration) {
await (new Promise(resolve => { setTimeout(resolve, 1000); }));
assert_equals(registration.active.scriptURL, normalized_worker_url,
'active worker should be present');
assert_equals(registration.active.state, 'activating',
'active worker should be in activating state');
}
promise_test(async t => {
const registration = await registerAndWaitForActivating(t);
let frame = null;
t.add_cleanup(() => {
if (frame) {
frame.remove();
}
});
// This should block until we message the worker to tell it to complete
// the activate event.
const frameLoadPromise = with_iframe(worker_scope).then(function(f) {
frame = f;
});
await ensureFunctionalEventsAreWaiting(registration);
assert_equals(frame, null, 'frame should not be loaded');
registration.active.postMessage('ACTIVATE');
await frameLoadPromise;
assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalized_worker_url,
'frame should now be loaded and controlled');
assert_equals(registration.active.state, 'activated',
'active worker should be in activated state');
}, 'Navigation fetch events should wait for the activate event to complete.');
promise_test(async t => {
const frame = await with_iframe(worker_scope);
t.add_cleanup(() => { frame.remove(); });
const registration = await registerAndWaitForActivating(t);
// Make the Service Worker control the frame so the frame can perform an
// intercepted fetch.
await (new Promise(resolve => {
navigator.serviceWorker.onmessage = e => {
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalized_worker_url, 'frame should be controlled');
resolve();
};
registration.active.postMessage('CLAIM');
}));
const fetch_url = `${worker_scope}non/existent/path`;
const expected_fetch_result = 'Hello world';
let fetch_promise_settled = false;
// This should block until we message the worker to tell it to complete
// the activate event.
const fetchPromise = frame.contentWindow.fetch(fetch_url, {
method: 'POST',
body: expected_fetch_result,
}).then(response => {
fetch_promise_settled = true;
return response;
});
await ensureFunctionalEventsAreWaiting(registration);
assert_false(fetch_promise_settled,
"fetch()-ing a Service Worker-controlled scope shouldn't have " +
"settled yet");
registration.active.postMessage('ACTIVATE');
const response = await fetchPromise;
assert_equals(await response.text(), expected_fetch_result,
"Service Worker should have responded to request to" +
fetch_url)
assert_equals(registration.active.state, 'activated',
'active worker should be in activated state');
}, 'Subresource fetch events should wait for the activate event to complete.');
</script>
</body>