121 lines
4.0 KiB
TypeScript
121 lines
4.0 KiB
TypeScript
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> = {}): 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(<IngredientTable {...defaultProps} />);
|
|
|
|
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(<IngredientTable {...defaultProps} />);
|
|
|
|
const netPriceElements = screen.getAllByText(/5\.45/);
|
|
expect(netPriceElements.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('toggles individual ingredient selection', () => {
|
|
render(<IngredientTable {...defaultProps} />);
|
|
|
|
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(
|
|
<IngredientTable {...defaultProps} ingredients={ingredients} />
|
|
);
|
|
|
|
// 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<HTMLInputElement>;
|
|
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(
|
|
<IngredientTable {...defaultProps} ingredients={[]} />
|
|
);
|
|
|
|
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(<IngredientTable {...defaultProps} ingredients={ingredients} />);
|
|
|
|
// 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(<IngredientTable {...defaultProps} ingredients={ingredients} />);
|
|
|
|
// net = 10.00 * 1.25 = 12.50
|
|
const netPriceElements = screen.getAllByText(/12\.50/);
|
|
expect(netPriceElements.length).toBeGreaterThan(0);
|
|
});
|
|
});
|