Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

"use strict";
// This test registers a SW for a scope that will never control a document
// and therefore never trigger a "fetch" functional event that would
// automatically attempt to update the registration. The overlap of the
// PAGE_URI and SCOPE is incidental. checkForUpdate is the only thing that
// will trigger an update of the registration and so there is no need to
// worry about Schedule Job races to coalesce an update job.
const PAGE_URI = BASE_URI + "empty.html";
const SCOPE = PAGE_URI + "?storage_recovery";
const SW_SCRIPT = BASE_URI + "storage_recovery_worker.sjs";
async function checkForUpdate(browser) {
return SpecialPowers.spawn(browser, [SCOPE], async function (uri) {
let reg = await content.navigator.serviceWorker.getRegistration(uri);
await reg.update();
return !!reg.installing;
});
}
// Delete all of our chrome-namespace Caches for this origin, leaving any
// content-owned caches in place. This is exclusively for simulating loss
// of the origin's storage without loss of the registration and without
// having to worry that future enhancements to QuotaClients/ServiceWorkerRegistrar
// will break this test. If you want to wipe storage for an origin, use
// QuotaManager APIs
async function wipeStorage(u) {
let uri = Services.io.newURI(u);
let principal = Services.scriptSecurityManager.createContentPrincipal(
uri,
{}
);
let caches = new CacheStorage("chrome", principal);
let list = await caches.keys();
return Promise.all(list.map(c => caches.delete(c)));
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.serviceWorkers.idle_timeout", 0],
],
});
// Configure the server script to not redirect.
await fetch(SW_SCRIPT + "?clear-redirect");
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
await SpecialPowers.spawn(
browser,
[{ script: SW_SCRIPT, scope: SCOPE }],
async function (opts) {
let reg = await content.navigator.serviceWorker.register(opts.script, {
scope: opts.scope,
});
let worker = reg.installing || reg.waiting || reg.active;
await new Promise(resolve => {
if (worker.state === "activated") {
resolve();
return;
}
worker.addEventListener("statechange", function onStateChange() {
if (worker.state === "activated") {
worker.removeEventListener("statechange", onStateChange);
resolve();
}
});
});
}
);
BrowserTestUtils.removeTab(tab);
});
// Verify that our service worker doesn't update normally.
add_task(async function normal_update_check() {
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
let updated = await checkForUpdate(browser);
ok(!updated, "normal update check should not trigger an update");
BrowserTestUtils.removeTab(tab);
});
// Test what happens when we wipe the service worker scripts
// out from under the site before triggering the update. This
// should cause an update to occur.
add_task(async function wiped_update_check() {
// Wipe the backing cache storage, but leave the SW registered.
await wipeStorage(PAGE_URI);
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
let updated = await checkForUpdate(browser);
ok(updated, "wiping the service worker scripts should trigger an update");
BrowserTestUtils.removeTab(tab);
});
// Test what happens when we wipe the service worker scripts
// out from under the site before triggering the update. This
// should cause an update to occur.
add_task(async function wiped_and_failed_update_check() {
// Wipe the backing cache storage, but leave the SW registered.
await wipeStorage(PAGE_URI);
// Configure the service worker script to redirect. This will
// prevent the update from completing successfully.
await fetch(SW_SCRIPT + "?set-redirect");
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// Attempt to update the service worker. This should throw
// an error because the script is now redirecting.
let updateFailed = false;
try {
await checkForUpdate(browser);
} catch (e) {
updateFailed = true;
}
ok(updateFailed, "redirecting service worker script should fail to update");
// Also, since the existing service worker's scripts are broken
// we should also remove the registration completely when the
// update fails.
let exists = await SpecialPowers.spawn(
browser,
[SCOPE],
async function (uri) {
let reg = await content.navigator.serviceWorker.getRegistration(uri);
return !!reg;
}
);
ok(
!exists,
"registration should be removed after scripts are wiped and update fails"
);
// Note, we don't have to clean up the service worker registration
// since its effectively been force-removed here.
BrowserTestUtils.removeTab(tab);
});