mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
fix(pwa): give the offline page a way back and reload once on any stale chunk
Without a connection a signed-in page opens the worker's offline page: signed-in pages carry `private, no-store` from the proxy and are never cached, so this is also what an offline launch of the installed app shows. The page now offers a real 64 px retry control, reloads by itself when the connection returns, follows the device's light or dark scheme and keeps clear of the notch and home indicator. The worker's comment on the page cache says plainly that only public pages land in it. The single reload after a stale-shell chunk failure moves into src/lib/pwa/chunk-reload.ts and now runs in the root error boundary too, and it recognises a failed dynamic import as WebKit and Firefox word it. pwa-offline.spec.ts runs in the service-worker project and proves the offline strip, the offline page and the automatic recovery against the real worker.
This commit is contained in:
1 parent
503802e363
commit
ac212cf6b7
8 files changed
+271
-78
No files matched your search
@@ -217,6 +217,10 @@ function bootServiceWorker(): SwHarness {
|
||||
URL,
|
||||
Promise,
|
||||
console,
|
||||
// Read through the context so a test can install fake timers before
|
||||
// dispatching (the slow-navigation fallback arms one per navigation).
|
||||
setTimeout: (...args: Parameters<typeof setTimeout>) => setTimeout(...args),
|
||||
clearTimeout: (id: ReturnType<typeof setTimeout>) => clearTimeout(id),
|
||||
};
|
||||
vm.createContext(context);
|
||||
vm.runInContext(SW_SOURCE, context);
|
||||
@@ -617,6 +621,23 @@ describe("sw.js — networkFirst offline fallback", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("sw.js — offline page", () => {
|
||||
it("offers a retry control, reloads by itself when the connection returns, and follows the device scheme", async () => {
|
||||
const harness = bootServiceWorker();
|
||||
const res = await dispatchNavigationFetch(harness, "/");
|
||||
expect(res.status).toBe(503);
|
||||
const html = await res.text();
|
||||
// A real control, not a decorative icon: a link back to the same URL.
|
||||
expect(html).toMatch(/<a href="" aria-label="[^"]+"/);
|
||||
expect(html).toContain('addEventListener("online"');
|
||||
expect(html).toContain("prefers-color-scheme:light");
|
||||
expect(html).toContain("viewport-fit=cover");
|
||||
expect(html).toContain("env(safe-area-inset-bottom)");
|
||||
// Still language-neutral: no sentence in any one locale.
|
||||
expect(html).not.toMatch(/Keine Verbindung|You are offline/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("sw.js — networkFirst privacy gate", () => {
|
||||
it("does not cache a navigation response that carries Cache-Control: no-store", async () => {
|
||||
const harness = bootServiceWorker();
|
||||
|
||||
Reference in new issue
Block a user