Files
portal/app/tests/Frontend/DealDetailHero.spec.ts
T
Дмитрий c7fd90c08d fix(deals): читать проекты из конверта { data } + чинить фикстуры LeadStatus
DealsView крашился (Cannot read properties of undefined reading 'map'): listProjects() читал data.projects, но ProjectController::index() отдаёт { data: [...] } после миграции на JsonResource — availableProjects=undefined ломал .map, фильтр «Проект» был пуст. Фикс: читать data.data ?? []. + deals-api.spec.ts тест на новый конверт + защитный []. + DealDetailHero.spec.ts: фикстуры LeadStatus (isSystem/sortOrder вместо order) — устранён pre-existing type-check error.

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

52 lines
2.5 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import DealDetailHero from '../../resources/js/components/deals/DealDetailHero.vue';
import type { MockDeal } from '../../resources/js/composables/mockDeals';
import type { LeadStatus } from '../../resources/js/composables/leadStatuses';
const vuetify = createVuetify();
const statuses: LeadStatus[] = [
{ slug: 'new', nameRu: 'Новая сделка', isSystem: true, sortOrder: 1, colorHex: '#5b2db2' },
{ slug: 'viewed', nameRu: 'Просмотрено', isSystem: true, sortOrder: 2, colorHex: '#5a2db2' },
{ slug: 'won', nameRu: 'Куплено', isSystem: true, sortOrder: 3, colorHex: '#00A36C' },
];
function makeDeal(over: Partial<MockDeal> = {}): MockDeal {
return {
id: 1, name: '+79991234567', phone: '+79991234567', statusSlug: 'new',
project: 'p', manager: { initials: 'A', name: 'A' }, cost: 0,
receivedMinutesAgo: 1, ...over,
};
}
describe('DealDetailHero — inline status picker (18.05.2026)', () => {
it('рендерит статус-chip с триггером (data-testid="status-chip-trigger")', () => {
const w = mount(DealDetailHero, {
props: { deal: makeDeal(), status: statuses[0], allStatuses: statuses },
global: { plugins: [vuetify] },
});
expect(w.find('[data-testid="status-chip-trigger"]').exists()).toBe(true);
});
it('клик по chip открывает меню (data-testid="status-option-{slug}" появляются)', async () => {
const w = mount(DealDetailHero, {
props: { deal: makeDeal(), status: statuses[0], allStatuses: statuses },
global: { plugins: [vuetify], stubs: { teleport: false } },
attachTo: document.body,
});
await w.find('[data-testid="status-chip-trigger"]').trigger('click');
// Give v-menu time to mount (teleport target = body).
await new Promise((r) => setTimeout(r, 200));
const options = document.body.querySelectorAll('[data-testid^="status-option-"]');
expect(options.length).toBeGreaterThan(0);
const wonOption = document.body.querySelector('[data-testid="status-option-won"]') as HTMLElement | null;
expect(wonOption).not.toBeNull();
wonOption?.click();
await new Promise((r) => setTimeout(r, 30));
expect(w.emitted('change-status')?.[0]?.[0]).toBe('won');
w.unmount();
});
});