261a3cd46f
Два бага, которых не видел ни один тест — их нашёл робот, снимавший инструкции для гостей. 1) Карточка остановленного проекта показывала одновременно «На паузе» и зелёную плашку «Собирает заявки»: плашка смотрела только на связь с поставщиком (там всё «ок») и про паузу не знала. Теперь серым: «Остановлен вами — заявки не приходят». 2) В «Канбане» сумма в шапке колонки всегда была прочерком: считалась по старому демо-полю, которого у живых заявок нет (там ноль), хотя на карточках стояла честная цена. Теперь считает по настоящему списанию. Тесты: сначала падающие, потом фикс. Весь фронт 1229 зелёных. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
61 lines
3.1 KiB
TypeScript
61 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
||
import { mount } from '@vue/test-utils';
|
||
import { createVuetify } from 'vuetify';
|
||
import KanbanColumn from '../../resources/js/components/kanban/KanbanColumn.vue';
|
||
import { LEAD_STATUSES } from '../../resources/js/composables/leadStatuses';
|
||
import { MOCK_DEALS } from '../../resources/js/composables/mockDeals';
|
||
|
||
describe('KanbanColumn.vue', () => {
|
||
const status = LEAD_STATUSES[0]; // 'new'
|
||
const dealsForNew = MOCK_DEALS.filter((d) => d.statusSlug === 'new');
|
||
|
||
const factory = (props: { status: typeof status; deals: typeof MOCK_DEALS }) =>
|
||
mount(KanbanColumn, {
|
||
props,
|
||
global: { plugins: [createVuetify()] },
|
||
});
|
||
|
||
it('header содержит nameRu статуса и count', () => {
|
||
const wrapper = factory({ status, deals: dealsForNew });
|
||
const text = wrapper.text();
|
||
expect(text).toContain(status.nameRu);
|
||
expect(text).toContain(String(dealsForNew.length));
|
||
});
|
||
|
||
it('total = sum dealcost (форматированный «N ₽»)', () => {
|
||
const deals = MOCK_DEALS.slice(0, 2); // первые 2 — 1850 + 2400 = 4250
|
||
const wrapper = factory({ status, deals });
|
||
expect(wrapper.text()).toMatch(/4\s+250\s*₽/);
|
||
});
|
||
|
||
// Живые заявки приходят с сервера: списание лежит в costKopecks, а демо-поле cost у них
|
||
// ноль. Итог колонки считался по cost → в шапке всегда стоял прочерк, хотя на карточках
|
||
// честные 55 ₽ (поймано на кадрах разборов 14.07.2026).
|
||
it('total считает по настоящему списанию (costKopecks), а не по демо-полю cost', () => {
|
||
const deals = MOCK_DEALS.slice(0, 3).map((d) => ({ ...d, cost: 0, costKopecks: 55_00 }));
|
||
const wrapper = factory({ status, deals });
|
||
expect(wrapper.text()).toMatch(/165\s*₽/); // 3 × 55 ₽
|
||
expect(wrapper.text()).not.toContain('—');
|
||
});
|
||
|
||
it('total = «—» при пустом списке', () => {
|
||
const wrapper = factory({ status, deals: [] });
|
||
expect(wrapper.text()).toContain('—');
|
||
expect(wrapper.text()).toContain('пусто');
|
||
});
|
||
|
||
it('применяет colorHex статуса как CSS var --accent', () => {
|
||
const wrapper = factory({ status, deals: dealsForNew });
|
||
const head = wrapper.find('.column-head');
|
||
// Vue 3 inline-style сохраняет как есть (case-preserve) — матчим case-insensitive.
|
||
expect(head.attributes('style')?.toLowerCase()).toContain(status.colorHex.toLowerCase());
|
||
});
|
||
|
||
it('пробрасывает open от карточки → openDeal с id', async () => {
|
||
const wrapper = factory({ status, deals: dealsForNew });
|
||
await wrapper.findComponent({ name: 'KanbanCard' }).vm.$emit('open', dealsForNew[0].id);
|
||
expect(wrapper.emitted('openDeal')).toBeTruthy();
|
||
expect(wrapper.emitted('openDeal')?.[0]).toEqual([dealsForNew[0].id]);
|
||
});
|
||
});
|