import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import path from 'node:path'; import test from 'node:test'; import vm from 'node:vm'; const root = path.resolve(import.meta.dirname, '..'); class MemoryStorage { constructor() { this.values = new Map(); } getItem(key) { return this.values.has(key) ? this.values.get(key) : null; } setItem(key, value) { this.values.set(key, String(value)); } removeItem(key) { this.values.delete(key); } } async function loadModule() { const source = await fs.readFile(path.join(root, 'public/js/privacy-storage.js'), 'utf8'); const localStorage = new MemoryStorage(); const context = { Wegwichtel: {}, localStorage, document: { cookie: '' }, Date, JSON, Number, Set, String, Promise, setTimeout, clearTimeout }; context.globalThis = context; vm.runInNewContext(source, context, { filename: path.join(root, 'public/js/privacy-storage.js') }); return { storage: context.Wegwichtel.PrivacyStorage, localStorage }; } test('route progress storage is opt-in and deleting the option removes progress data', async () => { const { storage, localStorage } = await loadModule(); assert.equal(storage.isProgressStorageEnabled(), false); assert.equal(storage.activateRoute({ id: 7, name: 'Testweg' }), null); storage.setProgressStorageEnabled(true); storage.activateRoute({ id: 7, name: 'Testweg' }); storage.markVisited(7, 11); storage.markViewed(7, 12); storage.markAudioPlayed(7, 12); storage.saveRouteState({ id: 7, name: 'Testweg' }, 'paused', 23, [11], [12], [12]); const route = storage.loadRoute(7); assert.equal(route.routeState, 'paused'); assert.equal(route.routeProgressIndex, 23); assert.deepEqual([...route.visitedPoiIds], [11]); assert.deepEqual([...route.viewedPoiIds], [12]); assert.deepEqual([...route.playedAudioPoiIds], [12]); storage.setProgressStorageEnabled(false); assert.equal(storage.isProgressStorageEnabled(), false); assert.equal(localStorage.getItem(storage.PROGRESS_KEY), null); }); test('route progress older than 24 hours is removed with visible loop progress', async () => { const { storage, localStorage } = await loadModule(); storage.setProgressStorageEnabled(true); const oldTimestamp = new Date(Date.now() - storage.MAX_PROGRESS_AGE_MS - 1000).toISOString(); const freshTimestamp = new Date().toISOString(); localStorage.setItem(storage.PROGRESS_KEY, JSON.stringify({ version: 1, currentRouteId: 1, routes: { 1: { routeId: 1, routeName: 'Alt', updatedAt: oldTimestamp }, 2: { routeId: 2, routeName: 'Neu', updatedAt: freshTimestamp } } })); const updates = []; const result = await storage.cleanupExpired((removed, total) => updates.push(`${removed} / ${total}`)); assert.equal(result.removed, 1); assert.equal(result.total, 1); assert.deepEqual(updates, ['0 / 1', '1 / 1']); assert.equal(storage.loadRoute(1), null); assert.equal(storage.loadRoute(2).routeName, 'Neu'); });