diff --git a/lib/__tests__/app-update.test.ts b/lib/__tests__/app-update.test.ts index ede111d70..4adbb77bc 100644 --- a/lib/__tests__/app-update.test.ts +++ b/lib/__tests__/app-update.test.ts @@ -83,4 +83,16 @@ describe('app update', () => { adoptWaitingWorker({ waiting: other, addEventListener: () => {} } as unknown as ServiceWorkerRegistration); expect(other.postMessage).not.toHaveBeenCalled(); }); + + it('also when the worker of this tab’s build was still installing', () => { + const listeners: Array<() => void> = []; + const installing = { scriptURL: 'https://mail.example.com/sw.js?v=build-a', state: 'installing', postMessage: vi.fn(), addEventListener: (_: string, fn: () => void) => listeners.push(fn) }; + const registration = { waiting: null as unknown, installing, addEventListener: () => {} }; + adoptWaitingWorker(registration as unknown as ServiceWorkerRegistration); + expect(installing.postMessage).not.toHaveBeenCalled(); + installing.state = 'installed'; + registration.waiting = installing; + listeners.forEach((fn) => fn()); + expect(installing.postMessage).toHaveBeenCalledWith({ type: 'skip-waiting' }); + }); }); diff --git a/lib/app-update.ts b/lib/app-update.ts index dab926309..c2d7db144 100644 --- a/lib/app-update.ts +++ b/lib/app-update.ts @@ -91,13 +91,15 @@ export function adoptWaitingWorker(registration: ServiceWorkerRegistration): voi const adopt = () => { if (ours(registration.waiting)) registration.waiting!.postMessage({ type: 'skip-waiting' }); }; - adopt(); - registration.addEventListener('updatefound', () => { - const installing = registration.installing; - installing?.addEventListener('statechange', () => { - if (installing.state === 'installed') adopt(); + const watch = (worker: ServiceWorker | null) => { + worker?.addEventListener('statechange', () => { + if (worker.state === 'installed') adopt(); }); - }); + }; + adopt(); + // Still installing when the registration resolved, or installed later. + watch(registration.installing); + registration.addEventListener('updatefound', () => watch(registration.installing)); } /** Tells the service worker which build this tab runs, so it keeps that build's files while the tab is open. */