const request = require('supertest'); jest.mock('../src/lib/prisma', () => require('./__mocks__/prisma')); const prisma = require('../src/lib/prisma'); const app = require('../src/app'); const ANIMAL_ID = 'dddddddd-0000-0000-0000-000000000001'; const STATUS = { id: 'eeeeeeee-0000-0000-0000-000000000001', animal_id: ANIMAL_ID, date: new Date('2024-06-01').toISOString(), experiment_description: 'Baseline measurement', vitals: 'HR 72, Temp 37.2', treatment: 'Control', notes: 'Healthy', }; beforeEach(() => jest.clearAllMocks()); describe('GET /api/daily-statuses', () => { it('returns statuses filtered by animalId', async () => { prisma.dailyStatus.findMany.mockResolvedValue([STATUS]); const res = await request(app).get(`/api/daily-statuses?animalId=${ANIMAL_ID}`); expect(res.status).toBe(200); expect(res.body).toHaveLength(1); expect(res.body[0].vitals).toBe('HR 72, Temp 37.2'); }); it('returns 422 for invalid animalId UUID', async () => { const res = await request(app).get('/api/daily-statuses?animalId=invalid'); expect(res.status).toBe(422); }); }); describe('GET /api/daily-statuses/:id', () => { it('returns a single status entry', async () => { prisma.dailyStatus.findUnique.mockResolvedValue({ ...STATUS, animal: {} }); const res = await request(app).get(`/api/daily-statuses/${STATUS.id}`); expect(res.status).toBe(200); expect(res.body.id).toBe(STATUS.id); }); it('returns 404 for unknown id', async () => { prisma.dailyStatus.findUnique.mockResolvedValue(null); const res = await request(app).get('/api/daily-statuses/00000000-0000-0000-0000-000000000000'); expect(res.status).toBe(404); }); }); describe('POST /api/daily-statuses', () => { it('creates status and returns 201 with UUID', async () => { prisma.dailyStatus.create.mockResolvedValue(STATUS); prisma.auditLog.create.mockResolvedValue({}); const res = await request(app) .post('/api/daily-statuses') .send({ animal_id: ANIMAL_ID, date: '2024-06-01', vitals: 'HR 72' }); expect(res.status).toBe(201); expect(res.body.id).toMatch(/^[0-9a-f-]{36}$/i); expect(prisma.auditLog.create).toHaveBeenCalled(); }); it('returns 422 when animal_id is missing', async () => { const res = await request(app) .post('/api/daily-statuses') .send({ date: '2024-06-01' }); expect(res.status).toBe(422); expect(res.body.details).toEqual( expect.arrayContaining([expect.objectContaining({ field: 'animal_id' })]) ); }); it('returns 422 when date is missing', async () => { const res = await request(app) .post('/api/daily-statuses') .send({ animal_id: ANIMAL_ID }); expect(res.status).toBe(422); expect(res.body.details).toEqual( expect.arrayContaining([expect.objectContaining({ field: 'date' })]) ); }); it('returns 422 when date is not a valid ISO date', async () => { const res = await request(app) .post('/api/daily-statuses') .send({ animal_id: ANIMAL_ID, date: 'not-a-date' }); expect(res.status).toBe(422); }); }); describe('PUT /api/daily-statuses/:id', () => { it('updates status and writes UPDATE audit log', async () => { const updated = { ...STATUS, vitals: 'HR 80' }; prisma.dailyStatus.findUnique .mockResolvedValueOnce(STATUS) .mockResolvedValueOnce(updated); prisma.dailyStatus.update.mockResolvedValue(updated); prisma.auditLog.create.mockResolvedValue({}); const res = await request(app) .put(`/api/daily-statuses/${STATUS.id}`) .send({ vitals: 'HR 80' }); expect(res.status).toBe(200); expect(res.body.vitals).toBe('HR 80'); expect(prisma.auditLog.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ action: 'UPDATE' }) }) ); }); it('returns 422 when date format is invalid', async () => { prisma.dailyStatus.findUnique.mockResolvedValue(STATUS); const res = await request(app) .put(`/api/daily-statuses/${STATUS.id}`) .send({ date: 'garbage' }); expect(res.status).toBe(422); }); }); describe('DELETE /api/daily-statuses/:id', () => { it('deletes status and writes DELETE audit log', async () => { prisma.dailyStatus.findUnique.mockResolvedValue(STATUS); prisma.dailyStatus.delete.mockResolvedValue(STATUS); prisma.auditLog.create.mockResolvedValue({}); const res = await request(app).delete(`/api/daily-statuses/${STATUS.id}`); expect(res.status).toBe(204); expect(prisma.auditLog.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ action: 'DELETE' }) }) ); }); });