Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service workers: Resurrection is no longer a thing #17139

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,113 +72,54 @@
.catch(unreached_rejection(t));
}, 'Registering a new script URL while an unregistered registration is in use');
jakearchibald marked this conversation as resolved.
Show resolved Hide resolved

async_test(function(t) {
var scope = 'resources/scope/unregister-then-register-new-script-that-404s';
var iframe;
var registration;
promise_test(async function(t) {
const scope = 'resources/scope/unregister-then-register-new-script-that-404s';
const registration = await service_worker_unregister_and_register(t, worker_url, scope);
await wait_for_state(t, registration.installing, 'activated');

service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
registration = r;
return wait_for_state(t, r.installing, 'activated');
})
.then(function() {
return with_iframe(scope);
})
.then(function(frame) {
iframe = frame;
return registration.unregister();
})
.then(function() {
// Step 5.1 of Register clears the uninstall flag before fetching
// the script:
//
// https://w3c.github.io/ServiceWorker/#register-algorithm
var promise = navigator.serviceWorker.register('this-will-404',
{ scope: scope });
return promise;
})
.then(
function() {
assert_unreached('register should reject the promise');
},
function() {
assert_equals(registration.installing, null,
'registration.installing');
assert_equals(registration.waiting, null,
'registration.waiting');
assert_equals(registration.active.scriptURL, normalizeURL(worker_url),
'registration.active');
iframe.remove();
return with_iframe(scope);
})
.then(function(frame) {
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalizeURL(worker_url),
'the original worker should control a new document');
frame.remove();
return registration.unregister();
})
.then(function() {
t.done();
})
.catch(unreached_rejection(t));
}, 'Registering a new script URL that 404s does resurrect an ' +
'unregistered registration');
const iframe = await with_iframe(scope);

async_test(function(t) {
var scope = 'resources/scope/unregister-then-register-reject-install-worker';
var iframe;
var registration;
await registration.unregister();
jakearchibald marked this conversation as resolved.
Show resolved Hide resolved

service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
registration = r;
return wait_for_state(t, r.installing, 'activated');
})
.then(function() {
return with_iframe(scope);
})
.then(function(frame) {
iframe = frame;
return registration.unregister();
})
.then(function() {
// Step 5.1 of Register clears the uninstall flag before firing
// the install event:
//
// https://w3c.github.io/ServiceWorker/#register-algorithm
var promise = navigator.serviceWorker.register(
'resources/reject-install-worker.js', { scope: scope });
return promise;
})
.then(function(r) {
registration = r;
return wait_for_state(t, r.installing, 'redundant');
})
.then(function() {
assert_equals(registration.installing, null,
'registration.installing');
assert_equals(registration.waiting, null,
'registration.waiting');
assert_equals(registration.active.scriptURL, normalizeURL(worker_url),
'registration.active');
iframe.remove();
return with_iframe(scope);
})
.then(function(frame) {
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalizeURL(worker_url),
'the original worker should control a new document');
frame.remove();
return registration.unregister();
})
.then(function() {
t.done();
})
.catch(unreached_rejection(t));
}, 'Registering a new script URL that fails to install does resurrect ' +
'an unregistered registration');
try {
await navigator.serviceWorker.register('this-will-404', { scope });
assert_unreached('register should reject');
} catch (err) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have promise_rejects() but I'm not sure which is actually easier to read. I guess promise_rejects lets you test the exception type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

promise_rejects is better, as it also ensures it's a promise that rejects, and not a function that throws.


assert_equals(registration.installing, null, 'registration.installing');
assert_equals(registration.waiting, null, 'registration.waiting');
assert_equals(registration.active.scriptURL, normalizeURL(worker_url), 'registration.active');

const newIframe = await with_iframe(scope);

assert_equals(newIframe.contentWindow.navigator.serviceWorker.controller, null, 'Document should not be controlled');
newIframe.remove();
iframe.remove();
}, 'Registering a new script URL that 404s does not resurrect unregistered registration');
// Service worker used to 'ressurect' registrations, so registration and new_registration would be equal.
// This has since been changed.
jakearchibald marked this conversation as resolved.
Show resolved Hide resolved

promise_test(async function(t) {
const scope = 'resources/scope/unregister-then-register-new-script-that-404s';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that-404s -> that-rejects-in-install

(but we don't really need these unique scopes anymore, they were just there because we used async_tests which run in parallel and caused collisions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, silly copy-paste error. Thanks for spotting.

const registration = await service_worker_unregister_and_register(t, worker_url, scope);
await wait_for_state(t, registration.installing, 'activated');

const iframe = await with_iframe(scope);

await registration.unregister();

const newRegistration = await navigator.serviceWorker.register(
'resources/reject-install-worker.js', { scope }
);
await wait_for_state(t, newRegistration.installing, 'redundant');

assert_equals(registration.installing, null, 'registration.installing');
assert_equals(registration.waiting, null, 'registration.waiting');
assert_equals(registration.active.scriptURL, null, 'registration.active');
assert_not_equals(registration, newRegistration, 'New registration is different');

iframe.remove();
}, 'Registering a new script URL that fails to install does not resurrect unregistered registration');
// Service worker used to 'ressurect' registrations, so registration and new_registration would be equal.
// This has since been changed.
</script>
143 changes: 40 additions & 103 deletions service-workers/service-worker/unregister-then-register.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
t.add_cleanup(function() {
return service_worker_unregister(t, scope);
});
return service_worker_unregister(t, scope);
});

