import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import DataManagementPage from '../DataManagementPage.tsx'; import { api } from '../../../services/apiClient.ts'; vi.mock('../../../services/apiClient.ts', () => ({ api: { kpis: { list: vi.fn().mockResolvedValue([]), }, countings: { list: vi.fn().mockResolvedValue([]), create: vi.fn(), update: vi.fn(), sync: vi.fn().mockResolvedValue({ upserted: 2, dates: ['2026-09-02', '2026-09-03'] }), }, manualInputs: { list: vi.fn().mockResolvedValue([ { id: 1, cycle: 1, date: '2026-08-10', mortality_manual: 10, mortality_manual_total: 10, harvest_manual: 0, harvest_weight_manual: 0, }, ]), create: vi.fn(), }, }, errorMessage: (err: unknown) => (err instanceof Error ? err.message : 'Terjadi kesalahan'), })); vi.mock('../../shared/PageAiInsight.tsx', () => ({ PageAiInsight: () =>
, })); vi.mock('../../../context/FarmContext.tsx', () => ({ useFarm: () => ({ selectedSite: { id: 1, site_name: 'Sukawarna', user: 1, created_at: '', updated_at: '' }, selectedKandang: { id: 1, kandang_name: 'Kandang 1', site: 1, created_at: '', updated_at: '', }, selectedKandangId: 1, selectedCycle: { id: 1, kandang: 1, flock: 1, total_days: 35, current_day: 1, visible_through_date: '2026-08-10', start_date: '2026-08-10', end_date: null, chick_in_weight: 45, doc_in_count: 20000, doc_in_weight: 45, status: 'active', created_at: '', updated_at: '', }, }), })); vi.mock('../../../utils/format.ts', async () => { const actual = await vi.importActual( '../../../utils/format.ts' ); return { ...actual, todayIso: () => '2026-08-12', }; }); describe('DataManagementPage', () => { beforeEach(() => { vi.mocked(api.kpis.list).mockResolvedValue([]); vi.mocked(api.countings.list).mockResolvedValue([]); vi.mocked(api.countings.sync).mockResolvedValue({ upserted: 2, dates: ['2026-09-02', '2026-09-03'], }); }); it('renders the Hitung Ayam dashboard view with stats and daily rows', async () => { render( undefined} />); expect(await screen.findByRole('heading', { name: 'Hitung Ayam' })).toBeInTheDocument(); expect(screen.getByText(/Populasi Awal/i)).toBeInTheDocument(); expect(screen.getByText(/Total Mortalitas/i)).toBeInTheDocument(); expect(screen.getByText(/Tingkat Mortalitas/i)).toBeInTheDocument(); expect(screen.getAllByText(/Hari 0/i).length).toBeGreaterThan(0); expect(screen.getAllByText(/Hari 2/i).length).toBeGreaterThan(0); }); it('does not offer manual or counting input forms', async () => { render( undefined} />); expect(await screen.findByRole('heading', { name: 'Hitung Ayam' })).toBeInTheDocument(); expect(screen.queryByRole('heading', { name: /Input manual/i })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: /Simpan hitungan/i })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: /Edit/i })).not.toBeInTheDocument(); }); it('shows Mati IoT as 0 and Akurasi Mati when counting row is missing', async () => { render( undefined} />); expect(await screen.findByRole('heading', { name: 'Hitung Ayam' })).toBeInTheDocument(); expect(screen.getAllByText('Mati IoT').length).toBeGreaterThan(0); expect(screen.getAllByText('Akurasi Mati').length).toBeGreaterThan(0); // manual 10 vs iot 0 → 0.0% expect(screen.getAllByText('0.0%').length).toBeGreaterThan(0); }); it('calls chicken counting sync when Sync is clicked', async () => { render( undefined} />); await screen.findByRole('heading', { name: 'Hitung Ayam' }); fireEvent.click(screen.getByRole('button', { name: /Sync/i })); await waitFor(() => { expect(api.countings.sync).toHaveBeenCalledWith({ cycle_id: 1 }); }); }); it('shows under-count IoT accuracy warning for the latest IoT day', async () => { vi.mocked(api.kpis.list).mockResolvedValue([ { id: 1, cycle: 1, kandang: 1, flock_id: 1, date: '2026-08-12', age: 2, mortality: 0, mortality_total: 10, feed: 0, feed_total: 0, harvest: 0, harvest_total: 0, harvest_weight: 0, harvest_weight_total: 0, chicken_life: 19990, chicken_life_percentage: 99.95, iot_weight: 0, average_harvest_day: 0, average_harvest_weight: 0, fcr: 0, eef: 0, cc: 0, cw: 0, fs: 0, manual: 0, created_at: '', updated_at: '', }, ]); vi.mocked(api.countings.list).mockResolvedValue([ { id: 1, cycle: 1, kandang: 1, flock_id: 1, date: '2026-08-12', total_count: 18000, mortality_count: 0, created_at: '', updated_at: '', }, ]); render( undefined} />); const alert = await screen.findByRole('alert'); expect(within(alert).getByText(/IoT lebih rendah dari stock/i)).toBeInTheDocument(); expect(within(alert).getByText(/Hari 2/i)).toBeInTheDocument(); }); });