import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import AnimalForm from '../src/components/AnimalForm'; import * as client from '../src/api/client'; jest.mock('../src/api/client', () => ({ animalsApi: { create: jest.fn(), update: jest.fn(), }, })); const EXP_ID = 'exp-001'; const onSuccess = jest.fn(); const onCancel = jest.fn(); beforeEach(() => jest.clearAllMocks()); describe('AnimalForm', () => { it('renders Animal ID and Animal Name fields', () => { render(); expect(screen.getByLabelText(/animal id/i)).toBeInTheDocument(); expect(screen.getByLabelText(/animal name/i)).toBeInTheDocument(); }); it('shows required field errors on empty submit', async () => { render(); fireEvent.click(screen.getByRole('button', { name: /add animal/i })); expect(await screen.findAllByRole('alert')).toHaveLength(2); expect(client.animalsApi.create).not.toHaveBeenCalled(); }); it('calls create with correct payload', async () => { const animal = { id: 'a-1', animal_id_string: 'M-001', animal_name: 'Whiskers', experiment_id: EXP_ID }; client.animalsApi.create.mockResolvedValue(animal); render(); await userEvent.type(screen.getByLabelText(/animal id/i), 'M-001'); await userEvent.type(screen.getByLabelText(/animal name/i), 'Whiskers'); fireEvent.click(screen.getByRole('button', { name: /add animal/i })); await waitFor(() => expect(client.animalsApi.create).toHaveBeenCalledWith({ animal_id_string: 'M-001', animal_name: 'Whiskers', experiment_id: EXP_ID, }) ); await waitFor(() => expect(onSuccess).toHaveBeenCalledWith(animal)); }); it('pre-fills fields for existing animal and uses update API', async () => { const existing = { id: 'a-1', animal_id_string: 'M-001', animal_name: 'Whiskers' }; const updated = { ...existing, animal_name: 'Mr Whiskers' }; client.animalsApi.update.mockResolvedValue(updated); render(); expect(screen.getByDisplayValue('Whiskers')).toBeInTheDocument(); const nameInput = screen.getByLabelText(/animal name/i); await userEvent.clear(nameInput); await userEvent.type(nameInput, 'Mr Whiskers'); fireEvent.click(screen.getByRole('button', { name: /save changes/i })); await waitFor(() => expect(client.animalsApi.update).toHaveBeenCalledWith('a-1', { animal_id_string: 'M-001', animal_name: 'Mr Whiskers', }) ); }); });