import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import type React from 'react'; import userEvent from '@testing-library/user-event'; const { mockUseApi } = vi.hoisted(() => ({ mockUseApi: vi.fn() })); const { mockUseParams } = vi.hoisted(() => ({ mockUseParams: vi.fn() })); const { mockGetMedicine, mockListMedicineProducts, mockCreateMedicineProduct, mockDeleteMedicineProduct, mockUpdateMedicine, mockUpdateMedicineProduct, } = vi.hoisted(() => ({ mockGetMedicine: vi.fn(), mockListMedicineProducts: vi.fn(), mockCreateMedicineProduct: vi.fn(), mockDeleteMedicineProduct: vi.fn(), mockUpdateMedicine: vi.fn(), mockUpdateMedicineProduct: vi.fn(), })); const { mockListCabinetItems, mockAdjustCabinetItemQuantity, mockDeleteCabinetItem } = vi.hoisted( () => ({ mockListCabinetItems: vi.fn(), mockAdjustCabinetItemQuantity: vi.fn(), mockDeleteCabinetItem: vi.fn(), }), ); vi.mock('@/lib/useApi', () => ({ useApi: mockUseApi })); vi.mock('next/navigation', () => ({ useParams: mockUseParams })); vi.mock('next/link', () => ({ default: (props: { href?: string; children: React.ReactNode }) => ( {props.children} ), })); vi.mock('@/services/medicines', () => ({ getMedicine: mockGetMedicine, listMedicineProducts: mockListMedicineProducts, createMedicineProduct: mockCreateMedicineProduct, deleteMedicineProduct: mockDeleteMedicineProduct, updateMedicine: mockUpdateMedicine, updateMedicineProduct: mockUpdateMedicineProduct, })); vi.mock('@/services/cabinet', () => ({ listCabinetItems: mockListCabinetItems, adjustCabinetItemQuantity: mockAdjustCabinetItemQuantity, deleteCabinetItem: mockDeleteCabinetItem, })); import MedicineDetailPage from '../../../../../src/app/(dashboard)/medicines/[id]/page'; const medicine = { _id: 'med-1', name: 'Metformin', form: 'tablet', strength: 500, strengthUnit: 'mg', category: 'prescription', notes: '', tags: [], createdAt: '2026-01-01T00:00:00.000Z', updatedAt: '2026-01-01T00:00:00.000Z', }; const emptyProducts = { data: [], pagination: { cursor: null, hasMore: false } }; const emptyItems = { data: [], pagination: { cursor: null, hasMore: false } }; beforeEach(() => { vi.clearAllMocks(); mockUseParams.mockReturnValue({ id: 'med-1' }); mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false }); mockGetMedicine.mockResolvedValue(medicine); mockListMedicineProducts.mockResolvedValue(emptyProducts); mockListCabinetItems.mockResolvedValue(emptyItems); }); describe('MedicineDetailPage', () => { it('shows loading skeleton when session is loading', () => { mockUseApi.mockReturnValue({ householdId: null, isLoading: true }); render(); expect(screen.queryByText('Metformin')).not.toBeInTheDocument(); }); it('renders medicine name and sections after load', async () => { render(); await waitFor(() => expect(screen.getByText('Metformin')).toBeInTheDocument()); expect(screen.getByText('Inventory')).toBeInTheDocument(); expect(screen.getByText('Products (Brands/Packages)')).toBeInTheDocument(); }); it('shows error when medicine fails to load', async () => { mockGetMedicine.mockRejectedValue(new Error('Not found')); render(); await waitFor(() => expect(screen.getByText('Not found')).toBeInTheDocument()); }); it('shows empty inventory state', async () => { render(); await waitFor(() => expect(screen.getByText(/No inventory items/)).toBeInTheDocument()); }); it('shows empty products state', async () => { render(); await waitFor(() => expect(screen.getByText(/No products yet/)).toBeInTheDocument()); }); it('toggles Add Product form', async () => { render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); expect(screen.getByText('Add Product', { selector: 'h3' })).toBeInTheDocument(); await userEvent.click(screen.getAllByText('Cancel')[0]); expect(screen.queryByText('Add Product', { selector: 'h3' })).not.toBeInTheDocument(); }); it('toggles edit medicine form', async () => { render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); expect(screen.getByText('Edit Medicine')).toBeInTheDocument(); await userEvent.click(screen.getByText('Cancel')); expect(screen.queryByText('Edit Medicine')).not.toBeInTheDocument(); }); it('saves medicine edit', async () => { mockUpdateMedicine.mockResolvedValue({ ...medicine, name: 'Metformin XR' }); render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); await userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => expect(mockUpdateMedicine).toHaveBeenCalledWith('hh1', 'med-1', expect.any(Object)), ); }); it('deletes a product after confirmation', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Glucophage', packageSize: 60, packageUnit: 'tablet', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); mockDeleteMedicineProduct.mockResolvedValue({}); vi.spyOn(window, 'confirm').mockReturnValue(true); render(); await waitFor(() => screen.getByText('Glucophage')); await userEvent.click(screen.getByTitle('Delete')); expect(mockDeleteMedicineProduct).toHaveBeenCalledWith('hh1', 'prod-1'); }); it('submits CreateProductForm', async () => { mockCreateMedicineProduct.mockResolvedValue({ _id: 'prod-new', brand: 'NewBrand', packageSize: 30, packageUnit: 'tablet', source: 'manual', }); render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByPlaceholderText('e.g. CVS Health')); fireEvent.change(screen.getByPlaceholderText('e.g. CVS Health'), { target: { value: 'NewBrand' }, }); fireEvent.change(screen.getByPlaceholderText('90'), { target: { value: '30' }, }); fireEvent.submit(screen.getByPlaceholderText('e.g. CVS Health').closest('form')!); await waitFor(() => expect(mockCreateMedicineProduct).toHaveBeenCalledWith( 'hh1', 'med-1', expect.objectContaining({ brand: 'NewBrand' }), ), ); }); it('shows create product error on failure', async () => { mockCreateMedicineProduct.mockRejectedValue(new Error('Duplicate brand')); render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByPlaceholderText('e.g. CVS Health')); fireEvent.change(screen.getByPlaceholderText('e.g. CVS Health'), { target: { value: 'Brand' }, }); fireEvent.submit(screen.getByPlaceholderText('e.g. CVS Health').closest('form')!); await waitFor(() => expect(screen.getByText('Duplicate brand')).toBeInTheDocument()); }); it('opens and saves product edit form', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Glucophage', packageSize: 60, packageUnit: 'tablet', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); mockUpdateMedicineProduct.mockResolvedValue({ _id: 'prod-1', brand: 'Glucophage XR', packageSize: 60, packageUnit: 'tablet', source: 'manual', }); render(); await waitFor(() => screen.getByText('Glucophage')); // First Edit title is the medicine edit, second is the product edit await userEvent.click(screen.getAllByTitle('Edit')[1]!); await waitFor(() => screen.getByDisplayValue('Glucophage')); fireEvent.change(screen.getByDisplayValue('Glucophage'), { target: { value: 'Glucophage XR' }, }); fireEvent.submit(screen.getByDisplayValue('Glucophage XR').closest('form')!); await waitFor(() => expect(mockUpdateMedicineProduct).toHaveBeenCalledWith( 'hh1', 'prod-1', expect.objectContaining({ brand: 'Glucophage XR' }), ), ); }); it('shows concentration fields when injection medicine with ml unit', async () => { mockGetMedicine.mockResolvedValue({ ...medicine, form: 'injection', }); render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByPlaceholderText('e.g. CVS Health')); // Change package unit to ml to show concentration fields const unitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).value === 'vial') as HTMLSelectElement; fireEvent.change(unitSelect!, { target: { value: 'ml' } }); await waitFor(() => expect(screen.getByPlaceholderText('e.g. 100')).toBeInTheDocument()); }); it('deletes a product after confirmation', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Glucophage', packageSize: 60, packageUnit: 'tablet', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); mockDeleteMedicineProduct.mockResolvedValue({}); vi.spyOn(window, 'confirm').mockReturnValue(true); render(); await waitFor(() => screen.getByText('Glucophage')); await userEvent.click(screen.getByTitle('Delete')); expect(mockDeleteMedicineProduct).toHaveBeenCalledWith('hh1', 'prod-1'); }); it('edits injection product and changes concentration fields', async () => { mockGetMedicine.mockResolvedValue({ ...medicine, form: 'injection', }); mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Insulin', packageSize: 10, packageUnit: 'ml', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Insulin')); await userEvent.click(screen.getAllByTitle('Edit')[1]!); await waitFor(() => screen.getByDisplayValue('Insulin')); // concentration field should be visible since form=injection, unit=ml await waitFor(() => screen.getByPlaceholderText('e.g. 100')); fireEvent.change(screen.getByPlaceholderText('e.g. 100'), { target: { value: '100' } }); // Change concentration unit const concUnitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).options[0]?.text === '--') as HTMLSelectElement; if (concUnitSelect) { fireEvent.change(concUnitSelect, { target: { value: 'mg/ml' } }); } expect(screen.getByDisplayValue('Insulin')).toBeInTheDocument(); }); it('changes fields in the product edit inline form', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Glucophage', packageSize: 60, packageUnit: 'tablet', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Glucophage')); await userEvent.click(screen.getAllByTitle('Edit')[1]!); await waitFor(() => screen.getByDisplayValue('Glucophage')); // Change package size fireEvent.change(screen.getByDisplayValue('60'), { target: { value: '90' } }); // Change package unit const unitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).value === 'tablet') as HTMLSelectElement; fireEvent.change(unitSelect!, { target: { value: 'capsule' } }); expect(screen.getByDisplayValue('Glucophage')).toBeInTheDocument(); }); it('changes manufacturer, concentration and notes fields in product form', async () => { mockGetMedicine.mockResolvedValue({ ...medicine, form: 'injection', }); render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByPlaceholderText('e.g. Pfizer')); // Change manufacturer (truthy) then clear (falsy → undefined) fireEvent.change(screen.getByPlaceholderText('e.g. Pfizer'), { target: { value: 'Pfizer' } }); fireEvent.change(screen.getByPlaceholderText('e.g. Pfizer'), { target: { value: '' } }); // Change notes (truthy) then clear (falsy → undefined) fireEvent.change(screen.getByPlaceholderText('Any additional notes'), { target: { value: 'Store in fridge' }, }); fireEvent.change(screen.getByPlaceholderText('Any additional notes'), { target: { value: '' }, }); // Change unit to ml to show concentration fields const unitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).value === 'vial') as HTMLSelectElement; fireEvent.change(unitSelect!, { target: { value: 'ml' } }); await waitFor(() => screen.getByPlaceholderText('e.g. 100')); // Set concentration (truthy) then clear (falsy → undefined) fireEvent.change(screen.getByPlaceholderText('e.g. 100'), { target: { value: '50' } }); fireEvent.change(screen.getByPlaceholderText('e.g. 100'), { target: { value: '' } }); // Change concentration unit const concUnitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).value === '') as HTMLSelectElement; if (concUnitSelect) { fireEvent.change(concUnitSelect, { target: { value: 'mg/ml' } }); } expect(screen.getByPlaceholderText('e.g. Pfizer')).toBeInTheDocument(); }); it('changes fields in the product edit inline form (manufacturer, notes)', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Glucophage', packageSize: 60, packageUnit: 'tablet', source: 'manual', manufacturer: '', notes: '', }, ], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Glucophage')); await userEvent.click(screen.getAllByTitle('Edit')[1]!); await waitFor(() => screen.getByDisplayValue('Glucophage')); // Find the manufacturer input (empty string value, maxLength 200) const allInputs = document.querySelectorAll('input[maxLength="200"]'); // First is brand (Glucophage), second is manufacturer if (allInputs.length > 1) { fireEvent.change(allInputs[1]!, { target: { value: 'Pfizer' } }); // Clear manufacturer to cover the || undefined false branch fireEvent.change(allInputs[1]!, { target: { value: '' } }); } // Change notes (maxLength 1000 input) const notesInput = document.querySelector('input[maxLength="1000"]') as HTMLElement; if (notesInput) { fireEvent.change(notesInput, { target: { value: 'Keep refrigerated' } }); } expect(screen.getByDisplayValue('Glucophage')).toBeInTheDocument(); }); it('adjusts cabinet item quantity', async () => { mockListCabinetItems.mockResolvedValue({ data: [ { _id: 'ci-1', quantity: 10, unit: 'tablet', status: 'active', }, ], pagination: { cursor: null, hasMore: false }, }); mockAdjustCabinetItemQuantity.mockResolvedValue({}); render(); await waitFor(() => screen.getByTitle('Add 1')); await userEvent.click(screen.getByTitle('Add 1')); expect(mockAdjustCabinetItemQuantity).toHaveBeenCalledWith('hh1', 'ci-1', { delta: 1 }); }); it('takes 1 from cabinet item', async () => { mockListCabinetItems.mockResolvedValue({ data: [{ _id: 'ci-1', quantity: 10, unit: 'tablet', status: 'active' }], pagination: { cursor: null, hasMore: false }, }); mockAdjustCabinetItemQuantity.mockResolvedValue({}); render(); await waitFor(() => screen.getByTitle('Take 1')); await userEvent.click(screen.getByTitle('Take 1')); expect(mockAdjustCabinetItemQuantity).toHaveBeenCalledWith('hh1', 'ci-1', { delta: -1 }); }); it('deletes cabinet item after confirmation', async () => { mockListCabinetItems.mockResolvedValue({ data: [{ _id: 'ci-1', quantity: 10, unit: 'tablet', status: 'active' }], pagination: { cursor: null, hasMore: false }, }); mockDeleteCabinetItem.mockResolvedValue({}); vi.spyOn(window, 'confirm').mockReturnValue(true); render(); await waitFor(() => screen.getByTitle('Delete')); await userEvent.click(screen.getByTitle('Delete')); expect(mockDeleteCabinetItem).toHaveBeenCalledWith('hh1', 'ci-1'); }); it('cancels CreateProductForm with internal Cancel button', async () => { render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByText('Add Product', { selector: 'h3' })); // Click the Cancel button inside the form (last Cancel button in DOM) const cancelButtons = screen.getAllByText('Cancel'); await userEvent.click(cancelButtons[cancelButtons.length - 1]!); expect(screen.queryByText('Add Product', { selector: 'h3' })).not.toBeInTheDocument(); }); it('changes all fields in edit medicine form', async () => { render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); await waitFor(() => screen.getByPlaceholderText('e.g. daily, morning')); // Change name const nameInput = document.querySelector('input[maxLength="200"]') as HTMLElement; if (nameInput) fireEvent.change(nameInput, { target: { value: 'Metformin XR' } }); // Change form select const formSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).options[0]?.value === 'tablet') as HTMLSelectElement; if (formSelect) fireEvent.change(formSelect, { target: { value: 'capsule' } }); // Change strength const strengthInput = document.querySelector('input[min="0.01"]') as HTMLElement; if (strengthInput) fireEvent.change(strengthInput, { target: { value: '250' } }); // Change category select const catSelect = screen .getAllByRole('combobox') .find( (s) => (s as HTMLSelectElement).options[0]?.value === 'prescription', ) as HTMLSelectElement; if (catSelect) fireEvent.change(catSelect, { target: { value: 'otc' } }); // Change notes (truthy value) const notesInputs = document.querySelectorAll('input[maxLength="1000"]'); if (notesInputs[0]) fireEvent.change(notesInputs[0]!, { target: { value: 'Take with food' } }); // Also clear notes (covers the || undefined false branch) if (notesInputs[0]) fireEvent.change(notesInputs[0]!, { target: { value: '' } }); // Change tags fireEvent.change(screen.getByPlaceholderText('e.g. daily, morning'), { target: { value: 'morning, daily' }, }); expect(screen.getByPlaceholderText('e.g. daily, morning')).toBeInTheDocument(); }); it('shows error when update medicine fails', async () => { mockUpdateMedicine.mockRejectedValue(new Error('Update failed')); render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); await userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => expect(screen.getByText('Update failed')).toBeInTheDocument()); }); it('dismisses error in detail page', async () => { mockUpdateMedicine.mockRejectedValue(new Error('Update failed')); render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); await userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => screen.getByText('Update failed')); await userEvent.click(screen.getByText('Dismiss')); expect(screen.queryByText('Update failed')).not.toBeInTheDocument(); }); it('changes strength unit in edit medicine form', async () => { render(); await waitFor(() => screen.getByTitle('Edit')); await userEvent.click(screen.getByTitle('Edit')); await waitFor(() => screen.getByText('Edit Medicine')); // Change strength unit select (the one with 'mg' options) const unitSelect = screen .getAllByRole('combobox') .find((s) => (s as HTMLSelectElement).value === 'mg') as HTMLSelectElement; if (unitSelect) fireEvent.change(unitSelect, { target: { value: 'mcg' } }); expect(screen.getByText('Edit Medicine')).toBeInTheDocument(); }); it('cancels product edit form', async () => { mockListMedicineProducts.mockResolvedValue({ data: [{ _id: 'mp-1', brand: 'Bayer', packageSize: 100, unit: 'tablet', form: 'tablet' }], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Bayer')); const editButtons = screen.getAllByTitle('Edit'); await userEvent.click(editButtons[editButtons.length - 1]!); await waitFor(() => screen.getByDisplayValue('Bayer')); // Click Cancel to close product edit form await userEvent.click(screen.getByRole('button', { name: 'Cancel' })); expect(screen.queryByDisplayValue('Bayer')).not.toBeInTheDocument(); }); it('shows fallback error when non-Error thrown on create product', async () => { mockCreateMedicineProduct.mockRejectedValue('create failed'); render(); await waitFor(() => screen.getByText('Add Product')); await userEvent.click(screen.getByText('Add Product')); await waitFor(() => screen.getByPlaceholderText('e.g. CVS Health')); fireEvent.change(screen.getByPlaceholderText('e.g. CVS Health'), { target: { value: 'Brand X' }, }); fireEvent.submit(screen.getByPlaceholderText('e.g. CVS Health').closest('form')!); await waitFor(() => expect(screen.getByText('Failed to create product')).toBeInTheDocument()); }); it('shows fallback error when non-Error thrown on update product', async () => { mockListMedicineProducts.mockResolvedValue({ data: [{ _id: 'mp-1', brand: 'Bayer', packageSize: 100, unit: 'tablet', form: 'tablet' }], pagination: { cursor: null, hasMore: false }, }); mockUpdateMedicineProduct.mockRejectedValue('update failed'); render(); await waitFor(() => screen.getByText('Bayer')); // Click the product Edit button (last Edit button, not the medicine one) const editButtons = screen.getAllByTitle('Edit'); await userEvent.click(editButtons[editButtons.length - 1]!); await waitFor(() => screen.getByDisplayValue('Bayer')); fireEvent.submit(screen.getByDisplayValue('Bayer').closest('form')!); await waitFor(() => expect(screen.getByText('Failed to update product')).toBeInTheDocument()); }); it('shows fallback error when non-Error thrown on delete product', async () => { mockListMedicineProducts.mockResolvedValue({ data: [{ _id: 'mp-1', brand: 'Bayer', packageSize: 100, unit: 'tablet', form: 'tablet' }], pagination: { cursor: null, hasMore: false }, }); mockDeleteMedicineProduct.mockRejectedValue('delete failed'); vi.spyOn(window, 'confirm').mockReturnValue(true); render(); await waitFor(() => screen.getByText('Bayer')); await userEvent.click(screen.getAllByTitle('Delete')[0]!); await waitFor(() => expect(screen.getByText('Failed to delete product')).toBeInTheDocument()); }); it('shows fallback error when non-Error thrown on adjust cabinet', async () => { mockListCabinetItems.mockResolvedValue({ data: [{ _id: 'ci-1', quantity: 10, unit: 'tablet', status: 'active' }], pagination: { cursor: null, hasMore: false }, }); mockAdjustCabinetItemQuantity.mockRejectedValue('adjust failed'); render(); await waitFor(() => screen.getByTitle('Take 1')); await userEvent.click(screen.getByTitle('Take 1')); await waitFor(() => expect(screen.getByText('Failed to adjust quantity')).toBeInTheDocument()); }); it('shows product concentration and manufacturer in display', async () => { mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'mp-1', brand: 'Lantus', packageSize: 10, packageUnit: 'ml', concentration: 100, concentrationUnit: 'IU/ml', manufacturer: 'Sanofi', notes: 'Refrigerate after opening', }, ], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Lantus')); expect(screen.getByText(/100 IU\/ml/)).toBeInTheDocument(); expect(screen.getByText(/Sanofi/)).toBeInTheDocument(); expect(screen.getByText('Refrigerate after opening')).toBeInTheDocument(); }); it('clears concentration and notes in edit inline form for injection', async () => { mockGetMedicine.mockResolvedValue({ ...medicine, form: 'injection' }); mockListMedicineProducts.mockResolvedValue({ data: [ { _id: 'prod-1', brand: 'Lantus', packageSize: 10, packageUnit: 'ml', source: 'manual', }, ], pagination: { cursor: null, hasMore: false }, }); render(); await waitFor(() => screen.getByText('Lantus')); await userEvent.click(screen.getAllByTitle('Edit')[1]!); await waitFor(() => screen.getByDisplayValue('Lantus')); await waitFor(() => screen.getByPlaceholderText('e.g. 100')); // Set concentration then clear (covers undefined branch at line 675) fireEvent.change(screen.getByPlaceholderText('e.g. 100'), { target: { value: '100' } }); fireEvent.change(screen.getByPlaceholderText('e.g. 100'), { target: { value: '' } }); // Set notes then clear (covers undefined branch at line 720) const notesInput = document.querySelector('input[maxLength="1000"]') as HTMLElement; if (notesInput) fireEvent.change(notesInput, { target: { value: 'Refrigerate' } }); if (notesInput) fireEvent.change(notesInput, { target: { value: '' } }); expect(screen.getByDisplayValue('Lantus')).toBeInTheDocument(); }); it('shows fallback error when non-Error thrown on delete cabinet', async () => { mockListCabinetItems.mockResolvedValue({ data: [{ _id: 'ci-1', quantity: 10, unit: 'tablet', status: 'active' }], pagination: { cursor: null, hasMore: false }, }); mockDeleteCabinetItem.mockRejectedValue('delete failed'); vi.spyOn(window, 'confirm').mockReturnValue(true); render(); await waitFor(() => screen.getAllByTitle('Delete')); await userEvent.click(screen.getAllByTitle('Delete')[0]!); await waitFor(() => expect(screen.getByText('Failed to delete cabinet item')).toBeInTheDocument(), ); }); });