import { tokenStorage } from '../token'; import { logger } from '../../services/logging'; describe('tokenStorage', () => { const STORAGE_KEY = 'meds_auth_tokens'; const originalLocalStorageDescriptor = Object.getOwnPropertyDescriptor( window, 'localStorage' ); beforeEach(() => { jest.restoreAllMocks(); tokenStorage.clear(); window.localStorage.clear(); }); afterAll(() => { if (originalLocalStorageDescriptor) { Object.defineProperty( window, 'localStorage', originalLocalStorageDescriptor ); } }); it('persists tokens with a single storage key', () => { const tokens = { accessToken: 'access-123', refreshToken: 'refresh-789' }; tokenStorage.save(tokens); expect(window.localStorage.getItem(STORAGE_KEY)).toEqual( JSON.stringify({ accessToken: 'access-123', refreshToken: 'refresh-789', }) ); expect(tokenStorage.getAccessToken()).toBe('access-123'); }); it('clears tokens from storage and cache', () => { tokenStorage.save({ accessToken: 'access-123', refreshToken: 'refresh-789', }); tokenStorage.clear(); expect(window.localStorage.getItem(STORAGE_KEY)).toBeNull(); expect(tokenStorage.getTokens()).toBeNull(); expect(tokenStorage.getAccessToken()).toBeNull(); }); it('handles corrupted storage values by clearing and logging', () => { window.localStorage.setItem(STORAGE_KEY, 'not json'); const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {}); expect(tokenStorage.getTokens()).toBeNull(); expect(window.localStorage.getItem(STORAGE_KEY)).toBeNull(); expect(warnSpy).toHaveBeenCalledWith( 'Failed to parse stored tokens, clearing cache', 'AUTH_TOKENS', expect.any(Error) ); }); it('falls back to in-memory storage when localStorage is unavailable', () => { const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {}); const error = new Error('blocked'); Object.defineProperty(window, 'localStorage', { configurable: true, get: () => { throw error; }, }); tokenStorage.clear(); tokenStorage.save({ accessToken: 'access-only' }); expect(tokenStorage.getAccessToken()).toBe('access-only'); expect(warnSpy).toHaveBeenCalledWith( 'Token storage fallback to memory', 'AUTH_TOKENS', error ); if (originalLocalStorageDescriptor) { Object.defineProperty( window, 'localStorage', originalLocalStorageDescriptor ); } }); it('throws when attempting to save without an access token', () => { expect(() => tokenStorage.save({ accessToken: '' })).toThrow( 'Token payload must include an access token' ); }); });