fix: fetch and activate the new service worker on Refresh UI when none is waiting yet
This commit is contained in:
@@ -93,6 +93,76 @@ test('falls back to a plain reload when there is no waiting worker', async () =>
|
||||
assert.strictEqual(reloadCount, 1);
|
||||
});
|
||||
|
||||
test('with no waiting worker, fetches the SW update and activates the newly installed worker (buildTag-poll path)', async () => {
|
||||
// Simulates: server redeployed (banner shown by the /api/version poll) but
|
||||
// the browser hasn't fetched the new sw.js yet — reg.waiting is null until
|
||||
// reg.update() is called and the new worker finishes installing.
|
||||
const messages = [];
|
||||
const container = fakeContainer();
|
||||
let reloadCount = 0;
|
||||
|
||||
const stateListeners = [];
|
||||
const installing = {
|
||||
state: 'installing',
|
||||
addEventListener: (type, fn) => { if (type === 'statechange') stateListeners.push(fn); },
|
||||
postMessage: (m) => messages.push(m),
|
||||
};
|
||||
const reg = {
|
||||
waiting: null,
|
||||
installing: null,
|
||||
update() {
|
||||
// Browser found a byte-different sw.js → a new worker starts installing.
|
||||
this.installing = installing;
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
const done = applyUpdate({
|
||||
reg,
|
||||
container,
|
||||
reload: () => { reloadCount++; },
|
||||
setTimeout: () => {}, // no-op — we drive state transitions manually
|
||||
});
|
||||
|
||||
// Let applyUpdate reach the waitForInstalled stage, then finish the install.
|
||||
await Promise.resolve(); await Promise.resolve();
|
||||
installing.state = 'installed';
|
||||
reg.waiting = installing;
|
||||
stateListeners.forEach((fn) => fn());
|
||||
await Promise.resolve(); await Promise.resolve();
|
||||
|
||||
assert.deepStrictEqual(messages, [{ type: 'SKIP_WAITING' }], 'skip-waiting sent to the freshly installed worker');
|
||||
assert.strictEqual(reloadCount, 0, 'must not reload before the new SW takes control');
|
||||
|
||||
container.fireControllerChange();
|
||||
await done;
|
||||
assert.strictEqual(reloadCount, 1);
|
||||
});
|
||||
|
||||
test('with no waiting worker and no update found, reloads once after the bounded wait', async () => {
|
||||
const container = fakeContainer();
|
||||
let reloadCount = 0;
|
||||
const timeouts = [];
|
||||
|
||||
const reg = {
|
||||
waiting: null,
|
||||
installing: null,
|
||||
update: () => Promise.resolve(), // update check ran; nothing new
|
||||
};
|
||||
|
||||
const done = applyUpdate({
|
||||
reg,
|
||||
container,
|
||||
reload: () => { reloadCount++; },
|
||||
setTimeout: (fn) => { timeouts.push(fn); },
|
||||
});
|
||||
|
||||
await Promise.resolve(); await Promise.resolve();
|
||||
// reg.installing is null → waitForInstalled resolves immediately with null.
|
||||
await done;
|
||||
assert.strictEqual(reloadCount, 1, 'plain reload when the update check finds nothing');
|
||||
});
|
||||
|
||||
test('falls back to a plain reload when there is no registration at all', async () => {
|
||||
const container = fakeContainer();
|
||||
let reloadCount = 0;
|
||||
|
||||
Reference in New Issue
Block a user