import { describe, it, expect, vi, beforeEach } from 'vitest'; const { mockGet, mockPost, mockPatch, mockDelete } = vi.hoisted(() => ({ mockGet: vi.fn(), mockPost: vi.fn(), mockPatch: vi.fn(), mockDelete: vi.fn(), })); vi.mock('../api-client', () => ({ apiClient: { get: mockGet, post: mockPost, patch: mockPatch, delete: mockDelete }, })); import { listCabinetItems, getCabinetItem, getCabinetSummary, getExpiringSoon, createCabinetItem, updateCabinetItem, adjustCabinetItemQuantity, deleteCabinetItem, } from '../cabinet'; beforeEach(() => vi.clearAllMocks()); describe('cabinet service', () => { it('listCabinetItems with no query', async () => { mockGet.mockResolvedValue({ data: [] }); await listCabinetItems('hh1'); expect(mockGet).toHaveBeenCalledWith('/households/hh1/cabinet'); }); it('listCabinetItems builds query string', async () => { mockGet.mockResolvedValue({ data: [] }); await listCabinetItems('hh1', { medicineId: 'med-1', status: 'active', expiringWithin: 30 }); expect(mockGet).toHaveBeenCalledWith(expect.stringContaining('medicineId=med-1')); expect(mockGet).toHaveBeenCalledWith(expect.stringContaining('status=active')); expect(mockGet).toHaveBeenCalledWith(expect.stringContaining('expiringWithin=30')); }); it('listCabinetItems with cursor and limit', async () => { mockGet.mockResolvedValue({ data: [] }); await listCabinetItems('hh1', { cursor: 'cur1', limit: 20 }); expect(mockGet).toHaveBeenCalledWith(expect.stringContaining('cursor=cur1')); expect(mockGet).toHaveBeenCalledWith(expect.stringContaining('limit=20')); }); it('getCabinetItem calls GET', async () => { mockGet.mockResolvedValue({ _id: 'ci-1' }); await getCabinetItem('hh1', 'ci-1'); expect(mockGet).toHaveBeenCalledWith('/households/hh1/cabinet/ci-1'); }); it('getCabinetSummary calls GET', async () => { mockGet.mockResolvedValue({}); await getCabinetSummary('hh1'); expect(mockGet).toHaveBeenCalledWith('/households/hh1/cabinet/summary'); }); it('getExpiringSoon uses default days', async () => { mockGet.mockResolvedValue({ data: [] }); await getExpiringSoon('hh1'); expect(mockGet).toHaveBeenCalledWith('/households/hh1/cabinet/expiring-soon?days=30'); }); it('getExpiringSoon uses custom days', async () => { mockGet.mockResolvedValue({ data: [] }); await getExpiringSoon('hh1', 7); expect(mockGet).toHaveBeenCalledWith('/households/hh1/cabinet/expiring-soon?days=7'); }); it('createCabinetItem calls POST', async () => { mockPost.mockResolvedValue({ _id: 'ci-1' }); const data = { medicineId: 'med-1' } as never; await createCabinetItem('hh1', data); expect(mockPost).toHaveBeenCalledWith('/households/hh1/cabinet', data); }); it('updateCabinetItem calls PATCH', async () => { mockPatch.mockResolvedValue({ _id: 'ci-1' }); await updateCabinetItem('hh1', 'ci-1', { notes: 'x' } as never); expect(mockPatch).toHaveBeenCalledWith('/households/hh1/cabinet/ci-1', { notes: 'x' }); }); it('adjustCabinetItemQuantity calls POST', async () => { mockPost.mockResolvedValue({ _id: 'ci-1' }); await adjustCabinetItemQuantity('hh1', 'ci-1', { adjustment: -5, reason: 'used' } as never); expect(mockPost).toHaveBeenCalledWith('/households/hh1/cabinet/ci-1/adjust', { adjustment: -5, reason: 'used' }); }); it('deleteCabinetItem calls DELETE', async () => { mockDelete.mockResolvedValue(undefined); await deleteCabinetItem('hh1', 'ci-1'); expect(mockDelete).toHaveBeenCalledWith('/households/hh1/cabinet/ci-1'); }); });