50 Playwright E2E tests across 13 spec files covering all routes and user flows (items CRUD, check-out/in, locations, labels, scanning, search/filter). Uses vitest as runner with playwright-core for browser automation (bun-compatible alternative to @playwright/test). Includes Gherkin .feature files as living documentation, test support infrastructure (IDB seeding, item factories, assertion helpers, layout measurement), and HANDOFF.md covering project state, deployment, and open design decisions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
/**
|
|
* @feature Items List
|
|
* @see e2e/features/pages/items-list.feature
|
|
*/
|
|
import { describe, test, expect } from 'vitest';
|
|
import { setupBrowser } from '../../support/browser';
|
|
import { waitForAppReady, seedItems, clearItems } from '../../support/seed';
|
|
import { buildItem, resetCounter } from '../../support/item-factory';
|
|
import { expectVisible, expectNotVisible } from '../../support/expect';
|
|
|
|
const { getPage } = setupBrowser();
|
|
|
|
describe('Items List', () => {
|
|
test('empty inventory shows placeholder', async () => {
|
|
const page = getPage();
|
|
await page.goto('/');
|
|
await waitForAppReady(page);
|
|
await clearItems(page);
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await expectVisible(page.getByText('No items yet'));
|
|
});
|
|
|
|
test('items are listed with details', async () => {
|
|
const page = getPage();
|
|
await page.goto('/');
|
|
await waitForAppReady(page);
|
|
await seedItems(page, [buildItem({ name: 'Laptop', category: 'Electronics' })]);
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await expectVisible(page.getByText('Laptop'));
|
|
// 'Electronics' appears in both the filter dropdown and the item card
|
|
await expectVisible(page.locator('button').filter({ hasText: 'Electronics' }));
|
|
});
|
|
|
|
test('search filters items by name', async () => {
|
|
const page = getPage();
|
|
await page.goto('/');
|
|
await waitForAppReady(page);
|
|
await seedItems(page, [
|
|
buildItem({ name: 'Laptop', category: 'Electronics' }),
|
|
buildItem({ name: 'Toaster', category: 'Kitchen' }),
|
|
]);
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await page.getByPlaceholder('Search items...').fill('Laptop');
|
|
await expectVisible(page.getByText('Laptop'));
|
|
await expectNotVisible(page.getByText('Toaster'));
|
|
});
|
|
|
|
test('item count is displayed', async () => {
|
|
const page = getPage();
|
|
resetCounter();
|
|
await page.goto('/');
|
|
await waitForAppReady(page);
|
|
const items = Array.from({ length: 5 }, (_, i) => buildItem({ name: `Item ${i + 1}` }));
|
|
await seedItems(page, items);
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await expectVisible(page.getByText('5 of 5 items'));
|
|
});
|
|
|
|
test('filtered count reflects active filters', async () => {
|
|
const page = getPage();
|
|
await page.goto('/');
|
|
await waitForAppReady(page);
|
|
await seedItems(page, [
|
|
buildItem({ name: 'Laptop', category: 'Electronics' }),
|
|
buildItem({ name: 'Toaster', category: 'Kitchen' }),
|
|
]);
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await page.getByPlaceholder('Search items...').fill('Laptop');
|
|
await expectVisible(page.getByText('1 of 2 items'));
|
|
});
|
|
|
|
test('new item button is visible', async () => {
|
|
const page = getPage();
|
|
await page.goto('/items');
|
|
await waitForAppReady(page);
|
|
|
|
await expectVisible(page.getByText('+ New'));
|
|
});
|
|
});
|