/** * Prüft die beiden Grenzen der Sitzung. * * Beide sind eine Zusage an den Betreiber, und beide lassen sich mit einer * falschen Zeile still aushebeln: Wer beim Vermerken einer Interaktion die * harte Obergrenze mitverschiebt, macht aus „30 Minuten" ein „unbegrenzt, * solange die Maus wackelt". */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { SESSION_IDLE_MS, SESSION_MAXIMUM_MS, clearStoredSession, readStoredSession, remainingSessionMs, touchStoredSession, writeStoredSession, } from './sessionStore'; const tokenPair = { access_token: 'zugriff', refresh_token: 'erneuerung', // secretscan:erlaubt — Testwert, kein Geheimnis access_expires_at: '', refresh_expires_at: '', }; describe('Sitzungsablage', () => { beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-08-18T10:00:00Z')); clearStoredSession(); }); afterEach(() => { vi.useRealTimers(); }); it('überlebt ein Neuladen innerhalb der Frist', () => { writeStoredSession(tokenPair); // Ein Neuladen bedeutet: neuer Arbeitsspeicher, gleiche Ablage. const resumed = readStoredSession(); expect(resumed).not.toBeNull(); expect(resumed?.accessToken).toBe('zugriff'); }); it('endet nach der harten Obergrenze, auch bei ständiger Interaktion', () => { writeStoredSession(tokenPair); // Alle fünf Minuten eine Interaktion — sieben Mal, also 35 Minuten. for (let step = 0; step < 7; step += 1) { vi.advanceTimersByTime(5 * 60 * 1000); touchStoredSession(); } // Die Untätigkeitsgrenze wäre nie erreicht worden. Die Obergrenze schon. expect(readStoredSession()).toBeNull(); }); it('endet bei Untätigkeit vor der Obergrenze', () => { writeStoredSession(tokenPair); vi.advanceTimersByTime(SESSION_IDLE_MS + 1000); expect(readStoredSession()).toBeNull(); }); it('verschiebt die Obergrenze durch eine Interaktion nicht', () => { const created = writeStoredSession(tokenPair); vi.advanceTimersByTime(60 * 1000); const touched = touchStoredSession(); expect(touched?.absoluteExpiryMs).toBe(created.absoluteExpiryMs); expect(touched?.lastActivityMs).toBeGreaterThan(created.lastActivityMs); }); it('nennt die frühere der beiden Grenzen als Restzeit', () => { const created = writeStoredSession(tokenPair); // Direkt nach der Anmeldung fallen beide Grenzen zusammen. expect(remainingSessionMs(created)).toBe(SESSION_MAXIMUM_MS); vi.advanceTimersByTime(20 * 60 * 1000); const stillValid = readStoredSession(); expect(stillValid).not.toBeNull(); // Zehn Minuten bis zur Obergrenze, dreißig bis zur Untätigkeitsgrenze — // maßgeblich sind die zehn. expect(remainingSessionMs(stillValid!)).toBe(10 * 60 * 1000); }); it('verwirft einen unlesbaren Eintrag, statt ihn zu raten', () => { window.sessionStorage.setItem('syncova.session', '{kein gültiges json'); expect(readStoredSession()).toBeNull(); expect(window.sessionStorage.getItem('syncova.session')).toBeNull(); }); });