import { describe, it, expect, beforeEach, vi } from 'vitest'; import { mount } from '@vue/test-utils'; import { createPinia, setActivePinia } from 'pinia'; import { createVuetify } from 'vuetify'; vi.mock('../../resources/js/api/auth', () => ({ updateProfile: vi.fn(), })); vi.mock('../../resources/js/api/client', () => ({ apiClient: {}, ensureCsrfCookie: vi.fn(), extractValidationErrors: vi.fn(() => null), extractErrorMessage: vi.fn((_e, fallback) => fallback ?? 'Произошла ошибка.'), extractRateLimitRetry: vi.fn(() => null), })); import * as authApi from '../../resources/js/api/auth'; import ProfileTab from '../../resources/js/views/settings/ProfileTab.vue'; import { useAuthStore } from '../../resources/js/stores/auth'; import type { AuthUser } from '../../resources/js/api/auth'; const vuetify = createVuetify(); const mockUser: AuthUser = { id: 1, email: 'ivan@example.ru', first_name: 'Иван', last_name: 'Петров', phone: '+7 916 000-00-00', timezone: 'Europe/Moscow', tenant_id: 1, totp_enabled: false, last_login_at: null, }; const factory = (user: AuthUser | null = mockUser) => { setActivePinia(createPinia()); const auth = useAuthStore(); auth.user = user; return mount(ProfileTab, { global: { plugins: [vuetify] } }); }; describe('ProfileTab.vue', () => { beforeEach(() => { vi.clearAllMocks(); }); it('подставляет имя/фамилию/телефон/тайм-зону из auth-store', () => { const wrapper = factory(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = wrapper.vm as any; expect(vm.firstName).toBe('Иван'); expect(vm.lastName).toBe('Петров'); expect(vm.phone).toBe('+7 916 000-00-00'); expect(vm.timezone).toBe('Europe/Moscow'); }); it('save() вызывает updateProfile с payload и показывает успех', async () => { (authApi.updateProfile as ReturnType).mockResolvedValue({ ...mockUser, first_name: 'Пётр', }); const wrapper = factory(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = wrapper.vm as any; vm.firstName = 'Пётр'; await vm.save(); expect(authApi.updateProfile).toHaveBeenCalledWith({ first_name: 'Пётр', last_name: 'Петров', phone: '+7 916 000-00-00', timezone: 'Europe/Moscow', }); expect(vm.saveSuccess).toBe(true); expect(vm.saveError).toBe(null); }); it('save() с пустым phone отправляет null', async () => { (authApi.updateProfile as ReturnType).mockResolvedValue(mockUser); const wrapper = factory(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = wrapper.vm as any; vm.phone = ' '; await vm.save(); expect(authApi.updateProfile).toHaveBeenCalledWith(expect.objectContaining({ phone: null })); }); it('save() показывает ошибку при reject', async () => { (authApi.updateProfile as ReturnType).mockRejectedValue(new Error('boom')); const wrapper = factory(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = wrapper.vm as any; await vm.save(); expect(vm.saveError).toBe('Не удалось сохранить профиль.'); expect(vm.saveSuccess).toBe(false); expect(vm.saving).toBe(false); }); it('resetForm() возвращает поля к значениям из store', async () => { const wrapper = factory(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = wrapper.vm as any; vm.firstName = 'Изменено'; vm.resetForm(); expect(vm.firstName).toBe('Иван'); }); });