-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WPT] BFCache: service worker clients
This CL adds service worker tests for BFCache: - navigator.serviceWorker.controller - Fetch interception - Clients.claim() - Clients.matchAll() and - unregister(). Expected behavior: - Controlled pages should remain controlled after restored from BFCache, i.e. navigator.serviceWorker.controller should remain non-null and fetch should be intercepted. - Clients.claim() should evict pages that would be affected from BFCache. - Clients.matchAll() shouldn't list pages in BFCache. - unregister() should evict controlled pages from BFCache. Failing tests: - service-worker-clients-claim.https.html: On Safari/Firefox, Clients.claim() doesn't evict pages from BFCache. - service-worker-controlled-after-restore.https.html: On Firefox, fetches are not intercepted after restored from BFCache while `navigator.serviceWorker.controller` is non-null. - service-worker-unregister.https.html: Controlled pages aren't evicted by unregister() (all browsers). Bug: 1107415, 1204228, w3c/ServiceWorker#1594 Change-Id: I73233cf917e31dd91b974823d5490d0190f0eade Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3201011 Reviewed-by: Rakina Zata Amni <rakina@chromium.org> Reviewed-by: Ben Kelly <wanderview@chromium.org> Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org> Cr-Commit-Position: refs/heads/main@{#1008327}
- Loading branch information
1 parent
ba1428c
commit e08e12d
Showing
6 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
html/browsers/browsing-the-web/back-forward-cache/resources/service-worker.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
self.addEventListener('message', function(event) { | ||
self.clients.claim() | ||
.then(function(result) { | ||
if (result !== undefined) { | ||
event.data.port.postMessage( | ||
'FAIL: claim() should be resolved with undefined'); | ||
return; | ||
} | ||
event.data.port.postMessage('PASS'); | ||
}) | ||
.catch(function(error) { | ||
event.data.port.postMessage('FAIL: exception: ' + error.name); | ||
}); | ||
}); | ||
|
||
self.addEventListener('fetch', e => { | ||
if (e.request.url.match(/\/is-controlled/)) { | ||
e.respondWith(new Response('controlled')); | ||
} | ||
else if (e.request.url.match(/\/get-clients-matchall/)) { | ||
const options = { includeUncontrolled: true, type: 'all' }; | ||
e.respondWith( | ||
self.clients.matchAll(options) | ||
.then(clients => { | ||
const client_urls = []; | ||
clients.forEach(client => client_urls.push(client.url)); | ||
return new Response(JSON.stringify(client_urls)); | ||
}) | ||
); | ||
} | ||
}); |
71 changes: 71 additions & 0 deletions
71
html/browsers/browsing-the-web/back-forward-cache/service-worker-clients-claim.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<!doctype html> | ||
<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="/common/dispatcher/dispatcher.js"></script> | ||
<script src="resources/helper.sub.js"></script> | ||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||
<script> | ||
// Calling Clients.claim() on the service worker when a controlled page is in | ||
// BFCache should evict the page from BFCache, as per | ||
// https://github.com/w3c/ServiceWorker/issues/1038#issuecomment-291028845. | ||
promise_test(async t => { | ||
const pageA = new RemoteContext(token()); | ||
const pageB = new RemoteContext(token()); | ||
|
||
const urlA = location.origin + executorPath + pageA.context_id; | ||
const urlB = originCrossSite + executorPath + pageB.context_id; | ||
|
||
window.open(urlA, '_blank', 'noopener'); | ||
await pageA.execute_script(waitForPageShow); | ||
|
||
// Register a service worker after `pageA` is loaded to make `pageA` | ||
// uncontrolled at this time. | ||
const workerUrl = | ||
'resources/service-worker.js?pipe=header(Service-Worker-Allowed,../)'; | ||
const registration = | ||
await service_worker_unregister_and_register(t, workerUrl, './'); | ||
t.add_cleanup(_ => registration.unregister()); | ||
await wait_for_state(t, registration.installing, 'activated'); | ||
|
||
// Navigate to `urlB`. | ||
await pageA.execute_script( | ||
(url) => { | ||
prepareNavigation(() => { location.href = url; }); | ||
}, | ||
[urlB]); | ||
await pageB.execute_script(waitForPageShow); | ||
|
||
// Call Clients.claim() on the service worker when `pageA` is in BFCache. | ||
const controllerChanged = new Promise( | ||
resolve => navigator.serviceWorker.oncontrollerchange = resolve); | ||
await claim(t, registration.active); | ||
await controllerChanged; | ||
|
||
// `pageA` doesn't appear in matchAll(). | ||
const clients1 = await (await fetch('/get-clients-matchall')).json(); | ||
assert_true(clients1.indexOf(urlA) < 0, | ||
'1: matchAll() before back navigation'); | ||
|
||
// Back navigate and check that the page was evicted from BFCache. | ||
await pageB.execute_script( | ||
() => { | ||
prepareNavigation(() => { history.back(); }); | ||
} | ||
); | ||
await pageA.execute_script(waitForPageShow); | ||
await assert_not_bfcached(pageA); | ||
|
||
// After back navigation, `pageA` appear in matchAll(), because it was newly | ||
// loaded and controlled by the service worker. | ||
const clients2 = await (await fetch('/get-clients-matchall')).json(); | ||
const controlled2 = await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)); | ||
assert_true(clients2.indexOf(urlA) >= 0, | ||
'2: matchAll() just after back navigation'); | ||
assert_true(controlled2, | ||
'2: pageA should be controlled just after back navigation'); | ||
|
||
}, 'Clients.claim() evicts pages that would be affected from BFCache'); | ||
</script> |
76 changes: 76 additions & 0 deletions
76
html/browsers/browsing-the-web/back-forward-cache/service-worker-clients-matchall.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<!doctype html> | ||
<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="/common/dispatcher/dispatcher.js"></script> | ||
<script src="resources/helper.sub.js"></script> | ||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||
<script> | ||
promise_test(async t => { | ||
// Register a service worker and make this page controlled. | ||
const workerUrl = | ||
'resources/service-worker.js?pipe=header(Service-Worker-Allowed,../)'; | ||
const registration = | ||
await service_worker_unregister_and_register(t, workerUrl, './'); | ||
t.add_cleanup(_ => registration.unregister()); | ||
await wait_for_state(t, registration.installing, 'activated'); | ||
const controllerChanged = new Promise( | ||
resolve => navigator.serviceWorker.oncontrollerchange = resolve); | ||
await claim(t, registration.active); | ||
await controllerChanged; | ||
|
||
const pageA = new RemoteContext(token()); | ||
const pageB = new RemoteContext(token()); | ||
|
||
const urlA = location.origin + executorPath + pageA.context_id; | ||
const urlB = originCrossSite + executorPath + pageB.context_id; | ||
|
||
// Open `urlA`. | ||
window.open(urlA, '_blank', 'noopener'); | ||
await pageA.execute_script(waitForPageShow); | ||
|
||
// Get Clients.matchAll() and check whether `pageA` is controlled. | ||
// Actual `assert_*()` is called after `assert_bfcached()` below. | ||
const clients1 = await (await fetch('/get-clients-matchall')).json(); | ||
const controlled1 = await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)); | ||
|
||
// Navigate to `urlB` and get Clients.matchAll() when `urlA` is in BFCache. | ||
await pageA.execute_script( | ||
(url) => prepareNavigation(() => { | ||
location.href = url; | ||
}), | ||
[urlB]); | ||
await pageB.execute_script(waitForPageShow); | ||
const clients2 = await (await fetch('/get-clients-matchall')).json(); | ||
|
||
// Back navigate and check whether the page is restored from BFCache. | ||
await pageB.execute_script( | ||
() => { | ||
prepareNavigation(() => { history.back(); }); | ||
} | ||
); | ||
await pageA.execute_script(waitForPageShow); | ||
await assert_bfcached(pageA); | ||
|
||
// Get Clients.matchAll() and check whether `pageA` is controlled. | ||
const clients3 = await (await fetch('/get-clients-matchall')).json(); | ||
const controlled3 = await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)); | ||
|
||
// Clients.matchAll() should not list `urlA` when it is in BFCache. | ||
assert_true(clients1.indexOf(urlA) >= 0, | ||
'1: matchAll() before navigation'); | ||
assert_true(clients2.indexOf(urlA) < 0, | ||
'2: matchAll() before back navigation'); | ||
assert_true(clients3.indexOf(urlA) >= 0, | ||
'3: matchAll() after back navigation'); | ||
|
||
// `pageA` should be controlled before/after BFCached. | ||
assert_true(controlled1, | ||
'pageA should be controlled before BFCached'); | ||
assert_true(controlled3, | ||
'pageA should be controlled after restored'); | ||
}, 'Clients.matchAll() should not list pages in BFCache'); | ||
</script> |
54 changes: 54 additions & 0 deletions
54
...rs/browsing-the-web/back-forward-cache/service-worker-controlled-after-restore.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<!doctype html> | ||
<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="/common/dispatcher/dispatcher.js"></script> | ||
<script src="resources/helper.sub.js"></script> | ||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||
<script> | ||
promise_test(async t => { | ||
const pageA = new RemoteContext(token()); | ||
const pageB = new RemoteContext(token()); | ||
|
||
const urlA = location.origin + executorPath + pageA.context_id; | ||
const urlB = originCrossSite + executorPath + pageB.context_id; | ||
|
||
// Register a service worker. | ||
const workerUrl = | ||
'resources/service-worker.js?pipe=header(Service-Worker-Allowed,../)'; | ||
const registration = | ||
await service_worker_unregister_and_register(t, workerUrl, './'); | ||
t.add_cleanup(_ => registration.unregister()); | ||
await wait_for_state(t, registration.installing, 'activated'); | ||
|
||
window.open(urlA, '_blank', 'noopener'); | ||
await pageA.execute_script(waitForPageShow); | ||
|
||
assert_true( | ||
await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)), | ||
'pageA should be controlled before navigation'); | ||
|
||
navigateAndThenBack(pageA, pageB, urlB); | ||
await assert_bfcached(pageA); | ||
|
||
assert_true( | ||
await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)), | ||
'navigator.serviceWorker.controller should be non-null ' + | ||
'after restored from BFCache'); | ||
|
||
const isControlled = await pageA.execute_script( | ||
() => fetch('/is-controlled').then(r => r.text())); | ||
|
||
assert_true( | ||
await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)), | ||
'navigator.serviceWorker.controller should be non-null ' + | ||
'after restored from BFCache and after fetch'); | ||
|
||
assert_equals(isControlled, 'controlled', | ||
'fetch should be intercepted after restored from BFCache'); | ||
}, 'Pages should remain controlled after restored from BFCache'); | ||
</script> |
67 changes: 67 additions & 0 deletions
67
html/browsers/browsing-the-web/back-forward-cache/service-worker-unregister.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<!doctype html> | ||
<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="/common/dispatcher/dispatcher.js"></script> | ||
<script src="resources/helper.sub.js"></script> | ||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||
<script> | ||
// When a service worker is unregistered when a controlled page is in BFCache, | ||
// the page can be still restored from BFCache and remain controlled by the | ||
// service worker. | ||
promise_test(async t => { | ||
// Register a service worker and make this page controlled. | ||
const workerUrl = | ||
'resources/service-worker.js?pipe=header(Service-Worker-Allowed,../)'; | ||
const registration = | ||
await service_worker_unregister_and_register(t, workerUrl, './'); | ||
t.add_cleanup(_ => registration.unregister()); | ||
await wait_for_state(t, registration.installing, 'activated'); | ||
const controllerChanged = new Promise( | ||
resolve => navigator.serviceWorker.oncontrollerchange = resolve); | ||
await claim(t, registration.active); | ||
await controllerChanged; | ||
|
||
const pageA = new RemoteContext(token()); | ||
const pageB = new RemoteContext(token()); | ||
|
||
const urlA = location.origin + executorPath + pageA.context_id; | ||
const urlB = originCrossSite + executorPath + pageB.context_id; | ||
|
||
// Open `urlA`. | ||
window.open(urlA, '_blank', 'noopener'); | ||
await pageA.execute_script(waitForPageShow); | ||
|
||
assert_true( | ||
await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller !== null)), | ||
'pageA should be controlled before navigation'); | ||
|
||
// Navigate to `urlB`. | ||
await pageA.execute_script( | ||
(url) => prepareNavigation(() => { | ||
location.href = url; | ||
}), | ||
[urlB]); | ||
await pageB.execute_script(waitForPageShow); | ||
|
||
// Unregister the service worker when the controlled `pageA` is in BFCache. | ||
await registration.unregister(); | ||
|
||
// Back navigate and check whether the page is restored from BFCache. | ||
await pageB.execute_script( | ||
() => { | ||
prepareNavigation(() => { history.back(); }); | ||
} | ||
); | ||
await pageA.execute_script(waitForPageShow); | ||
await assert_not_bfcached(pageA); | ||
|
||
assert_true( | ||
await pageA.execute_script( | ||
() => (navigator.serviceWorker.controller === null)), | ||
'pageA should not be controlled'); | ||
|
||
}, 'Unregister service worker while a controlled page is in BFCache'); | ||
</script> |