9ee4e9a79f
- 12-я колонка «Корзина», результат «В корзину» просит только причину; - в шапке «Отказа» дробь «4/2» с подсказкой «из них 2 после ручного тестирования»; при нуле дробь не рисуется — «69/0» это шум; - у «Выслано КП» поле даты подписано «если договорились» и необязательно; - орган фильтра по датам на ОБОИХ экранах, два режима + период. Приёмка глазами пройдена живьём по всем семи пунктам, включая «Воронку отдела» (снимки в docs/superpowers/screens/2026-08-01-korzina-filtry/priemka/). Браузер поймал то, чего не видели тесты: при смене режима оставался прежний период, и «что менялось за завтра» давало пустую доску — теперь период возвращается к «Сегодня», на это заведён отдельный тест. Прогон: сервер 1245/1245, фронт 1567/1567. Журнал схемы — v9.31.
78 lines
3.5 KiB
TypeScript
78 lines
3.5 KiB
TypeScript
import { mount, flushPromises } from '@vue/test-utils';
|
|
import { createVuetify } from 'vuetify';
|
|
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
|
|
vi.mock('../../resources/js/api/sales', () => ({
|
|
listProspects: vi.fn().mockResolvedValue({ prospects: [], by_stage: {}, stages: [] }),
|
|
listSalesManagers: vi.fn().mockResolvedValue([
|
|
{ id: 7, name: 'Иванов', email: 'i@s', role: 'manager', is_active: true, clients_count: 0, paid_all_time_rub: 0 },
|
|
]),
|
|
updateProspect: vi.fn(),
|
|
extractSalesErrorMessage: () => 'err',
|
|
}));
|
|
|
|
import SalesProspectsBoardView from '../../resources/js/views/sales/SalesProspectsBoardView.vue';
|
|
import { listProspects } from '../../resources/js/api/sales';
|
|
|
|
const vuetify = createVuetify();
|
|
|
|
interface BoardVm {
|
|
managerId: number | null;
|
|
load: () => Promise<void>;
|
|
managerItems: { id: number | null; name: string }[];
|
|
applyDateFilter: (v: unknown) => Promise<void>;
|
|
}
|
|
|
|
describe('SalesProspectsBoardView', () => {
|
|
beforeEach(() => vi.clearAllMocks());
|
|
|
|
it('при выборе менеджера перезагружает с его id', async () => {
|
|
const w = mount(SalesProspectsBoardView, { global: { plugins: [vuetify] } });
|
|
await flushPromises();
|
|
// 'department' — воронка отдела просит весь отдел явно (§23).
|
|
expect(listProspects).toHaveBeenCalledWith(undefined, undefined, 'department', null);
|
|
|
|
(w.vm as unknown as BoardVm).managerId = 7;
|
|
await (w.vm as unknown as BoardVm).load();
|
|
expect(listProspects).toHaveBeenLastCalledWith(7, undefined, 'department', null);
|
|
});
|
|
|
|
it('фильтр по датам уходит в запрос, а «Все карточки» его гасят', async () => {
|
|
const w = mount(SalesProspectsBoardView, { global: { plugins: [vuetify] } });
|
|
await flushPromises();
|
|
const vm = w.vm as unknown as BoardVm;
|
|
|
|
const todo = { mode: 'todo', period: 'today', from: null, to: null };
|
|
await vm.applyDateFilter(todo);
|
|
expect(listProspects).toHaveBeenLastCalledWith(undefined, undefined, 'department', todo);
|
|
|
|
await vm.applyDateFilter({ mode: null, period: 'today', from: null, to: null });
|
|
expect(listProspects).toHaveBeenLastCalledWith(undefined, undefined, 'department', null);
|
|
});
|
|
|
|
it('фильтр происхождения уходит в запрос вторым параметром', async () => {
|
|
const w = mount(SalesProspectsBoardView, { global: { plugins: [vuetify] } });
|
|
await flushPromises();
|
|
|
|
(w.vm as unknown as BoardVm & { source: string | null }).source = 'manager';
|
|
await (w.vm as unknown as BoardVm).load();
|
|
|
|
expect(listProspects).toHaveBeenLastCalledWith(undefined, 'manager', 'department', null);
|
|
});
|
|
|
|
it('в фильтре у менеджера показывается число его карточек', async () => {
|
|
(listProspects as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
prospects: [],
|
|
by_stage: {},
|
|
stages: [],
|
|
manager_counts: { '7': 3 },
|
|
});
|
|
const w = mount(SalesProspectsBoardView, { global: { plugins: [vuetify] } });
|
|
await flushPromises();
|
|
|
|
const items = (w.vm as unknown as BoardVm).managerItems;
|
|
expect(items[0]).toMatchObject({ id: null, name: 'Все менеджеры' });
|
|
expect(items.some((i) => i.name === 'Иванов (3)')).toBe(true);
|
|
});
|
|
});
|