import { describe, it, expect, vi, beforeEach } from 'vitest'; import { mount, flushPromises } from '@vue/test-utils'; import { createVuetify } from 'vuetify'; import { createPinia } from 'pinia'; import { createRouter, createMemoryHistory } from 'vue-router'; import SalesPerformanceView from '../../resources/js/views/sales/SalesPerformanceView.vue'; // ─── mock getSalesManagersPerformance ───────────────────────────────────────── const perfMock = vi.fn().mockResolvedValue([ { manager_id: 1, name: 'Алексей Смирнов', email: 'a.smirnov@liderra.ru', clients_count: 7, active_clients: 5, leads_delivered: 1567, oborot_rub: 235050, paid_all_time_rub: 85000, earned_rub: 13350, status: 'active', }, { manager_id: 3, name: 'Игорь Лебедев', email: 'i.lebedev@liderra.ru', clients_count: 4, active_clients: 3, leads_delivered: 724, oborot_rub: 108600, paid_all_time_rub: 40000, earned_rub: 10000, status: 'vacation', }, ]); vi.mock('../../resources/js/api/sales', () => ({ getSalesManagersPerformance: (...args: unknown[]) => perfMock(...args), })); beforeEach(() => { perfMock.mockClear(); }); // ─── helpers ────────────────────────────────────────────────────────────────── function makeRouter() { const router = createRouter({ history: createMemoryHistory(), routes: [ { path: '/sales/performance', name: 'sales-performance', component: SalesPerformanceView }, { path: '/sales', name: 'sales-overview', component: { template: '
' } }, ], }); return router.push('/sales/performance').then(() => router); } async function mountView() { const router = await makeRouter(); const wrapper = mount(SalesPerformanceView, { global: { plugins: [createVuetify(), createPinia(), router] }, }); await flushPromises(); return wrapper; } describe('SalesPerformanceView', () => { it('отрисовывает заголовок и колонки', async () => { const wrapper = await mountView(); const text = wrapper.text(); expect(text).toContain('Результативность менеджеров'); expect(text).toContain('Менеджер'); expect(text).toContain('Клиентов'); expect(text).toContain('Активных'); expect(text).toContain('Лидов пришло'); expect(text).toContain('Оборот клиентов'); expect(text).toContain('Выплачено'); expect(text).toContain('Заработал'); expect(text).toContain('Статус'); }); it('вызывает getSalesManagersPerformance при монтировании', async () => { await mountView(); expect(perfMock).toHaveBeenCalled(); }); it('отрисовывает строки менеджеров из мока (имя + email)', async () => { const wrapper = await mountView(); const rows = wrapper.findAll('[data-testid="perf-row"]'); expect(rows.length).toBe(2); const text = wrapper.text(); expect(text).toContain('Алексей Смирнов'); expect(text).toContain('a.smirnov@liderra.ru'); expect(text).toContain('Игорь Лебедев'); expect(text).toContain('i.lebedev@liderra.ru'); }); it('статус active → чип «Активен», vacation → чип «Отпуск»', async () => { const wrapper = await mountView(); const text = wrapper.text(); expect(text).toContain('Активен'); expect(text).toContain('Отпуск'); }); it('ввод в поиск вызывает getSalesManagersPerformance с параметром search (после debounce)', async () => { vi.useFakeTimers(); try { const router = await makeRouter(); const wrapper = mount(SalesPerformanceView, { global: { plugins: [createVuetify(), createPinia(), router] }, }); // initial onMounted load await vi.runAllTimersAsync(); await flushPromises(); perfMock.mockClear(); const input = wrapper.find('[data-testid="search-input"] input'); await input.setValue('Мария'); // Ждём завершения debounce. await vi.runAllTimersAsync(); await flushPromises(); expect(perfMock).toHaveBeenCalled(); const lastCall = perfMock.mock.calls[perfMock.mock.calls.length - 1]; expect(lastCall[0]).toMatchObject({ search: 'Мария' }); } finally { vi.useRealTimers(); } }); });