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>
102 lines
2.4 KiB
TypeScript
102 lines
2.4 KiB
TypeScript
import type { Item } from '../../src/lib/types';
|
|
|
|
let counter = 0;
|
|
|
|
function nextId(): string {
|
|
counter++;
|
|
const chars = '23456789abcdefghjkmnpqrstuvwxyz';
|
|
let id = '';
|
|
let n = counter;
|
|
for (let i = 0; i < 7; i++) {
|
|
id += chars[n % chars.length];
|
|
n = Math.floor(n / chars.length);
|
|
}
|
|
return id;
|
|
}
|
|
|
|
export interface ItemOverrides extends Partial<Item> {}
|
|
|
|
export function buildItem(overrides: ItemOverrides = {}): Item {
|
|
const shortId = overrides.shortId ?? nextId();
|
|
const now = new Date().toISOString();
|
|
return {
|
|
shortId,
|
|
name: `Test Item ${shortId}`,
|
|
description: '',
|
|
category: '',
|
|
brand: '',
|
|
serialNumber: '',
|
|
color: '',
|
|
purchaseDate: null,
|
|
itemType: 'durable',
|
|
currentQuantity: null,
|
|
originalQuantity: null,
|
|
quantityUnit: null,
|
|
lowThreshold: null,
|
|
expiryDate: null,
|
|
barcodeFormat: 'qr',
|
|
barcodeUri: `https://haus.toph.so/${shortId}`,
|
|
photoIds: [],
|
|
lastSeenAt: null,
|
|
lastSeenTimestamp: null,
|
|
lastUsedAt: null,
|
|
supposedToBeAt: null,
|
|
locationConfidence: 'unknown',
|
|
custodyState: 'checked-in',
|
|
checkedOutSince: null,
|
|
checkedOutReason: null,
|
|
checkedOutFrom: null,
|
|
checkedOutTo: null,
|
|
checkedOutNote: null,
|
|
storageTier: 'warm',
|
|
storageContainerId: null,
|
|
storageContainerLabel: null,
|
|
labelPrinted: false,
|
|
labelPrintedAt: null,
|
|
labelBatchId: null,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
tags: [],
|
|
createdBy: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
export function buildCheckedOutItem(overrides: ItemOverrides = {}): Item {
|
|
const tenDaysAgo = new Date(Date.now() - 10 * 86400000).toISOString();
|
|
return buildItem({
|
|
custodyState: 'checked-out',
|
|
checkedOutSince: tenDaysAgo,
|
|
checkedOutReason: 'in-use',
|
|
checkedOutFrom: 'kueche',
|
|
checkedOutTo: null,
|
|
checkedOutNote: '',
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function buildConsumableItem(overrides: ItemOverrides = {}): Item {
|
|
return buildItem({
|
|
itemType: 'consumable',
|
|
currentQuantity: 3,
|
|
originalQuantity: 10,
|
|
quantityUnit: 'pcs',
|
|
lowThreshold: 5,
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function buildItemAtLocation(locationId: string, overrides: ItemOverrides = {}): Item {
|
|
const now = new Date().toISOString();
|
|
return buildItem({
|
|
lastSeenAt: locationId,
|
|
lastSeenTimestamp: now,
|
|
supposedToBeAt: locationId,
|
|
locationConfidence: 'confirmed',
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function resetCounter() {
|
|
counter = 0;
|
|
}
|