94 lines
3.5 KiB
React
94 lines
3.5 KiB
React
import React from 'react';
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import DailyStatusForm from '../src/components/DailyStatusForm';
|
|
import * as client from '../src/api/client';
|
|
|
|
jest.mock('../src/api/client', () => ({
|
|
dailyStatusesApi: {
|
|
create: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
const ANIMAL_ID = 'animal-001';
|
|
const onSuccess = jest.fn();
|
|
const onCancel = jest.fn();
|
|
|
|
beforeEach(() => jest.clearAllMocks());
|
|
|
|
describe('DailyStatusForm', () => {
|
|
it('renders date field (required) and optional fields', () => {
|
|
render(<DailyStatusForm animalId={ANIMAL_ID} onSuccess={onSuccess} onCancel={onCancel} />);
|
|
expect(screen.getByLabelText(/date/i)).toBeInTheDocument();
|
|
expect(screen.getByLabelText(/vitals/i)).toBeInTheDocument();
|
|
expect(screen.getByLabelText(/treatment/i)).toBeInTheDocument();
|
|
expect(screen.getByLabelText(/notes/i)).toBeInTheDocument();
|
|
expect(screen.getByLabelText(/experiment description/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('pre-fills date with today by default', () => {
|
|
render(<DailyStatusForm animalId={ANIMAL_ID} onSuccess={onSuccess} onCancel={onCancel} />);
|
|
const today = new Date().toISOString().slice(0, 10);
|
|
expect(screen.getByLabelText(/date/i)).toHaveValue(today);
|
|
});
|
|
|
|
it('shows error when date is cleared', async () => {
|
|
render(<DailyStatusForm animalId={ANIMAL_ID} onSuccess={onSuccess} onCancel={onCancel} />);
|
|
const dateInput = screen.getByLabelText(/date/i);
|
|
await userEvent.clear(dateInput);
|
|
fireEvent.click(screen.getByRole('button', { name: /log status/i }));
|
|
expect(await screen.findByRole('alert')).toHaveTextContent(/date is required/i);
|
|
expect(client.dailyStatusesApi.create).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('calls create with correct payload including animal_id', async () => {
|
|
const status = { id: 's-1', animal_id: ANIMAL_ID, date: '2024-06-01', vitals: 'HR 72' };
|
|
client.dailyStatusesApi.create.mockResolvedValue(status);
|
|
|
|
render(<DailyStatusForm animalId={ANIMAL_ID} onSuccess={onSuccess} onCancel={onCancel} />);
|
|
|
|
const dateInput = screen.getByLabelText(/date/i);
|
|
await userEvent.clear(dateInput);
|
|
await userEvent.type(dateInput, '2024-06-01');
|
|
|
|
await userEvent.type(screen.getByLabelText(/vitals/i), 'HR 72');
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: /log status/i }));
|
|
|
|
await waitFor(() =>
|
|
expect(client.dailyStatusesApi.create).toHaveBeenCalledWith(
|
|
expect.objectContaining({ animal_id: ANIMAL_ID, vitals: 'HR 72' })
|
|
)
|
|
);
|
|
await waitFor(() => expect(onSuccess).toHaveBeenCalled());
|
|
});
|
|
|
|
it('shows "Save Changes" and pre-fills fields for existing status', () => {
|
|
const existing = {
|
|
id: 's-1',
|
|
date: '2024-06-01T00:00:00.000Z',
|
|
vitals: 'HR 72',
|
|
treatment: 'Control',
|
|
notes: 'Normal',
|
|
experiment_description: 'Baseline',
|
|
};
|
|
render(
|
|
<DailyStatusForm
|
|
existing={existing}
|
|
animalId={ANIMAL_ID}
|
|
onSuccess={onSuccess}
|
|
onCancel={onCancel}
|
|
/>
|
|
);
|
|
expect(screen.getByRole('button', { name: /save changes/i })).toBeInTheDocument();
|
|
expect(screen.getByDisplayValue('HR 72')).toBeInTheDocument();
|
|
});
|
|
|
|
it('calls onCancel when Cancel is clicked', () => {
|
|
render(<DailyStatusForm animalId={ANIMAL_ID} onSuccess={onSuccess} onCancel={onCancel} />);
|
|
fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
|
|
expect(onCancel).toHaveBeenCalled();
|
|
});
|
|
});
|