From 25d087aaa2f3341d5ade0f9507bdb066d7a3105a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Wed, 11 Nov 2026 20:39:08 +0100 Subject: [PATCH] fix(push): stop handling the clear push in the service worker The worker answered a `type: "clear"` push by closing the dose reminder for that slot and showing nothing. Browsers do not allow a push without a visible notification on a subscription that promised one: Safari removes the subscription after a few, Chromium shows its own "updated in the background" notice. The server no longer sends it, so the branch and its tests go; a reminder stays until it is tapped or the next reminder with the same tag replaces it. --- public/sw.js | 21 --------- .../baselines/version-stamp-comments.json | 5 +- src/__tests__/service-worker.test.ts | 46 ++----------------- 3 files changed, 5 insertions(+), 67 deletions(-) diff --git a/public/sw.js b/public/sw.js index 6dbeb9995..087a1f34e 100644 --- a/public/sw.js +++ b/public/sw.js @@ -530,27 +530,6 @@ self.addEventListener("push", (event) => { payload = { title: "HealthLog", body: event.data.text() }; } - // v1.18.4 — `type:"clear"` is the PWA equivalent of ending an iOS Live - // Activity: the server sends it when a dose is logged so the still-pending - // dose-due reminder for that slot is closed here (matched on its stable - // `tag`), and the app badge re-reflects the outstanding-dose count. No new - // notification is shown. - if (payload && payload.type === "clear") { - event.waitUntil( - (async () => { - const tagToClear = payload.tag; - if (tagToClear) { - const matches = await self.registration.getNotifications({ - tag: tagToClear, - }); - for (const n of matches) n.close(); - } - applyAppBadge(payload.badge); - })(), - ); - return; - } - const { title = "HealthLog", body = "", diff --git a/src/__tests__/baselines/version-stamp-comments.json b/src/__tests__/baselines/version-stamp-comments.json index c2ab886d7..d181dbcd1 100644 --- a/src/__tests__/baselines/version-stamp-comments.json +++ b/src/__tests__/baselines/version-stamp-comments.json @@ -1,7 +1,7 @@ { "$comment": "Comment lines that open with a release version, per file under src/. Maintained by src/__tests__/version-stamp-ratchet.test.ts.", - "count": 2888, - "total": 9204, + "count": 2887, + "total": 9203, "entries": { "__tests__/account-payload-consumer-guard.test.ts": 2, "__tests__/acting-account-boundary-guard.test.ts": 7, @@ -55,7 +55,6 @@ "__tests__/recurrence-course-anchor-guard.test.ts": 1, "__tests__/relation-links-backup-completeness.test.ts": 1, "__tests__/resolved-field-consumer-guard.test.ts": 1, - "__tests__/service-worker.test.ts": 1, "__tests__/session-surface-guard.test.ts": 7, "__tests__/settings-legacy-routes.test.ts": 1, "__tests__/shared-record-navigation.test.tsx": 1, diff --git a/src/__tests__/service-worker.test.ts b/src/__tests__/service-worker.test.ts index 301642f89..875a6b3e4 100644 --- a/src/__tests__/service-worker.test.ts +++ b/src/__tests__/service-worker.test.ts @@ -158,8 +158,8 @@ function bootServiceWorker(): SwHarness { navPreload.enabled = true; }, }; - // v1.18.4 — push-handler fakes: a notification store the `getNotifications` - // / `showNotification` calls read/write, and a Badging-API spy. + // Push-handler fakes: the notifications `showNotification` shows, and a + // Badging-API spy. const shown: Array<{ title: string; tag?: string; closed: boolean }> = []; const badge = { value: undefined as number | undefined, cleared: false }; const selfObj = { @@ -180,14 +180,6 @@ function bootServiceWorker(): SwHarness { showNotification: async (title: string, opts: { tag?: string }) => { shown.push({ title, tag: opts?.tag, closed: false }); }, - getNotifications: async ({ tag }: { tag?: string }) => - shown - .filter((n) => !n.closed && (tag === undefined || n.tag === tag)) - .map((n) => ({ - close: () => { - n.closed = true; - }, - })), }, navigator: { setAppBadge: (n: number) => { @@ -1080,7 +1072,7 @@ describe("sw.js — trimCache", () => { }); }); -// ── push handler (v1.18.4: clear-on-taken tag close + app badge) ───────────── +// ── push handler ───────────────────────────────────────────────────────────── async function dispatchPush(harness: SwHarness, data: unknown): Promise { let settled: Promise = Promise.resolve(); harness.listeners.get("push")!({ @@ -1117,36 +1109,4 @@ describe("sw.js — push handler", () => { expect(shown[0].tag).toBe(tag); expect(badge.value).toBe(3); }); - - it("a type:clear push closes the matching-tag notification (no new one) and updates the badge", async () => { - const harness = bootServiceWorker(); - const { shown, badge } = swFakes(harness); - const tag = "med:med-1:2026-06-18T07:00:00.000Z"; - - await dispatchPush(harness, { title: "dose", tag, badge: 1 }); - expect(shown.filter((n) => !n.closed)).toHaveLength(1); - - await dispatchPush(harness, { type: "clear", tag, badge: 0 }); - - // The pending reminder for that slot is closed; no new notification shown. - expect(shown).toHaveLength(1); - expect(shown[0].closed).toBe(true); - // badge: 0 clears the app badge. - expect(badge.cleared).toBe(true); - }); - - it("a type:clear push only closes its own slot's tag", async () => { - const harness = bootServiceWorker(); - const { shown } = swFakes(harness); - - await dispatchPush(harness, { title: "a", tag: "med:a:t1" }); - await dispatchPush(harness, { title: "b", tag: "med:b:t2" }); - - await dispatchPush(harness, { type: "clear", tag: "med:a:t1" }); - - const a = shown.find((n) => n.tag === "med:a:t1")!; - const b = shown.find((n) => n.tag === "med:b:t2")!; - expect(a.closed).toBe(true); - expect(b.closed).toBe(false); - }); });