import { describe, it, expect, vi, beforeEach } from 'vitest'; import { TokenStorage } from './tokenStorage'; // Mock dependencies vi.mock('./tokenStorage'); const mockTokenStorage = vi.mocked(TokenStorage); // Mock axios const mockPost = vi.fn(); const mockAxiosInstance = { post: mockPost, get: vi.fn(), put: vi.fn(), delete: vi.fn(), patch: vi.fn(), interceptors: { request: { use: vi.fn(), eject: vi.fn() }, response: { use: vi.fn(), eject: vi.fn() }, }, }; vi.mock('axios', () => ({ default: { create: vi.fn(() => mockAxiosInstance), }, })); // Import after mocks are set up import { refreshToken } from './tokenRefresh'; describe('tokenRefresh', () => { beforeEach(() => { vi.clearAllMocks(); mockPost.mockReset(); }); describe('refreshToken', () => { it('should refresh token successfully', async () => { const mockRefreshToken = 'test-refresh-token'; const mockAccessToken = 'new-access-token'; const mockNewRefreshToken = 'new-refresh-token'; // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); // Mock axios post response mockPost.mockResolvedValue({ data: { access_token: mockAccessToken, refresh_token: mockNewRefreshToken, expires_in: 900, }, }); await refreshToken(); // Verify refresh token was retrieved expect(mockTokenStorage.getRefreshToken).toHaveBeenCalledTimes(1); // Verify API call was made with correct parameters expect(mockPost).toHaveBeenCalledWith('/auth/refresh', { refresh_token: mockRefreshToken, }); // Verify tokens were updated expect(mockTokenStorage.setTokens).toHaveBeenCalledWith( mockAccessToken, mockNewRefreshToken, ); // Verify clearTokens was not called on success expect(mockTokenStorage.clearTokens).not.toHaveBeenCalled(); }); it('should throw error if no refresh token available', async () => { // Mock TokenStorage.getRefreshToken to return null mockTokenStorage.getRefreshToken.mockReturnValue(null); await expect(refreshToken()).rejects.toThrow( 'No refresh token available', ); // Verify API was not called expect(mockPost).not.toHaveBeenCalled(); // Verify tokens were not updated expect(mockTokenStorage.setTokens).not.toHaveBeenCalled(); }); it('should clear tokens and throw error on API failure', async () => { const mockRefreshToken = 'test-refresh-token'; const apiError = new Error('API Error'); // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); mockPost.mockRejectedValue(apiError); await expect(refreshToken()).rejects.toThrow('API Error'); // Verify API call was made expect(mockPost).toHaveBeenCalledWith('/auth/refresh', { refresh_token: mockRefreshToken, }); // Verify tokens were cleared on error expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1); // Verify tokens were not updated expect(mockTokenStorage.setTokens).not.toHaveBeenCalled(); }); it('should clear tokens on 401 Unauthorized error', async () => { const mockRefreshToken = 'test-refresh-token'; const axiosError = { response: { status: 401, data: { error: 'Invalid refresh token' }, }, isAxiosError: true, }; // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); mockPost.mockRejectedValue(axiosError); await expect(refreshToken()).rejects.toEqual(axiosError); // Verify tokens were cleared on 401 error expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1); }); it('should clear tokens on 400 Bad Request error', async () => { const mockRefreshToken = 'test-refresh-token'; const axiosError = { response: { status: 400, data: { error: 'Invalid request' }, }, isAxiosError: true, }; // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); mockPost.mockRejectedValue(axiosError); await expect(refreshToken()).rejects.toEqual(axiosError); // Verify tokens were cleared on error expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1); }); it('should clear tokens on network error', async () => { const mockRefreshToken = 'test-refresh-token'; const networkError = new Error('Network Error'); // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); mockPost.mockRejectedValue(networkError); await expect(refreshToken()).rejects.toThrow('Network Error'); // Verify tokens were cleared on error expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1); }); it('should update tokens with new values from API response', async () => { const mockRefreshToken = 'old-refresh-token'; const newAccessToken = 'updated-access-token'; const newRefreshToken = 'updated-refresh-token'; // Mock TokenStorage.getRefreshToken mockTokenStorage.getRefreshToken.mockReturnValue(mockRefreshToken); mockPost.mockResolvedValue({ data: { access_token: newAccessToken, refresh_token: newRefreshToken, expires_in: 900, }, }); await refreshToken(); // Verify tokens were updated with new values expect(mockTokenStorage.setTokens).toHaveBeenCalledWith( newAccessToken, newRefreshToken, ); }); it('should handle empty refresh token string', async () => { // Mock TokenStorage.getRefreshToken to return empty string mockTokenStorage.getRefreshToken.mockReturnValue(''); await expect(refreshToken()).rejects.toThrow( 'No refresh token available', ); // Verify API was not called expect(mockPost).not.toHaveBeenCalled(); }); }); });