import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { render, screen, fireEvent, cleanup } from '@testing-library/react'; import IngredientTable, { type Ingredient } from '@/app/dashboard/ingredients/IngredientTable'; const makeIngredient = (overrides: Partial = {}): Ingredient => ({ _id: 'ing1', code: 'ING-001', name: 'Butter', category: 'Dairy', subcategory: 'Fresh', quantity: 10, unit: 'kg', unitPrice: 5.00, vat: 9, supplier: 'Acme', createdAt: '2024-01-01T00:00:00Z', updatedAt: '2024-01-02T00:00:00Z', ...overrides, }); describe('IngredientTable', () => { const defaultProps = { ingredients: [makeIngredient()], onView: vi.fn(), onEdit: vi.fn(), onDelete: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { cleanup(); }); it('renders ingredient rows with correct data', () => { render(); expect(screen.getAllByText('Butter').length).toBeGreaterThan(0); expect(screen.getAllByText(/ING-001/).length).toBeGreaterThan(0); }); it('calculates net price correctly (unitPrice * (1 + vat/100))', () => { // unitPrice=5.00, vat=9 → net = 5.00 * 1.09 = 5.45 render(); const netPriceElements = screen.getAllByText(/5\.45/); expect(netPriceElements.length).toBeGreaterThan(0); }); it('toggles individual ingredient selection', () => { render(); const checkboxes = screen.getAllByRole('checkbox') as HTMLInputElement[]; // Find an unchecked ingredient checkbox (not the select-all header) const ingredientCheckbox = checkboxes.find(cb => !cb.checked)!; expect(ingredientCheckbox.checked).toBe(false); fireEvent.click(ingredientCheckbox); expect(ingredientCheckbox.checked).toBe(true); fireEvent.click(ingredientCheckbox); expect(ingredientCheckbox.checked).toBe(false); }); it('toggles all ingredients', () => { const ingredients = [ makeIngredient({ _id: 'ing1', name: 'Butter' }), makeIngredient({ _id: 'ing2', name: 'Milk' }), ]; const { container } = render( ); // Get the select-all checkbox from the desktop table header (thead) const thead = container.querySelector('thead'); const selectAllCheckbox = thead!.querySelector('input[type="checkbox"]') as HTMLInputElement; // Select all fireEvent.click(selectAllCheckbox); expect(selectAllCheckbox.checked).toBe(true); // Verify ingredient checkboxes in tbody are also checked const tbody = container.querySelector('tbody'); const tbodyCheckboxes = tbody!.querySelectorAll('input[type="checkbox"]') as NodeListOf; tbodyCheckboxes.forEach(cb => expect(cb.checked).toBe(true)); // Deselect all fireEvent.click(selectAllCheckbox); expect(selectAllCheckbox.checked).toBe(false); tbodyCheckboxes.forEach(cb => expect(cb.checked).toBe(false)); }); it('renders empty when ingredients list is empty', () => { const { container } = render( ); const tbody = container.querySelector('tbody'); expect(tbody?.children.length ?? 0).toBe(0); }); it('calculates net price with 0% VAT', () => { const ingredients = [makeIngredient({ unitPrice: 10.00, vat: 0 })]; render(); // net = 10.00 * 1.0 = 10.00 const netPriceElements = screen.getAllByText(/10\.00/); expect(netPriceElements.length).toBeGreaterThan(0); }); it('calculates net price with high VAT', () => { const ingredients = [makeIngredient({ unitPrice: 10.00, vat: 25 })]; render(); // net = 10.00 * 1.25 = 12.50 const netPriceElements = screen.getAllByText(/12\.50/); expect(netPriceElements.length).toBeGreaterThan(0); }); });