registration = r;
return wait_for_state(t, r.installing, 'activated');
Expand All @@ -30,75 +30,24 @@
});
}, 'Unregister then register resolves to a new value');

promise_test(function(t) {
var scope = 'resources/scope/re-register-while-old-registration-in-use';
var registration;
promise_test(async function(t) {
const scope = 'resources/scope/re-register-while-old-registration-in-use';
const registration = await service_worker_unregister_and_register(t, worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice to also remove the iframe in the cleanup before unregistering, as it helps unregister really unregister.


return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
t.add_cleanup(function() {
return service_worker_unregister(t, scope);
});
await wait_for_state(t, registration.installing, 'activated');
const frame = await with_iframe(scope);

registration = r;
return wait_for_state(t, r.installing, 'activated');
})
.then(function() {
return with_iframe(scope);
})
.then(function(frame) {
return registration.unregister();
})
.then(function() {
return navigator.serviceWorker.register(worker_url, { scope: scope });
})
.then(function(new_registration) {
assert_equals(registration, new_registration,
'new registration should resolve to the same registration');
});
}, 'Unregister then register resolves to the original value if the ' +
'registration is in use.');
await registration.unregister();
const newRegistration = await navigator.serviceWorker.register(worker_url, { scope });

promise_test(function(t) {
var scope = 'resources/scope/complete-unregistration-followed-by-' +
'reloading-controllee-iframe';
var registration;
var frame;
var service_worker;
return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
t.add_cleanup(function() {
return service_worker_unregister(t, scope);
});

registration = r;
return wait_for_state(t, r.installing, 'activated');
})
.then(function() {
return with_iframe(scope);
})
.then(function(f) {
frame = f;
return registration.unregister();
})
.then(function() {
return new Promise(function(resolve) {
frame.onload = resolve;
frame.contentWindow.location.reload();
});
})
.then(function() {
var c = frame.contentWindow.navigator.serviceWorker.controller;
assert_equals(c, null, 'a page after unregistration should not be ' +
'controlled by service worker');
return navigator.serviceWorker.getRegistration(scope);
})
.then(function(r) {
assert_equals(r, undefined, 'getRegistration should return ' +
'undefined after unregistration');
});
}, 'Reloading the last controlled iframe after unregistration should ensure ' +
'the deletion of the registration');
assert_not_equals(
registration, newRegistration,
'Unregister and register should always create a new registration'
);
}, 'Unregister then register does not resolve to the original value even if the registration is in use.');
// Service worker used to 'ressurect' registrations, so registration and new_registration would be equal.
// This has since been changed.

promise_test(function(t) {
var scope = 'resources/scope/re-register-does-not-affect-existing-controllee';
Expand All @@ -109,8 +58,8 @@
return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
t.add_cleanup(function() {
return service_worker_unregister(t, scope);
});
return service_worker_unregister(t, scope);
});

registration = r;
return wait_for_state(t, r.installing, 'activated');
Expand Down Expand Up @@ -138,39 +87,27 @@
});
}, 'Unregister then register does not affect existing controllee');

promise_test(function(t) {
var scope = 'resources/scope/resurrection';
var iframe;
var registration;
promise_test(async function(t) {
const scope = 'resources/scope/resurrection';
const registration = await service_worker_unregister_and_register(t, worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));

return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
t.add_cleanup(function() {
return service_worker_unregister(t, scope);
});
await wait_for_state(t, registration.installing, 'activated');
const iframe = await with_iframe(scope);

registration = r;
return wait_for_state(t, r.installing, 'activated');
})
.then(function() {
return with_iframe(scope);
})
.then(function(frame) {
iframe = frame;
return registration.unregister();
})
.then(function() {
return navigator.serviceWorker.register(worker_url, { scope: scope });
})
.then(function() {
iframe.remove();
return with_iframe(scope);
})
.then(function(frame) {
assert_not_equals(
frame.contentWindow.navigator.serviceWorker.controller, null,
'document should have a controller');
frame.remove();
});
}, 'Unregister then register resurrects the registration');
await registration.unregister();
const newRegistration = await navigator.serviceWorker.register(worker_url, { scope });

iframe.remove();
const newIframe = await with_iframe(scope);
const iframeRegistration = await newIframe.contentWindow.navigator.serviceWorker.ready;

assert_true(!!iframeRegistration, 'iFrame has registration');
assert_true(!!newIframe.contentWindow.navigator.serviceWorker.controller, 'iFrame has controller');

assert_not_equals(registration, newRegistration, 'Registrations are different');
assert_equals(newRegistration, iframeRegistration, 'iFrame uses new registration');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this holds because newRegistration and iframeRegistration are from different windows so have different prototypes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol indeed. Will fix.

}, 'Unregister then register does not resurrect the registration');
// Service worker used to 'ressurect' registrations, so registration and new_registration would be equal.
// This has since been changed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests for getRegistration() after unregister() in a controlled frame? I guess it can be added to getregistration.https.html. Looks like we already have coverage for getRegistrations() in getregistrations.https.html.

</script>