143 lines
4.1 KiB
TypeScript
143 lines
4.1 KiB
TypeScript
/**
|
|
* @format
|
|
*/
|
|
|
|
import { configureStore } from '@reduxjs/toolkit';
|
|
import authSlice, { login, refreshToken, logout, updateAccessToken } from '../src/modules/auth/store/authSlice';
|
|
import { authAPI } from '../src/modules/auth/services/authAPI';
|
|
|
|
// Mock the authAPI
|
|
jest.mock('../src/modules/auth/services/authAPI', () => ({
|
|
authAPI: {
|
|
login: jest.fn(),
|
|
refreshToken: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
const mockAuthAPI = authAPI as jest.Mocked<typeof authAPI>;
|
|
|
|
describe('Auth Slice', () => {
|
|
let store: ReturnType<typeof configureStore>;
|
|
|
|
beforeEach(() => {
|
|
store = configureStore({
|
|
reducer: {
|
|
auth: authSlice.reducer,
|
|
},
|
|
});
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('refreshToken', () => {
|
|
it('should handle successful token refresh', async () => {
|
|
const mockRefreshResponse = {
|
|
data: {
|
|
status: 'success',
|
|
message: 'Token refreshed successfully',
|
|
data: {
|
|
accessToken: 'new-access-token',
|
|
},
|
|
timestamp: '2024-01-01T00:00:00Z',
|
|
},
|
|
};
|
|
|
|
mockAuthAPI.refreshToken.mockResolvedValue(mockRefreshResponse);
|
|
|
|
const result = await store.dispatch(refreshToken('valid-refresh-token'));
|
|
|
|
expect(refreshToken.fulfilled.match(result)).toBe(true);
|
|
expect(store.getState().auth.accessToken).toBe('new-access-token');
|
|
expect(store.getState().auth.error).toBeNull();
|
|
});
|
|
|
|
it('should handle refresh token failure and logout user', async () => {
|
|
const mockErrorResponse = {
|
|
response: {
|
|
data: {
|
|
status: 'error',
|
|
message: 'Invalid refresh token',
|
|
errorCode: 'INVALID_REFRESH',
|
|
timestamp: '2024-01-01T00:00:00Z',
|
|
},
|
|
},
|
|
};
|
|
|
|
mockAuthAPI.refreshToken.mockRejectedValue(mockErrorResponse);
|
|
|
|
// Set initial state with user logged in
|
|
store.dispatch(updateAccessToken('old-access-token'));
|
|
store.dispatch({
|
|
type: 'auth/login/fulfilled',
|
|
payload: {
|
|
accessToken: 'old-access-token',
|
|
refreshToken: 'valid-refresh-token',
|
|
user: {
|
|
id: 1,
|
|
uuid: 'test-uuid',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
role: 'user',
|
|
},
|
|
},
|
|
});
|
|
|
|
const result = await store.dispatch(refreshToken('invalid-refresh-token'));
|
|
|
|
expect(refreshToken.rejected.match(result)).toBe(true);
|
|
expect(store.getState().auth.isAuthenticated).toBe(false);
|
|
expect(store.getState().auth.user).toBeNull();
|
|
expect(store.getState().auth.accessToken).toBeNull();
|
|
expect(store.getState().auth.refreshToken).toBeNull();
|
|
});
|
|
|
|
it('should handle network error during refresh', async () => {
|
|
mockAuthAPI.refreshToken.mockRejectedValue(new Error('Network error'));
|
|
|
|
const result = await store.dispatch(refreshToken('valid-refresh-token'));
|
|
|
|
expect(refreshToken.rejected.match(result)).toBe(true);
|
|
expect(store.getState().auth.error).toBe('Network error');
|
|
});
|
|
});
|
|
|
|
describe('updateAccessToken', () => {
|
|
it('should update access token', () => {
|
|
const newToken = 'new-access-token';
|
|
store.dispatch(updateAccessToken(newToken));
|
|
|
|
expect(store.getState().auth.accessToken).toBe(newToken);
|
|
});
|
|
});
|
|
|
|
describe('logout', () => {
|
|
it('should clear all auth state', () => {
|
|
// Set initial state
|
|
store.dispatch(updateAccessToken('access-token'));
|
|
store.dispatch({
|
|
type: 'auth/login/fulfilled',
|
|
payload: {
|
|
accessToken: 'access-token',
|
|
refreshToken: 'refresh-token',
|
|
user: {
|
|
id: 1,
|
|
uuid: 'test-uuid',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
role: 'user',
|
|
},
|
|
},
|
|
});
|
|
|
|
// Dispatch logout
|
|
store.dispatch(logout());
|
|
|
|
const state = store.getState().auth;
|
|
expect(state.user).toBeNull();
|
|
expect(state.accessToken).toBeNull();
|
|
expect(state.refreshToken).toBeNull();
|
|
expect(state.isAuthenticated).toBe(false);
|
|
expect(state.error).toBeNull();
|
|
});
|
|
});
|
|
});
|