add chicken counting, mortality api for daily data sync. Also adjust karung sync to sync every 30 sec after publish cutoff time to update real data without clicking sync button manually
This commit is contained in:
1 parent
5ae477a99d
commit
6c21af745d
17 files changed
+791
-119
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { fireEvent, render, screen, waitFor } 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: {
|
||||
@@ -11,9 +12,20 @@ vi.mock('../../../services/apiClient.ts', () => ({
|
||||
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([]),
|
||||
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(),
|
||||
},
|
||||
insights: {
|
||||
@@ -38,11 +50,13 @@ vi.mock('../../../context/FarmContext.tsx', () => ({
|
||||
kandang: 1,
|
||||
flock: 1,
|
||||
total_days: 35,
|
||||
current_day: 3,
|
||||
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: '',
|
||||
@@ -50,7 +64,25 @@ vi.mock('../../../context/FarmContext.tsx', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
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.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} />);
|
||||
|
||||
@@ -70,4 +102,25 @@ describe('DataManagementPage', () => {
|
||||
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 });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user