Skip to content

Commit 1ca2d53

Browse files
committed
test: preserve later service worker refreshes
1 parent 8cc74fe commit 1ca2d53

3 files changed

Lines changed: 53 additions & 8 deletions

File tree

‎src/register-service-worker.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function registerServiceWorker() {
66
if (isNativeApp()) return;
77
if (!import.meta.env.PROD || !('serviceWorker' in navigator)) return;
88

9-
const hadController = navigator.serviceWorker.controller !== null;
9+
let hadController = navigator.serviceWorker.controller !== null;
1010

1111
window.addEventListener('load', () => {
1212
navigator.serviceWorker.register(SERVICE_WORKER_URL)
@@ -27,7 +27,10 @@ export function registerServiceWorker() {
2727
});
2828

2929
navigator.serviceWorker.addEventListener('controllerchange', () => {
30-
if (!hadController) return;
30+
if (!hadController) {
31+
hadController = true;
32+
return;
33+
}
3134
if (sessionStorage.getItem('pwa-refreshing') === 'true') return;
3235
sessionStorage.setItem('pwa-refreshing', 'true');
3336
window.location.reload();
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
vi.mock('@/lib/native', () => ({ isNativeApp: () => false }));
4+
5+
import { registerServiceWorker } from '@/register-service-worker';
6+
7+
describe('registerServiceWorker', () => {
8+
const originalServiceWorker = Object.getOwnPropertyDescriptor(navigator, 'serviceWorker');
9+
let controllerChange: EventListener | undefined;
10+
11+
beforeEach(() => {
12+
vi.stubEnv('PROD', true);
13+
sessionStorage.clear();
14+
controllerChange = undefined;
15+
Object.defineProperty(navigator, 'serviceWorker', {
16+
configurable: true,
17+
value: {
18+
controller: null,
19+
register: vi.fn().mockResolvedValue({ addEventListener: vi.fn() }),
20+
addEventListener: vi.fn((type: string, listener: EventListener) => {
21+
if (type === 'controllerchange') controllerChange = listener;
22+
}),
23+
},
24+
});
25+
});
26+
27+
afterEach(() => {
28+
vi.unstubAllEnvs();
29+
vi.restoreAllMocks();
30+
if (originalServiceWorker) {
31+
Object.defineProperty(navigator, 'serviceWorker', originalServiceWorker);
32+
} else {
33+
Reflect.deleteProperty(navigator, 'serviceWorker');
34+
}
35+
});
36+
37+
it('skips the initial claim but refreshes for a later controller change', () => {
38+
registerServiceWorker();
39+
40+
expect(controllerChange).toBeDefined();
41+
controllerChange?.(new Event('controllerchange'));
42+
expect(sessionStorage.getItem('pwa-refreshing')).toBeNull();
43+
44+
vi.spyOn(console, 'error').mockImplementation(() => undefined);
45+
controllerChange?.(new Event('controllerchange'));
46+
expect(sessionStorage.getItem('pwa-refreshing')).toBe('true');
47+
});
48+
});

‎src/test/vercel-deployment-config.test.ts‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,6 @@ describe("Vercel frontend deployment configuration", () => {
9191
expect(serviceWorker).toContain("cache.put('/index.html', response.clone())");
9292
});
9393

94-
it("does not reload the page when the service worker first takes control", () => {
95-
const registration = readProjectFile("src/register-service-worker.ts");
96-
expect(registration).toContain("const hadController = navigator.serviceWorker.controller !== null");
97-
expect(registration).toContain("if (!hadController) return");
98-
});
99-
10094
it.each(["/app", "/app/(.*)", "/login", "/share/(.*)"])(
10195
"keeps private route %s out of search indexes",
10296
(source) => {

0 commit comments

Comments
 (0)