Files
portal/app/tests/Frontend/ProfileTab.spec.ts
T
Дмитрий 2c59a00714 refactor(settings): ProfileTab — document auth-guard assumption + tighten spec (review M1/M2)
Code-quality review of Task 2: documents why ProfileTab needs no
watch-resync of auth.user (router beforeEach awaits fetchMe before
requiresAuth navigation); tightens the save-error test to assert the
exact fallback message instead of mere truthiness.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:44:17 +03:00

111 lines
4.0 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';
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<typeof vi.fn>).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<typeof vi.fn>).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<typeof vi.fn>).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('Иван');
});
});