import { describe, it, expect, vi, beforeEach } from 'vitest'; import { mount } from '@vue/test-utils'; import { createVuetify } from 'vuetify'; import axios from 'axios'; import AdminSupplierIntegrationView from '../../resources/js/views/admin/AdminSupplierIntegrationView.vue'; vi.mock('axios'); const vuetify = createVuetify(); const healthPayload = { health: { last_run_at: '2026-05-18T12:00:00Z', last_status: 'ok', drift_ratio: 0.02, webhook_state: 'live' }, history: [ { started_at: '2026-05-18T12:00:00Z', finished_at: '2026-05-18T12:01:00Z', window_start: '2026-05-17T00:00:00Z', window_end: '2026-05-18T12:00:00Z', status: 'ok', total_csv_rows: 100, matched_count: 98, recovered_count: 2, drift_ratio: 0.02, }, ], }; function mountView() { return mount(AdminSupplierIntegrationView, { global: { plugins: [vuetify] } }); } const syncRunsPayload = { runs: [ { started_at: '2026-06-25T15:05:00Z', finished_at: '2026-06-25T15:47:00Z', groups_total: 180, synced_ok: 312, manual_queued: 1, deferred: 0, failed: 0, status: 'partial', }, ], }; beforeEach(() => { vi.clearAllMocks(); (axios.get as ReturnType).mockImplementation((url: string) => { if (url === '/api/admin/supplier-integration/sync-runs') { return Promise.resolve({ data: syncRunsPayload }); } if (url === '/api/admin/supplier-integration/manual-queue') { return Promise.resolve({ data: { queue: [] } }); } if (url === '/api/admin/supplier-integration/export-mode') { return Promise.resolve({ data: { mode: 'batch' } }); } return Promise.resolve({ data: healthPayload }); }); (axios.post as ReturnType).mockResolvedValue({ data: { dispatched: true } }); }); describe('AdminSupplierIntegrationView', () => { it('loads channel health on mount', async () => { const wrapper = mountView(); await new Promise((r) => setTimeout(r, 0)); expect(axios.get).toHaveBeenCalledWith('/api/admin/supplier-integration'); expect(wrapper.text()).toContain('live'); }); it('renders reconcile history rows', async () => { const wrapper = mountView(); await new Promise((r) => setTimeout(r, 0)); await wrapper.vm.$nextTick(); expect(wrapper.text()).toContain('100'); }); it('triggers manual reconcile on button click', async () => { const wrapper = mountView(); await new Promise((r) => setTimeout(r, 0)); await wrapper.find('[data-test="reconcile-now"]').trigger('click'); expect(axios.post).toHaveBeenCalledWith('/api/admin/supplier-integration/reconcile'); }); // --- Эпик 5: история вечерних заливок --- it('loads evening-upload history on mount', async () => { mountView(); await new Promise((r) => setTimeout(r, 0)); expect(axios.get).toHaveBeenCalledWith('/api/admin/supplier-integration/sync-runs'); }); it('renders sync-runs table with totals + human status', async () => { const wrapper = mountView(); await new Promise((r) => setTimeout(r, 0)); await wrapper.vm.$nextTick(); expect(wrapper.find('[data-testid="sync-runs-table"]').exists()).toBe(true); const rows = wrapper.findAll('[data-testid="sync-run-row"]'); expect(rows.length).toBe(1); expect(wrapper.text()).toContain('180'); // групп expect(wrapper.text()).toContain('312'); // готово expect(wrapper.text()).toContain('Частично'); // human status (partial) }); });