import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createVuetify } from 'vuetify';
import axios from 'axios';
vi.mock('axios');
import ProjectsView from '../../resources/js/views/ProjectsView.vue';
/**
* Инцидент 14.07.2026: клиент ЧЕТЫРЕ раза подряд пытался удалить проект из меню карточки
* и каждый раз получал молчание — сервер отвечал «Нельзя удалить проект: по нему есть
* сделки. Поставьте приём на паузу», а фронт ронял этот ответ в никуда (store.del без
* catch, глобального перехватчика нет). Человек так и ушёл, ничего не поняв.
*
* Теперь причина показывается прямо там, где он нажал, и предлагается выход — пауза.
*/
const BLOCKED_MESSAGE = 'Нельзя удалить проект: по нему есть сделки. Поставьте приём на паузу, чтобы скрыть проект из работы.';
const factory = () =>
mount(ProjectsView, {
global: {
plugins: [createVuetify()],
stubs: {
VDialog: {
template: '
',
props: ['modelValue'],
},
NewProjectDialog: true,
EditProjectDialog: true,
},
},
});
function mockProjects() {
(axios.get as unknown as ReturnType).mockResolvedValue({
data: {
data: [
{
id: 46,
name: 'дентал',
signal_type: 'call',
signal_identifier: '79221364286',
daily_limit_target: 15,
delivered_today: 0,
is_active: false,
sync_status: 'ok',
},
],
meta: { total: 1, current_page: 1, per_page: 20 },
},
});
}
function mockDeleteBlocked() {
(axios.delete as unknown as ReturnType).mockRejectedValue({
response: { status: 422, data: { errors: { project: [BLOCKED_MESSAGE] } } },
});
}
describe('ProjectsView — удаление проекта со сделками', () => {
beforeEach(() => {
setActivePinia(createPinia());
vi.clearAllMocks();
});
it('показывает причину отказа, а не молчит', async () => {
mockProjects();
mockDeleteBlocked();
const wrapper = factory();
await flushPromises();
wrapper.findComponent({ name: 'ProjectCard' }).vm.$emit('delete', { id: 46, name: 'дентал', is_active: false });
await flushPromises();
expect(wrapper.text()).toContain('по нему есть сделки');
});
it('предлагает выход — кнопку «Поставить на паузу»', async () => {
mockProjects();
mockDeleteBlocked();
(axios.patch as unknown as ReturnType).mockResolvedValue({ data: { data: {} } });
const wrapper = factory();
await flushPromises();
wrapper.findComponent({ name: 'ProjectCard' }).vm.$emit('delete', { id: 46, name: 'дентал', is_active: true });
await flushPromises();
const pauseBtn = wrapper.findAll('button').find((b) => b.text().includes('Поставить на паузу'));
expect(pauseBtn).toBeDefined();
await pauseBtn!.trigger('click');
await flushPromises();
expect(axios.patch).toHaveBeenCalledWith('/api/projects/46/toggle-active', { is_active: false });
});
});