291 lines
8.2 KiB
TypeScript
291 lines
8.2 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import SettingsPage from '../SettingsPage.tsx';
|
|
|
|
const { createKandangMock, createFlockMock, updateFlockMock, createCycleMock, updateCycleMock, reloadMock, farmState } = vi.hoisted(
|
|
() => ({
|
|
createKandangMock: vi.fn(),
|
|
createFlockMock: vi.fn(),
|
|
updateFlockMock: vi.fn(),
|
|
createCycleMock: vi.fn(),
|
|
updateCycleMock: vi.fn(),
|
|
reloadMock: vi.fn().mockResolvedValue(undefined),
|
|
farmState: {
|
|
sites: [{ id: 'site-a', site_name: 'Site A', user: 99, created_at: '', updated_at: '' }],
|
|
kandangs: [] as Array<{
|
|
id: number;
|
|
kandang_name: string;
|
|
site: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}>,
|
|
flocks: [] as Array<{
|
|
id: number;
|
|
flock_name: string;
|
|
iot_api_url?: string;
|
|
kandang: number;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}>,
|
|
cycles: [] as unknown[],
|
|
selectedSiteId: 'site-a',
|
|
selectedKandangId: null as number | null,
|
|
selectedCycleId: null as number | null,
|
|
selectedCycle: null as unknown,
|
|
},
|
|
})
|
|
);
|
|
|
|
vi.mock('../../services/apiClient.ts', () => ({
|
|
api: {
|
|
sites: {
|
|
create: vi.fn(),
|
|
remove: vi.fn(),
|
|
},
|
|
kandangs: {
|
|
create: createKandangMock,
|
|
remove: vi.fn(),
|
|
},
|
|
flocks: {
|
|
create: createFlockMock,
|
|
update: updateFlockMock,
|
|
remove: vi.fn(),
|
|
},
|
|
cycles: {
|
|
create: createCycleMock,
|
|
update: updateCycleMock,
|
|
remove: vi.fn(),
|
|
},
|
|
},
|
|
errorMessage: (err: unknown) => (err instanceof Error ? err.message : 'Terjadi kesalahan'),
|
|
}));
|
|
|
|
vi.mock('../../context/AuthContext.tsx', () => ({
|
|
useAuth: () => ({
|
|
user: {
|
|
id: 99,
|
|
user_name: 'tester',
|
|
display_name: 'Tester',
|
|
status: 'superadmin',
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
}),
|
|
}));
|
|
|
|
vi.mock('../../context/FarmContext.tsx', () => ({
|
|
useFarm: () => ({
|
|
sites: farmState.sites,
|
|
kandangs: farmState.kandangs,
|
|
flocks: farmState.flocks,
|
|
cycles: farmState.cycles,
|
|
selectedSiteId: farmState.selectedSiteId,
|
|
selectedKandangId: farmState.selectedKandangId,
|
|
selectedCycleId: farmState.selectedCycleId,
|
|
selectedCycle: farmState.selectedCycle,
|
|
reload: reloadMock,
|
|
setSelectedSiteId: vi.fn(),
|
|
setSelectedKandangId: vi.fn(),
|
|
setSelectedCycleId: vi.fn(),
|
|
}),
|
|
}));
|
|
|
|
describe('SettingsPage settings forms', () => {
|
|
beforeEach(() => {
|
|
createKandangMock.mockReset();
|
|
createFlockMock.mockReset();
|
|
updateFlockMock.mockReset();
|
|
createCycleMock.mockReset();
|
|
updateCycleMock.mockReset();
|
|
reloadMock.mockClear();
|
|
farmState.kandangs = [];
|
|
farmState.flocks = [];
|
|
farmState.cycles = [];
|
|
farmState.selectedSiteId = 'site-a';
|
|
farmState.selectedKandangId = null;
|
|
farmState.selectedCycleId = null;
|
|
farmState.selectedCycle = null;
|
|
createKandangMock.mockResolvedValue({
|
|
id: 11,
|
|
kandang_name: 'Kandang 1',
|
|
site: 'site-a',
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
createFlockMock.mockResolvedValue({
|
|
id: 3,
|
|
flock_name: 'Lantai 1',
|
|
iot_api_url: '',
|
|
kandang: 11,
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
updateFlockMock.mockResolvedValue({
|
|
id: 3,
|
|
flock_name: 'Lantai 1',
|
|
iot_api_url: 'https://example.test/iot/lantai-1',
|
|
kandang: 11,
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
createCycleMock.mockResolvedValue({
|
|
id: 21,
|
|
kandang: 11,
|
|
total_days: 35,
|
|
current_day: 1,
|
|
start_date: '2026-08-18',
|
|
end_date: '2026-09-21',
|
|
chick_in_weight: 35,
|
|
doc_in_count: 20000,
|
|
status: 'active',
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
updateCycleMock.mockResolvedValue({
|
|
id: 22,
|
|
kandang: 11,
|
|
total_days: 40,
|
|
current_day: 1,
|
|
start_date: '2026-08-01',
|
|
end_date: '2026-09-09',
|
|
chick_in_weight: 38,
|
|
doc_in_count: 18000,
|
|
status: 'closed',
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
});
|
|
|
|
it('submits only backend-supported kandang fields', async () => {
|
|
render(<SettingsPage />);
|
|
|
|
fireEvent.change(screen.getByPlaceholderText('Nama kandang'), {
|
|
target: { value: 'Kandang 1' },
|
|
});
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: 'Tambah kandang' }));
|
|
|
|
await waitFor(() => expect(createKandangMock).toHaveBeenCalledTimes(1));
|
|
expect(createKandangMock).toHaveBeenCalledWith({
|
|
kandang_name: 'Kandang 1',
|
|
site: 'site-a',
|
|
});
|
|
});
|
|
|
|
it('submits flock fields for the selected kandang', async () => {
|
|
farmState.kandangs = [
|
|
{ id: 11, kandang_name: 'Kandang 1', site: 'site-a', created_at: '', updated_at: '' },
|
|
];
|
|
farmState.selectedKandangId = 11;
|
|
|
|
render(<SettingsPage />);
|
|
|
|
fireEvent.change(screen.getByPlaceholderText('Nama flock'), {
|
|
target: { value: 'Lantai 1' },
|
|
});
|
|
fireEvent.click(screen.getByRole('button', { name: 'Tambah flock' }));
|
|
|
|
await waitFor(() => expect(createFlockMock).toHaveBeenCalledTimes(1));
|
|
expect(createFlockMock).toHaveBeenCalledWith({
|
|
flock_name: 'Lantai 1',
|
|
kandang: 11,
|
|
});
|
|
});
|
|
|
|
it('saves flock IoT API URL for a listed flock', async () => {
|
|
farmState.kandangs = [
|
|
{ id: 11, kandang_name: 'Kandang 1', site: 'site-a', created_at: '', updated_at: '' },
|
|
];
|
|
farmState.selectedKandangId = 11;
|
|
farmState.flocks = [
|
|
{
|
|
id: 3,
|
|
flock_name: 'Lantai 1',
|
|
iot_api_url: '',
|
|
kandang: 11,
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
];
|
|
|
|
render(<SettingsPage />);
|
|
|
|
fireEvent.change(screen.getByPlaceholderText('https://…/api/iot/…'), {
|
|
target: { value: 'https://example.test/iot/lantai-1' },
|
|
});
|
|
fireEvent.click(screen.getByRole('button', { name: 'Simpan URL IoT' }));
|
|
|
|
await waitFor(() => expect(updateFlockMock).toHaveBeenCalledTimes(1));
|
|
expect(updateFlockMock).toHaveBeenCalledWith(3, {
|
|
iot_api_url: 'https://example.test/iot/lantai-1',
|
|
});
|
|
});
|
|
|
|
it('submits cycle fields without flock assignment', async () => {
|
|
farmState.kandangs = [
|
|
{ id: 11, kandang_name: 'Kandang 1', site: 'site-a', created_at: '', updated_at: '' },
|
|
];
|
|
farmState.selectedKandangId = 11;
|
|
|
|
render(<SettingsPage />);
|
|
|
|
expect(screen.queryByLabelText(/^Siklus$/i)).not.toBeInTheDocument();
|
|
expect(screen.queryByLabelText(/Total hari/i)).not.toBeInTheDocument();
|
|
expect(screen.queryByLabelText(/Selesai/i)).not.toBeInTheDocument();
|
|
|
|
fireEvent.change(screen.getByLabelText(/Mulai/i), { target: { value: '2026-08-01' } });
|
|
fireEvent.click(screen.getByRole('button', { name: 'Tambah siklus' }));
|
|
|
|
await waitFor(() => expect(createCycleMock).toHaveBeenCalledTimes(1));
|
|
expect(createCycleMock).toHaveBeenCalledWith({
|
|
kandang: 11,
|
|
total_days: 1,
|
|
current_day: 1,
|
|
start_date: '2026-08-01',
|
|
chick_in_weight: 35,
|
|
doc_in_count: 20000,
|
|
});
|
|
});
|
|
|
|
it('updates an existing cycle from the edit form', async () => {
|
|
farmState.kandangs = [
|
|
{ id: 11, kandang_name: 'Kandang 1', site: 'site-a', created_at: '', updated_at: '' },
|
|
];
|
|
farmState.selectedKandangId = 11;
|
|
farmState.cycles = [
|
|
{
|
|
id: 22,
|
|
kandang: 11,
|
|
kandang_name: 'Kandang 1',
|
|
total_days: 35,
|
|
current_day: 1,
|
|
visible_through_date: '2026-08-18',
|
|
start_date: '2026-08-01',
|
|
end_date: null,
|
|
chick_in_weight: 35,
|
|
doc_in_count: 20000,
|
|
feed_initial_balance: 0,
|
|
status: 'active',
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
];
|
|
|
|
render(<SettingsPage />);
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: 'Ubah' }));
|
|
fireEvent.change(screen.getByLabelText(/DOC in/i), { target: { value: '18000' } });
|
|
fireEvent.change(screen.getByLabelText(/Berat DOC/i), { target: { value: '38' } });
|
|
fireEvent.click(screen.getByRole('button', { name: 'Simpan perubahan' }));
|
|
|
|
await waitFor(() => expect(updateCycleMock).toHaveBeenCalledTimes(1));
|
|
expect(updateCycleMock).toHaveBeenCalledWith(22, {
|
|
kandang: 11,
|
|
total_days: 1,
|
|
start_date: '2026-08-01',
|
|
chick_in_weight: 38,
|
|
doc_in_count: 18000,
|
|
});
|
|
});
|
|
});
|