51 lines
3.3 KiB
JavaScript
51 lines
3.3 KiB
JavaScript
|
|
// Offline end-to-end check against `pnpm preview` (production build, service worker on). Run: node scripts/offline-e2e.mjs
|
||
|
|
// 1) first visit saves the app + the map pack, 2) with the network cut the app reloads, shows the offline notice and still routes.
|
||
|
|
import { chromium } from 'playwright-core';
|
||
|
|
const URL = process.env.URL ?? 'http://localhost:4173/';
|
||
|
|
const browser = await chromium.launch();
|
||
|
|
const ctx = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'pl-PL', isMobile: true, hasTouch: true });
|
||
|
|
const page = await ctx.newPage();
|
||
|
|
let step = 0;
|
||
|
|
const ok = (cond, msg) => { step++; if (!cond) { console.error(`FAIL ${step}: ${msg}`); process.exitCode = 1; } else console.log(`ok ${step}: ${msg}`); };
|
||
|
|
const caches = () => page.evaluate(async () => { const o = {}; for (const n of await window.caches.keys()) o[n] = (await (await window.caches.open(n)).keys()).length; return o; });
|
||
|
|
|
||
|
|
await page.goto(URL);
|
||
|
|
await page.click('text=Zaloguj jako Anna Kowalska');
|
||
|
|
await page.waitForSelector('#q', { state: 'attached', timeout: 60_000 });
|
||
|
|
ok(await page.evaluate(() => !!navigator.serviceWorker.controller), 'service worker controls the page');
|
||
|
|
let tiles = 0;
|
||
|
|
for (let i = 0; i < 150 && tiles < 1000; i++) { tiles = (await caches())['osm-tiles'] ?? 0; if (tiles < 1000) await page.waitForTimeout(1000); }
|
||
|
|
ok(tiles >= 1000, `offline map pack saved (${tiles} tiles)`);
|
||
|
|
let rec = null;
|
||
|
|
for (let i = 0; i < 60 && !rec; i++) { rec = JSON.parse((await page.evaluate(() => localStorage.getItem('kbb.offline'))) ?? 'null'); if (!rec) await page.waitForTimeout(500); }
|
||
|
|
ok(rec && rec.failed === 0 && rec.tiles >= 1000, 'pack record stored');
|
||
|
|
|
||
|
|
await ctx.setOffline(true);
|
||
|
|
await page.waitForSelector('.kbb-banner--warning', { timeout: 5000 });
|
||
|
|
ok(/Trasy na żywo/.test(await page.locator('.kbb-banner--warning').innerText()), 'offline notice says live routes are unavailable');
|
||
|
|
await page.click('.kbb-banner--warning .kbb-banner__close');
|
||
|
|
ok((await page.locator('.kbb-banner--warning').count()) === 0, 'offline notice can be dismissed');
|
||
|
|
|
||
|
|
await page.reload({ waitUntil: 'domcontentloaded' });
|
||
|
|
await page.waitForSelector('#q', { state: 'attached', timeout: 30_000 });
|
||
|
|
ok(true, 'app reloads and opens with no network');
|
||
|
|
ok((await page.locator('.kbb-banner--warning').count()) === 1, 'offline notice shown again after the reload');
|
||
|
|
|
||
|
|
await page.click('nav >> text=Trasa');
|
||
|
|
await page.fill('#route-from', 'Sukiennice');
|
||
|
|
await page.fill('#route-to', 'Zamek Królewski na Wawelu');
|
||
|
|
await page.click('button[type=submit]:has-text("Wyznacz")');
|
||
|
|
await page.waitForSelector('.kbb-modes', { timeout: 10_000 });
|
||
|
|
ok(true, 'walking route is computed offline');
|
||
|
|
await page.click('.kbb-mode:has-text("Komunikacja")');
|
||
|
|
// scoped to the planner: the offline banner also says "Brak połączenia", and the loader shares the #tr-title heading
|
||
|
|
const planner = page.locator('section[aria-labelledby=tr-title]');
|
||
|
|
await planner.locator('.kbb-jhead, .usa-alert').first().waitFor({ timeout: 20_000 });
|
||
|
|
const note = await page.locator('#tr-title + p').innerText();
|
||
|
|
ok(/Według rozkładu/.test(note), `transit planner answers from the saved timetable and says delays are unavailable ("${note.slice(0, 60)}")`);
|
||
|
|
|
||
|
|
await ctx.setOffline(false);
|
||
|
|
await page.waitForSelector('.kbb-banner--success', { timeout: 5000 });
|
||
|
|
ok(true, 'back-online notice appears');
|
||
|
|
await browser.close();
|