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'; // VDialog в JSDOM не рендерит в teleport-цели; стабом отключаем диалоги, // чтобы не падал mount при попытке портала. const factory = () => mount(ProjectsView, { global: { plugins: [createVuetify()], stubs: { VDialog: { template: '
', props: ['modelValue'], }, NewProjectDialog: true, EditProjectDialog: true, }, }, }); beforeEach(() => { setActivePinia(createPinia()); vi.clearAllMocks(); }); describe('ProjectsView', () => { it('shows empty state when no projects', async () => { (axios.get as unknown as ReturnType).mockResolvedValue({ data: { data: [], meta: { total: 0, current_page: 1, per_page: 20 } }, }); const wrapper = factory(); await flushPromises(); expect(wrapper.text()).toMatch(/нет проектов|empty/i); }); it('renders card for each project', async () => { (axios.get as unknown as ReturnType).mockResolvedValue({ data: { data: [ { id: 1, name: 'AlphaSite', signal_type: 'site', signal_identifier: 'a.ru', daily_limit_target: 10, delivered_today: 0, is_active: true, archived_at: null, sync_status: 'ok', }, ], meta: { total: 1, current_page: 1, per_page: 20 }, }, }); const wrapper = factory(); await flushPromises(); expect(wrapper.text()).toContain('AlphaSite'); }); it.skip('filter by signal_type refetches', async () => { // TODO: VSelect dropdown в jsdom не открывает items-list через teleport, // findComponent({name:'VSelect'}).vm.$emit некорректно тригерит реактивную // цепочку @update:model-value. Покрытие — через Histoire + e2e после Plan 5. }); it('shows BulkActionsBar when at least 1 selected', async () => { (axios.get as unknown as ReturnType).mockResolvedValue({ data: { data: [ { id: 1, name: 'A', signal_type: 'site', signal_identifier: 'a.ru', daily_limit_target: 10, delivered_today: 0, is_active: true, archived_at: null, sync_status: 'ok', }, ], meta: { total: 1, current_page: 1, per_page: 20 }, }, }); const wrapper = factory(); await flushPromises(); const card = wrapper.findComponent({ name: 'ProjectCard' }); expect(card.exists()).toBe(true); card.vm.$emit('toggle-select', 1); await wrapper.vm.$nextTick(); expect(wrapper.findComponent({ name: 'BulkActionsBar' }).exists()).toBe(true); }); });