veza/apps/web/src/services/tokenStorage.test.ts

195 lines
5.8 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { TokenStorage, _resetTokenMemory } from './tokenStorage';
// Mock localStorage
const localStorageMock = (() => {
let store: Record<string, string> = {};
return {
getItem: vi.fn((key: string) => store[key] || null),
setItem: vi.fn((key: string, value: string) => {
store[key] = value.toString();
}),
removeItem: vi.fn((key: string) => {
delete store[key];
}),
clear: vi.fn(() => {
store = {};
}),
};
})();
Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
writable: true,
});
describe('TokenStorage', () => {
beforeEach(() => {
localStorageMock.clear();
vi.clearAllMocks();
// SECURITY: Réinitialiser la mémoire pour chaque test
_resetTokenMemory();
});
describe('setTokens', () => {
it('should store access token and refresh token in localStorage', () => {
const accessToken = 'test-access-token';
const refreshToken = 'test-refresh-token';
TokenStorage.setTokens(accessToken, refreshToken);
2025-12-13 02:34:34 +00:00
expect(localStorageMock.setItem).toHaveBeenCalledWith(
'veza_access_token',
accessToken,
);
expect(localStorageMock.setItem).toHaveBeenCalledWith(
'veza_refresh_token',
refreshToken,
);
expect(localStorageMock.setItem).toHaveBeenCalledTimes(2);
});
it('should overwrite existing tokens when called multiple times', () => {
TokenStorage.setTokens('token1', 'refresh1');
TokenStorage.setTokens('token2', 'refresh2');
expect(localStorageMock.setItem).toHaveBeenCalledTimes(4);
// Check that the last two calls set the new tokens
const calls = localStorageMock.setItem.mock.calls;
expect(calls[2]).toEqual(['veza_access_token', 'token2']);
expect(calls[3]).toEqual(['veza_refresh_token', 'refresh2']);
});
});
describe('getAccessToken', () => {
it('should return access token from localStorage', () => {
const accessToken = 'test-access-token';
localStorageMock.setItem('veza_access_token', accessToken);
const result = TokenStorage.getAccessToken();
expect(result).toBe(accessToken);
2025-12-13 02:34:34 +00:00
expect(localStorageMock.getItem).toHaveBeenCalledWith(
'veza_access_token',
);
});
it('should return null if access token does not exist', () => {
const result = TokenStorage.getAccessToken();
expect(result).toBeNull();
2025-12-13 02:34:34 +00:00
expect(localStorageMock.getItem).toHaveBeenCalledWith(
'veza_access_token',
);
});
});
describe('getRefreshToken', () => {
it('should return refresh token from localStorage', () => {
const refreshToken = 'test-refresh-token';
localStorageMock.setItem('veza_refresh_token', refreshToken);
const result = TokenStorage.getRefreshToken();
expect(result).toBe(refreshToken);
2025-12-13 02:34:34 +00:00
expect(localStorageMock.getItem).toHaveBeenCalledWith(
'veza_refresh_token',
);
});
it('should return null if refresh token does not exist', () => {
const result = TokenStorage.getRefreshToken();
expect(result).toBeNull();
2025-12-13 02:34:34 +00:00
expect(localStorageMock.getItem).toHaveBeenCalledWith(
'veza_refresh_token',
);
});
});
describe('clearTokens', () => {
it('should remove both tokens from localStorage', () => {
TokenStorage.setTokens('access-token', 'refresh-token');
localStorageMock.setItem.mockClear();
TokenStorage.clearTokens();
2025-12-13 02:34:34 +00:00
expect(localStorageMock.removeItem).toHaveBeenCalledWith(
'veza_access_token',
);
expect(localStorageMock.removeItem).toHaveBeenCalledWith(
'veza_refresh_token',
);
expect(localStorageMock.removeItem).toHaveBeenCalledTimes(2);
});
it('should not throw error if tokens do not exist', () => {
expect(() => TokenStorage.clearTokens()).not.toThrow();
expect(localStorageMock.removeItem).toHaveBeenCalledTimes(2);
});
});
describe('hasTokens', () => {
it('should return true when both tokens exist', () => {
TokenStorage.setTokens('access-token', 'refresh-token');
const result = TokenStorage.hasTokens();
expect(result).toBe(true);
});
it('should return false when access token is missing', () => {
localStorageMock.setItem('veza_refresh_token', 'refresh-token');
const result = TokenStorage.hasTokens();
expect(result).toBe(false);
});
it('should return false when refresh token is missing', () => {
localStorageMock.setItem('veza_access_token', 'access-token');
const result = TokenStorage.hasTokens();
expect(result).toBe(false);
});
it('should return false when both tokens are missing', () => {
const result = TokenStorage.hasTokens();
expect(result).toBe(false);
});
it('should return false when tokens are empty strings', () => {
localStorageMock.setItem('veza_access_token', '');
localStorageMock.setItem('veza_refresh_token', '');
const result = TokenStorage.hasTokens();
expect(result).toBe(false);
});
});
describe('integration', () => {
it('should work correctly with full token lifecycle', () => {
// Initially no tokens
expect(TokenStorage.hasTokens()).toBe(false);
expect(TokenStorage.getAccessToken()).toBeNull();
expect(TokenStorage.getRefreshToken()).toBeNull();
// Store tokens
TokenStorage.setTokens('access-123', 'refresh-456');
expect(TokenStorage.hasTokens()).toBe(true);
expect(TokenStorage.getAccessToken()).toBe('access-123');
expect(TokenStorage.getRefreshToken()).toBe('refresh-456');
// Clear tokens
TokenStorage.clearTokens();
expect(TokenStorage.hasTokens()).toBe(false);
expect(TokenStorage.getAccessToken()).toBeNull();
expect(TokenStorage.getRefreshToken()).toBeNull();
});
});
});