import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock apiClient vi.mock('../client', () => ({ default: { post: vi.fn(), get: vi.fn(), }, })); import { login, logout, getCurrentUser, refreshToken, masquerade, stopMasquerade, } from '../auth'; import apiClient from '../client'; describe('auth API', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('login', () => { it('sends credentials to login endpoint', async () => { const mockResponse = { data: { access: 'access-token', refresh: 'refresh-token', user: { id: 1, email: 'test@example.com' }, }, }; vi.mocked(apiClient.post).mockResolvedValue(mockResponse); const result = await login({ email: 'test@example.com', password: 'password' }); expect(apiClient.post).toHaveBeenCalledWith('/auth/login/', { email: 'test@example.com', password: 'password', }); expect(result).toEqual(mockResponse.data); }); it('returns MFA required response', async () => { const mockResponse = { data: { mfa_required: true, user_id: 1, mfa_methods: ['TOTP', 'SMS'], }, }; vi.mocked(apiClient.post).mockResolvedValue(mockResponse); const result = await login({ email: 'test@example.com', password: 'password' }); expect(result.mfa_required).toBe(true); expect(result.mfa_methods).toContain('TOTP'); }); }); describe('logout', () => { it('calls logout endpoint', async () => { vi.mocked(apiClient.post).mockResolvedValue({}); await logout(); expect(apiClient.post).toHaveBeenCalledWith('/auth/logout/'); }); }); describe('getCurrentUser', () => { it('fetches current user from API', async () => { const mockUser = { id: 1, email: 'test@example.com', name: 'Test User', role: 'owner', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockUser }); const result = await getCurrentUser(); expect(apiClient.get).toHaveBeenCalledWith('/auth/me/'); expect(result).toEqual(mockUser); }); }); describe('refreshToken', () => { it('sends refresh token to API', async () => { const mockResponse = { data: { access: 'new-access-token' } }; vi.mocked(apiClient.post).mockResolvedValue(mockResponse); const result = await refreshToken('old-refresh-token'); expect(apiClient.post).toHaveBeenCalledWith('/auth/refresh/', { refresh: 'old-refresh-token', }); expect(result.access).toBe('new-access-token'); }); }); describe('masquerade', () => { it('sends masquerade request with user_pk', async () => { const mockResponse = { data: { access: 'masq-access', refresh: 'masq-refresh', user: { id: 2, email: 'other@example.com' }, masquerade_stack: [{ user_id: 1, username: 'admin', role: 'superuser' }], }, }; vi.mocked(apiClient.post).mockResolvedValue(mockResponse); const result = await masquerade(2); expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/acquire/', { user_pk: 2, hijack_history: undefined, }); expect(result.masquerade_stack).toHaveLength(1); }); it('sends masquerade request with history', async () => { const history = [{ user_id: 1, username: 'admin', role: 'superuser' as const }]; vi.mocked(apiClient.post).mockResolvedValue({ data: {} }); await masquerade(2, history); expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/acquire/', { user_pk: 2, hijack_history: history, }); }); }); describe('stopMasquerade', () => { it('sends release request with masquerade stack', async () => { const stack = [{ user_id: 1, username: 'admin', role: 'superuser' as const }]; const mockResponse = { data: { access: 'orig-access', refresh: 'orig-refresh', user: { id: 1 }, masquerade_stack: [], }, }; vi.mocked(apiClient.post).mockResolvedValue(mockResponse); const result = await stopMasquerade(stack); expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/release/', { masquerade_stack: stack, }); expect(result.masquerade_stack).toHaveLength(0); }); }); });