veza/apps/web/src/features/auth/services/authService.test.ts
senke 670282989b chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:39:18 +01:00

338 lines
9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AxiosError } from 'axios';
import {
login,
register,
logout,
refreshToken,
requestPasswordReset,
resetPassword,
verifyEmail,
resendVerificationEmail,
type AuthResponse,
} from './authService';
import { apiClient } from '@/services/api/client';
// Mock apiClient
vi.mock('@/services/api/client', () => ({
apiClient: {
post: vi.fn(),
get: vi.fn(),
},
}));
// Mock handleApiServiceError - it always throws, so we let it through
// but need the real implementation for error handling tests
vi.mock('@/utils/serviceErrorHandler', async () => {
const actual = await vi.importActual('@/utils/serviceErrorHandler');
return actual;
});
const mockedApiClient = apiClient as {
post: ReturnType<typeof vi.fn>;
get: ReturnType<typeof vi.fn>;
};
describe('authService', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('login', () => {
it('should successfully login and return auth response', async () => {
const mockResponse: AuthResponse = {
user: {
id: '1',
email: 'test@example.com',
username: 'testuser',
},
token: {
access_token: 'access-token-123',
refresh_token: 'refresh-token-123',
expires_in: 3600,
},
};
mockedApiClient.post.mockResolvedValue({ data: mockResponse });
const result = await login({
email: 'test@example.com',
password: 'password123',
});
expect(result).toEqual(mockResponse);
expect(mockedApiClient.post).toHaveBeenCalledWith('/auth/login', {
email: 'test@example.com',
password: 'password123',
});
});
it('should throw on login failure', async () => {
const mockError = new AxiosError('Login failed');
mockError.response = {
status: 401,
data: { error: 'Invalid credentials' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
login({
email: 'test@example.com',
password: 'wrongpassword',
}),
).rejects.toThrow();
});
it('should throw on network errors', async () => {
const mockError = new AxiosError('Network Error');
mockError.request = {};
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
login({
email: 'test@example.com',
password: 'password123',
}),
).rejects.toThrow();
});
});
describe('register', () => {
it('should successfully register and return auth response', async () => {
const mockResponse: AuthResponse = {
user: {
id: '1',
email: 'newuser@example.com',
username: 'newuser',
},
token: {
access_token: 'access-token-123',
refresh_token: 'refresh-token-123',
expires_in: 3600,
},
};
mockedApiClient.post.mockResolvedValue({ data: mockResponse });
const result = await register({
email: 'newuser@example.com',
password: 'password123',
password_confirm: 'password123',
username: 'newuser',
});
expect(result).toEqual(mockResponse);
expect(mockedApiClient.post).toHaveBeenCalledWith('/auth/register', {
email: 'newuser@example.com',
password: 'password123',
password_confirm: 'password123',
username: 'newuser',
});
});
it('should throw on registration failure', async () => {
const mockError = new AxiosError('Registration failed');
mockError.response = {
status: 409,
data: { error: 'Email already exists' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
register({
email: 'existing@example.com',
password: 'password123',
password_confirm: 'password123',
username: 'existinguser',
}),
).rejects.toThrow();
});
});
describe('logout', () => {
it('should successfully logout', async () => {
mockedApiClient.post.mockResolvedValue({ data: {} });
await logout();
expect(mockedApiClient.post).toHaveBeenCalledWith('/auth/logout');
});
it('should throw on logout failure', async () => {
const mockError = new AxiosError('Logout failed');
mockError.response = {
status: 500,
data: { error: 'Internal server error' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(logout()).rejects.toThrow();
});
});
describe('refreshToken', () => {
it('should successfully refresh token and return auth response', async () => {
const mockResponse: AuthResponse = {
user: {
id: '1',
email: 'test@example.com',
username: 'testuser',
},
token: {
access_token: 'new-access-token-123',
refresh_token: 'new-refresh-token-123',
expires_in: 3600,
},
};
mockedApiClient.post.mockResolvedValue({ data: mockResponse });
const result = await refreshToken('refresh-token-123');
expect(result).toEqual(mockResponse);
expect(mockedApiClient.post).toHaveBeenCalledWith('/auth/refresh', {
refreshToken: 'refresh-token-123',
});
});
it('should throw on refresh failure', async () => {
const mockError = new AxiosError('Refresh failed');
mockError.response = {
status: 401,
data: { error: 'Invalid refresh token' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(refreshToken('invalid-token')).rejects.toThrow();
});
});
describe('requestPasswordReset', () => {
it('should successfully request password reset', async () => {
mockedApiClient.post.mockResolvedValue({ data: {} });
await requestPasswordReset({
email: 'test@example.com',
});
expect(mockedApiClient.post).toHaveBeenCalledWith(
'/auth/password/reset-request',
{
email: 'test@example.com',
},
);
});
it('should throw on request failure', async () => {
const mockError = new AxiosError('Request failed');
mockError.response = {
status: 404,
data: { error: 'User not found' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
requestPasswordReset({
email: 'nonexistent@example.com',
}),
).rejects.toThrow();
});
});
describe('resetPassword', () => {
it('should successfully reset password', async () => {
mockedApiClient.post.mockResolvedValue({ data: {} });
await resetPassword({
token: 'reset-token-123',
password: 'newpassword123',
confirmPassword: 'newpassword123',
});
expect(mockedApiClient.post).toHaveBeenCalledWith(
'/auth/password/reset',
{
token: 'reset-token-123',
password: 'newpassword123',
},
);
});
it('should throw on reset failure', async () => {
const mockError = new AxiosError('Reset failed');
mockError.response = {
status: 400,
data: { error: 'Invalid or expired token' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
resetPassword({
token: 'invalid-token',
password: 'newpassword123',
confirmPassword: 'newpassword123',
}),
).rejects.toThrow();
});
});
describe('verifyEmail', () => {
it('should successfully verify email', async () => {
mockedApiClient.get.mockResolvedValue({ data: {} });
await verifyEmail('verification-token-123');
expect(mockedApiClient.get).toHaveBeenCalledWith(
'/auth/verify-email?token=verification-token-123',
);
});
it('should throw on verification failure', async () => {
const mockError = new AxiosError('Verification failed');
mockError.response = {
status: 400,
data: { error: 'Invalid or expired token' },
} as any;
mockedApiClient.get.mockRejectedValue(mockError);
await expect(verifyEmail('invalid-token')).rejects.toThrow();
});
});
describe('resendVerificationEmail', () => {
it('should successfully resend verification email', async () => {
mockedApiClient.post.mockResolvedValue({ data: {} });
await resendVerificationEmail('test@example.com');
expect(mockedApiClient.post).toHaveBeenCalledWith(
'/auth/resend-verification',
{
email: 'test@example.com',
},
);
});
it('should throw on resend failure', async () => {
const mockError = new AxiosError('Resend failed');
mockError.response = {
status: 429,
data: { error: 'Too many requests' },
} as any;
mockedApiClient.post.mockRejectedValue(mockError);
await expect(
resendVerificationEmail('test@example.com'),
).rejects.toThrow();
});
});
});