2026-05-15 21:37:40 +03:00
|
|
|
|
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();
|
2026-06-17 05:17:12 +03:00
|
|
|
|
expect(authApi.updateProfile).toHaveBeenCalledWith(expect.objectContaining({ phone: null }));
|
2026-05-15 21:37:40 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
2026-05-15 21:44:17 +03:00
|
|
|
|
expect(vm.saveError).toBe('Не удалось сохранить профиль.');
|
2026-05-15 21:37:40 +03:00
|
|
|
|
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('Иван');
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|