- Created `verification-layout-themes.md` to document layout and theme verification results. - Introduced `AlertCard` component for displaying alerts with appropriate icons and metadata. - Added `RouteCloud` component to manage and display route information dynamically. - Implemented tests for QR code generation and decoding to ensure functionality across multiple city and platform links.
44 lines
3.3 KiB
JavaScript
44 lines
3.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readSnapshot, writeSnapshot, readTimetable, writeTimetable, readWeather, writeWeather, readSettings, saveSettings } from '../src/lib/storage.ts';
|
|
|
|
const data = { cityId: 1, stop: { id: 1, name: 'Швейная фабрика' }, mode: 'live', serviceDate: '2026-10-08', updatedAt: '2026-10-08T12:00:00+03:00', routes: [], alerts: [],
|
|
departures: [{ id: '1:12:30', scheduledAt: '2026-10-08T12:30:00+03:00' }] };
|
|
|
|
test('offline snapshot is restored when IndexedDB is unavailable in a kiosk WebView', async () => {
|
|
const values = new Map();
|
|
globalThis.localStorage = { getItem: key => values.get(key) || null, setItem: (key, value) => values.set(key, value) };
|
|
globalThis.indexedDB = { open: () => { throw new Error('IndexedDB unavailable'); } };
|
|
await writeSnapshot(data);
|
|
assert.deepEqual(await readSnapshot(1, 1), data);
|
|
assert.equal(await readSnapshot(2, 1), null);
|
|
assert.equal(await readSnapshot(1, 2), null);
|
|
});
|
|
test('damaged saved data is rejected, and total storage failure is reported to the UI', async () => {
|
|
globalThis.localStorage = { getItem: () => '{invalid', setItem: () => { throw new Error('Quota exceeded'); } };
|
|
globalThis.indexedDB = { open: () => { throw new Error('IndexedDB unavailable'); } };
|
|
assert.equal(await readSnapshot(1, 1), null);
|
|
await assert.rejects(writeSnapshot(data));
|
|
});
|
|
test('full timetable and weather survive storage fallback and stay isolated by city and stop', async () => {
|
|
const values = new Map();
|
|
globalThis.localStorage = { getItem: key => values.get(key) || null, setItem: (key, value) => values.set(key, value) };
|
|
globalThis.indexedDB = { open: () => { throw new Error('IndexedDB unavailable'); } };
|
|
const timetable = { version: 1, cityId: 1, cityName: 'Полоцк', stop: { id: 1, name: 'Швейная фабрика', direction: '' }, routes: [], holidays: [], calendarYears: [2026], updatedAt: data.updatedAt, expiresAt: '2026-10-15T12:00:00+03:00' };
|
|
const weather = { cityId: 1, stopId: 1, updatedAt: data.updatedAt, observedAt: data.updatedAt, temperature: 12, apparentTemperature: 10, code: 3, isDay: true, windSpeed: 3, hourly: [] };
|
|
await writeTimetable(timetable); await writeWeather(weather); await writeSnapshot(data);
|
|
assert.deepEqual(await readTimetable(1, 1), timetable); assert.deepEqual(await readWeather(1, 1), weather); assert.deepEqual(await readSnapshot(1, 1), data);
|
|
assert.equal(await readTimetable(1, 2), null); assert.equal(await readWeather(2, 1), null);
|
|
});
|
|
test('old theme preferences migrate safely and each theme retains its own accent', () => {
|
|
const values = new Map([['ridebus-board-settings-v1', JSON.stringify({ colorScheme: 'cyan' })]]);
|
|
globalThis.localStorage = { getItem: key => values.get(key) || null, setItem: (key, value) => values.set(key, value) };
|
|
const old = readSettings();
|
|
assert.equal(old.theme, 'dark'); assert.equal(old.colorScheme, 'cyan'); assert.equal(old.lightColorScheme, 'blue');
|
|
saveSettings({ ...old, theme: 'light', lightColorScheme: 'crimson' });
|
|
const saved = readSettings();
|
|
assert.equal(saved.theme, 'light'); assert.equal(saved.lightColorScheme, 'crimson'); assert.equal(saved.colorScheme, 'cyan');
|
|
values.set('ridebus-board-settings-v1', JSON.stringify({ theme: 'light', lightColorScheme: 'lime' }));
|
|
assert.equal(readSettings().lightColorScheme, 'blue');
|
|
});
|