Files
dashboard-cpsp/components/counting/__tests__/DataManagementPage.test.tsx
T

183 lines
5.6 KiB
TypeScript

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: () => <div data-testid="page-ai-insight" />,
}));
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: '2026-09-13',
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<typeof import('../../../utils/format.ts')>(
'../../../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(<DataManagementPage onSettings={() => 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(<DataManagementPage onSettings={() => 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(<DataManagementPage onSettings={() => 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(<DataManagementPage onSettings={() => 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(<DataManagementPage onSettings={() => 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();
});
});