/** * Unit tests for the persisted web-session storage helpers (TECH-1468). * * An in-memory storage stub is injected — no browser, no jsdom. Each test * builds its own fixtures inline. */ import { describe, expect, it } from 'bun:test'; import { clearStoredWebSession, readStoredWebSession, STORED_WEB_SESSION_VERSION, WEB_SESSION_STORAGE_KEY_PREFIX, writeStoredWebSession, type StoredWebSession, type WebSessionStorageLike, } from '../web-app-session.service'; interface MockStorage extends WebSessionStorageLike { dump(): Map; } const buildMockStorage = (initialEntries?: Record): MockStorage => { const entries = new Map(Object.entries(initialEntries ?? {})); return { getItem: (key: string) => entries.get(key) ?? null, setItem: (key: string, value: string) => { entries.set(key, value); }, removeItem: (key: string) => { entries.delete(key); }, dump: () => entries, }; }; const URL_ID = 'amco-5119/office-remote'; const STORAGE_KEY = `${WEB_SESSION_STORAGE_KEY_PREFIX}${URL_ID}`; const buildRecord = (overrides?: Partial): StoredWebSession => ({ v: overrides?.v ?? STORED_WEB_SESSION_VERSION, refreshToken: overrides?.refreshToken ?? 'grant-token-1', sessionDeadlineMs: overrides?.sessionDeadlineMs ?? Date.now() + 3600 * 1000, urlId: overrides?.urlId ?? URL_ID, savedAt: overrides?.savedAt ?? Date.now(), }); describe('stored web session helpers', () => { it('round-trips a record through write and read', () => { const storage = buildMockStorage(); const record = buildRecord(); expect(writeStoredWebSession(record, storage)).toBe(true); expect(readStoredWebSession(URL_ID, storage)).toEqual(record); }); it('returns null and clears a record written for a different urlId', () => { const storage = buildMockStorage({ [STORAGE_KEY]: JSON.stringify(buildRecord({ urlId: 'other-tenant/other-app' })), }); expect(readStoredWebSession(URL_ID, storage)).toBeNull(); expect(storage.dump().has(STORAGE_KEY)).toBe(false); }); it('returns null and clears a record past its session deadline', () => { const storage = buildMockStorage({ [STORAGE_KEY]: JSON.stringify(buildRecord({ sessionDeadlineMs: Date.now() - 1000 })), }); expect(readStoredWebSession(URL_ID, storage)).toBeNull(); expect(storage.dump().has(STORAGE_KEY)).toBe(false); }); it('returns null and clears a malformed or wrong-version record', () => { const malformedStorage = buildMockStorage({ [STORAGE_KEY]: 'not-json{' }); expect(readStoredWebSession(URL_ID, malformedStorage)).toBeNull(); expect(malformedStorage.dump().has(STORAGE_KEY)).toBe(false); const wrongVersionStorage = buildMockStorage({ [STORAGE_KEY]: JSON.stringify(buildRecord({ v: 999 })), }); expect(readStoredWebSession(URL_ID, wrongVersionStorage)).toBeNull(); expect(wrongVersionStorage.dump().has(STORAGE_KEY)).toBe(false); }); it('write returns false when the storage write throws (quota, private mode)', () => { const storage = buildMockStorage(); storage.setItem = () => { throw new Error('QuotaExceededError'); }; expect(writeStoredWebSession(buildRecord(), storage)).toBe(false); }); it('helpers degrade to no-ops without storage', () => { expect(readStoredWebSession(URL_ID, null)).toBeNull(); expect(writeStoredWebSession(buildRecord(), null)).toBe(false); clearStoredWebSession(URL_ID, null); }); it('clearStoredWebSession removes only the record for its urlId', () => { const otherKey = `${WEB_SESSION_STORAGE_KEY_PREFIX}other-tenant/other-app`; const storage = buildMockStorage({ [STORAGE_KEY]: JSON.stringify(buildRecord()), [otherKey]: JSON.stringify(buildRecord({ urlId: 'other-tenant/other-app' })), }); clearStoredWebSession(URL_ID, storage); expect(storage.dump().has(STORAGE_KEY)).toBe(false); expect(storage.dump().has(otherKey)).toBe(true); }); });