Files
rxminder/utils/__tests__/token.test.ts
2025-09-23 10:11:14 -07:00

104 lines
2.7 KiB
TypeScript

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'
);
});
});