kammer/e2e/support/browser.ts
Christopher Mühl 307ef24b78 test: E2E test suite + handoff documentation
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>
2026-02-26 20:53:08 +01:00

70 lines
1.8 KiB
TypeScript

import { chromium, type Browser, type Page, type BrowserContext } from 'playwright-core';
import { e2eConfig } from '../playwright.config';
import { afterAll, beforeAll, beforeEach, afterEach } from 'vitest';
import { execSync } from 'child_process';
let browser: Browser;
let context: BrowserContext;
let page: Page;
/**
* Find the Chromium executable installed by Playwright.
*/
function findChromium(): string {
// Check standard Playwright cache locations
const cacheDir = process.env.PLAYWRIGHT_BROWSERS_PATH
|| `${process.env.HOME}/Library/Caches/ms-playwright`;
try {
const result = execSync(
`find "${cacheDir}" -name "headless_shell" -type f 2>/dev/null | head -1`,
{ encoding: 'utf-8' }
).trim();
if (result) return result;
} catch {}
try {
const result = execSync(
`find "${cacheDir}" -name "chromium" -type f -not -path "*/node_modules/*" 2>/dev/null | head -1`,
{ encoding: 'utf-8' }
).trim();
if (result) return result;
} catch {}
// Fall back to system Chrome
const systemChrome = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
return systemChrome;
}
export function setupBrowser() {
beforeAll(async () => {
const executablePath = findChromium();
browser = await chromium.launch({
executablePath,
headless: true,
});
});
beforeEach(async () => {
context = await browser.newContext({
viewport: e2eConfig.viewport,
colorScheme: e2eConfig.colorScheme,
baseURL: e2eConfig.baseURL,
});
page = await context.newPage();
});
afterEach(async () => {
await context?.close();
});
afterAll(async () => {
await browser?.close();
});
return {
getPage: () => page,
getContext: () => context,
getBrowser: () => browser,
};
}