import { describe, it, expect, beforeEach, vi } from 'vitest'; import { TokenStorage } from './tokenStorage'; // Mock localStorage const localStorageMock = (() => { let store: Record = {}; 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(); }); 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); 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); expect(localStorageMock.getItem).toHaveBeenCalledWith( 'veza_access_token', ); }); it('should return null if access token does not exist', () => { const result = TokenStorage.getAccessToken(); expect(result).toBeNull(); 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); expect(localStorageMock.getItem).toHaveBeenCalledWith( 'veza_refresh_token', ); }); it('should return null if refresh token does not exist', () => { const result = TokenStorage.getRefreshToken(); expect(result).toBeNull(); 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(); 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(); }); }); });