Files
portal/app/tests/Frontend/auth-api.spec.ts
T
Дмитрий bacc7c5e24 feat: G1/SP3a фронт входа — регистрация + подтверждение почты
Переработка register под новый бэкенд SP1 (код на почту), новый ConfirmEmailView, капча-шов, роут /confirm-email. Проверено Playwright: register→код→confirm→dashboard, негатив, fallback email. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 23:33:26 +03:00

146 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, vi } from 'vitest';
vi.mock('../../resources/js/api/client', () => ({
apiClient: {
get: vi.fn(),
post: vi.fn(),
patch: vi.fn(),
delete: vi.fn(),
},
ensureCsrfCookie: vi.fn(),
}));
import {
login,
register,
me,
logout,
verifyTwoFactor,
useRecoveryCode,
twoFactorInit,
twoFactorConfirm,
twoFactorDisable,
twoFactorRegenerateRecoveryCodes,
forgotPassword,
resetPassword,
updateNotificationPreferences,
} from '../../resources/js/api/auth';
import { apiClient, ensureCsrfCookie } from '../../resources/js/api/client';
const FAKE_USER = {
id: 1,
email: 'demo@x.ru',
first_name: 'D',
last_name: 'U',
tenant_id: 1,
totp_enabled: false,
last_login_at: null,
};
describe('api/auth', () => {
beforeEach(() => vi.clearAllMocks());
it('login() POSTs /api/auth/login + calls ensureCsrfCookie + unwraps data', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { user: FAKE_USER, requires_2fa: false } });
const result = await login({ email: 'a@x.ru', password: 'pw' });
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/login', { email: 'a@x.ru', password: 'pw' });
expect(result.requires_2fa).toBe(false);
expect(result.user.email).toBe('demo@x.ru');
});
it('register() POSTs /api/auth/register с accept-флагами + captcha (G1/SP3a)', async () => {
vi.mocked(apiClient.post).mockResolvedValue({
data: { status: 'pending_email_confirm', email: 'a@x.ru', expires_at: '2026-06-18T12:00:00+00:00' },
});
await register({ email: 'a@x.ru', password: 'pw', accept_offer: true, accept_pdn: true, captcha_token: 'tok' });
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/register', {
email: 'a@x.ru',
password: 'pw',
accept_offer: true,
accept_pdn: true,
captcha_token: 'tok',
});
});
it('me() GETs /api/auth/me + unwraps data.user', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: { user: FAKE_USER } });
const result = await me();
expect(apiClient.get).toHaveBeenCalledWith('/api/auth/me');
expect(result.id).toBe(1);
});
it('logout() POSTs /api/auth/logout + ensureCsrfCookie', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: {} });
await logout();
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/logout');
});
it('verifyTwoFactor() POSTs /api/auth/2fa/verify с code', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { user: FAKE_USER, requires_2fa: false } });
await verifyTwoFactor('123456');
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/2fa/verify', { code: '123456' });
});
it('useRecoveryCode() POSTs /api/auth/2fa/recovery-use с code + возвращает remaining', async () => {
vi.mocked(apiClient.post).mockResolvedValue({
data: { user: FAKE_USER, requires_2fa: false, recovery_codes_remaining: 7 },
});
const r = await useRecoveryCode('xxxx-yyyy');
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/2fa/recovery-use', { code: 'xxxx-yyyy' });
expect(r.recovery_codes_remaining).toBe(7);
});
it('twoFactorInit() POSTs /api/2fa/init + возвращает secret+qr_url', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { secret: 'JBSW', qr_url: 'otpauth://...' } });
const r = await twoFactorInit();
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/init');
expect(r.secret).toBe('JBSW');
});
it('twoFactorConfirm() POSTs /api/2fa/confirm с code', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { recovery_codes: ['a', 'b'], message: 'ok' } });
await twoFactorConfirm('000000');
expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/confirm', { code: '000000' });
});
it('twoFactorDisable() POSTs /api/2fa/disable с паролем', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'disabled' } });
await twoFactorDisable('current-pw');
expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/disable', { password: 'current-pw' });
});
it('twoFactorRegenerateRecoveryCodes() POSTs /api/2fa/regenerate-recovery-codes', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { recovery_codes: ['x', 'y', 'z'], message: 'ok' } });
const r = await twoFactorRegenerateRecoveryCodes('pw');
expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/regenerate-recovery-codes', { password: 'pw' });
expect(r.recovery_codes.length).toBe(3);
});
it('forgotPassword() POSTs /api/auth/forgot с email', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'sent' } });
await forgotPassword('a@x.ru');
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/forgot', { email: 'a@x.ru' });
});
it('resetPassword() POSTs /api/auth/reset-password с token+email+password', async () => {
vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'reset' } });
const payload = { token: 't', email: 'a@x.ru', password: 'newpw', password_confirmation: 'newpw' };
await resetPassword(payload);
expect(apiClient.post).toHaveBeenCalledWith('/api/auth/reset-password', payload);
});
it('updateNotificationPreferences() PATCH /api/auth/me/notification-preferences', async () => {
vi.mocked(apiClient.patch).mockResolvedValue({ data: { user: FAKE_USER } });
const payload = { prefs: { new_lead: { inapp: true } }, sound_enabled: false };
await updateNotificationPreferences(payload);
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
expect(apiClient.patch).toHaveBeenCalledWith('/api/auth/me/notification-preferences', payload);
});
});