/** * P-series: PWA install prerequisites (Fase 6.1 + 6.2). * * Validates that the web manifest is served correctly and a service worker * registers after first load. Lighthouse ≥ 90 is manual (see `just lighthouse`). */ import { test, expect } from '@playwright/test'; import { USERS } from '../fixtures/users.js'; import { loginAs } from '../fixtures/login.js'; test.describe('PWA install prerequisites', () => { test('P-01: /manifest.webmanifest is served with a valid shape', async ({ request }) => { const r = await request.get('/manifest.webmanifest'); expect(r.status()).toBe(200); // Either application/manifest+json or application/json is acceptable // (Vite dev and the @vite-pwa plugin can disagree on the exact value). expect(r.headers()['content-type'] ?? '').toMatch(/manifest\+json|application\/json/); const m = (await r.json()) as { name?: string; short_name?: string; start_url?: string; display?: string; icons?: Array<{ sizes?: string; type?: string; src?: string }>; }; expect(m.name).toBeTruthy(); expect(m.short_name).toBeTruthy(); expect(m.start_url).toBeTruthy(); expect(m.display).toBe('standalone'); expect(Array.isArray(m.icons)).toBe(true); const sizes = (m.icons ?? []).map((i) => i.sizes); expect(sizes).toContain('192x192'); expect(sizes).toContain('512x512'); }); test('P-02: service worker registers after first load', async ({ page }) => { await loginAs(page, USERS.borja); await page.goto('/lists'); // SW registration is async and driven by an onMount() dynamic import in // the root layout — give it a few seconds to resolve before asserting. const reg = await page.waitForFunction( async () => { const r = await navigator.serviceWorker.getRegistration(); return r ? { scope: r.scope } : null; }, null, { timeout: 10_000 } ); const state = await reg.jsonValue(); expect(state).not.toBeNull(); expect(state?.scope).toMatch(/^https?:\/\//); }); });