modified: package-lock.json modified: package.json modified: src/App.tsx modified: src/screens/ActivePickListScreen.test.tsx modified: src/screens/ActivePickListScreen.tsx modified: src/screens/BarcodeScannerScreen.tsx modified: src/screens/HomeScreen.tsx modified: src/screens/ImportExportScreen.tsx modified: src/screens/ManageAreasScreen.test.tsx modified: src/screens/ManageAreasScreen.tsx modified: src/screens/ManageCategoriesScreen.test.tsx modified: src/screens/ManageCategoriesScreen.tsx modified: src/screens/ManageProductsScreen.test.tsx modified: src/screens/ManageProductsScreen.tsx modified: src/screens/PickListsScreen.test.tsx modified: src/screens/PickListsScreen.tsx modified: src/screens/StartPickListScreen.test.tsx modified: src/screens/StartPickListScreen.tsx modified: tsconfig.json modified: vite.config.ts
175 lines
5.1 KiB
TypeScript
175 lines
5.1 KiB
TypeScript
import { MemoryRouter } from 'react-router-dom';
|
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import StartPickListScreen from './StartPickListScreen';
|
|
|
|
const navigateMock = vi.fn();
|
|
|
|
vi.mock('react-router-dom', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('react-router-dom')>();
|
|
return {
|
|
...actual,
|
|
useNavigate: () => navigateMock,
|
|
};
|
|
});
|
|
|
|
const areasMock = [{ id: 'area-1', name: 'Front Counter', created_at: 0, updated_at: 0 }];
|
|
const categoriesMock = [
|
|
{ id: 'cat-1', name: 'Drinks', created_at: 0, updated_at: 0 },
|
|
{ id: 'cat-2', name: 'Snacks', created_at: 0, updated_at: 0 },
|
|
];
|
|
|
|
const productsMock = [
|
|
{
|
|
id: 'prod-1',
|
|
name: 'Soda',
|
|
category: 'Drinks',
|
|
unit_type: 'unit',
|
|
bulk_name: 'box',
|
|
archived: false,
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
},
|
|
{
|
|
id: 'prod-2',
|
|
name: 'Chips',
|
|
category: 'Snacks',
|
|
unit_type: 'unit',
|
|
bulk_name: 'box',
|
|
archived: false,
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
},
|
|
{
|
|
id: 'prod-3',
|
|
name: 'Old Soda',
|
|
category: 'Drinks',
|
|
unit_type: 'unit',
|
|
bulk_name: 'box',
|
|
archived: true,
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
},
|
|
];
|
|
|
|
const pickListAddMock = vi.fn();
|
|
const pickItemsBulkAddMock = vi.fn();
|
|
const transactionMock = vi.fn();
|
|
const productsToArrayMock = vi.fn();
|
|
|
|
vi.mock('../hooks/dataHooks', () => ({
|
|
useAreas: () => areasMock,
|
|
useCategories: () => categoriesMock,
|
|
}));
|
|
|
|
vi.mock('../context/DBProvider', () => ({
|
|
useDatabase: () => ({
|
|
pickLists: { add: pickListAddMock },
|
|
pickItems: { bulkAdd: pickItemsBulkAddMock },
|
|
products: { toArray: productsToArrayMock },
|
|
transaction: transactionMock,
|
|
}),
|
|
}));
|
|
|
|
vi.mock('uuid', () => ({
|
|
v4: () => 'generated-id',
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
navigateMock.mockReset();
|
|
pickListAddMock.mockReset();
|
|
pickItemsBulkAddMock.mockReset();
|
|
transactionMock.mockReset();
|
|
productsToArrayMock.mockReset();
|
|
productsToArrayMock.mockResolvedValue(productsMock);
|
|
transactionMock.mockImplementation(async (_mode: string, ...args: unknown[]) => {
|
|
const callback = args[args.length - 1] as () => Promise<void>;
|
|
await callback();
|
|
});
|
|
});
|
|
|
|
describe('StartPickListScreen', () => {
|
|
it('shows category selection controls', () => {
|
|
render(
|
|
<MemoryRouter>
|
|
<StartPickListScreen />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
categoriesMock.forEach((category) => {
|
|
expect(screen.getByRole('checkbox', { name: category.name })).toBeInTheDocument();
|
|
});
|
|
|
|
expect(screen.getByRole('checkbox', { name: /add new products/i })).toBeChecked();
|
|
});
|
|
|
|
it('prefills a new pick list with products from selected categories', async () => {
|
|
const user = userEvent.setup();
|
|
|
|
render(
|
|
<MemoryRouter>
|
|
<StartPickListScreen />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
await user.click(screen.getByLabelText(/area/i));
|
|
await user.click(screen.getByRole('option', { name: /front counter/i }));
|
|
|
|
await user.click(screen.getByRole('checkbox', { name: /drinks/i }));
|
|
await user.click(screen.getByRole('checkbox', { name: /snacks/i }));
|
|
|
|
await user.click(screen.getByRole('button', { name: /save pick list/i }));
|
|
|
|
await waitFor(() => expect(pickListAddMock).toHaveBeenCalled());
|
|
await waitFor(() => expect(pickItemsBulkAddMock).toHaveBeenCalled());
|
|
|
|
const pickItems = pickItemsBulkAddMock.mock.calls[0][0];
|
|
|
|
expect(pickItems).toHaveLength(2);
|
|
expect(pickItems.map((item: any) => item.product_id).sort()).toEqual(['prod-1', 'prod-2']);
|
|
pickItems.forEach((item: any) => {
|
|
expect(item.pick_list_id).toBe('generated-id');
|
|
expect(item.is_carton).toBe(false);
|
|
expect(item.quantity).toBe(1);
|
|
expect(item.status).toBe('pending');
|
|
});
|
|
|
|
const pickListRecord = pickListAddMock.mock.calls[0][0];
|
|
expect(pickListRecord.categories).toEqual(['Drinks', 'Snacks']);
|
|
expect(pickListRecord.auto_add_new_products).toBe(true);
|
|
});
|
|
|
|
it('deduplicates products when selected categories include overlaps', async () => {
|
|
const user = userEvent.setup();
|
|
productsToArrayMock.mockResolvedValue([
|
|
...productsMock,
|
|
{ ...productsMock[0] },
|
|
{ ...productsMock[1], id: 'prod-2-duplicate' },
|
|
]);
|
|
|
|
render(
|
|
<MemoryRouter>
|
|
<StartPickListScreen />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
await user.click(screen.getByLabelText(/area/i));
|
|
await user.click(screen.getByRole('option', { name: /front counter/i }));
|
|
|
|
await user.click(screen.getByRole('checkbox', { name: /drinks/i }));
|
|
await user.click(screen.getByRole('checkbox', { name: /snacks/i }));
|
|
|
|
await user.click(screen.getByRole('button', { name: /save pick list/i }));
|
|
|
|
await waitFor(() => expect(pickItemsBulkAddMock).toHaveBeenCalled());
|
|
|
|
const pickItems = pickItemsBulkAddMock.mock.calls[0][0];
|
|
const uniqueProductIds = new Set(pickItems.map((item: any) => item.product_id));
|
|
|
|
expect(pickItems).toHaveLength(2);
|
|
expect(uniqueProductIds.size).toBe(2);
|
|
expect(uniqueProductIds).toEqual(new Set(['prod-1', 'prod-2']));
|
|
});
|
|
});
|