.cursor/skills/test-on-change/SKILL.md
Always create and run tests affected by changes, including Playwright for UI changes. Use when modifying Wodbrains features or UI.
npx skillsauth add jdconley/wodbrains test-on-changeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use Vitest for packages/core changes:
pnpm -C packages/core test
Playwright tests live in apps/web/e2e and use the root config:
pnpm run test:e2e
8788 via E2E_WORKER_PORT5174 via E2E_WEB_PORT8787 / 5173 running.E2E_WORKER_PORT=8790 E2E_WEB_PORT=5176 pnpm run test:e2e/api to VITE_API_ORIGIN, which Playwright sets to the worker port.Sometimes Playwright fails during webServer startup with errors like EADDRINUSE / “port is already in use”. This can also leave the dev servers running even though the test run exited. When that happens:
5174 + 8788, or your E2E_WEB_PORT / E2E_WORKER_PORT overrides).pnpm run test:e2e.On macOS/Linux:
# Find which process is listening on the port
lsof -nP -iTCP:5174 -sTCP:LISTEN
lsof -nP -iTCP:8788 -sTCP:LISTEN
# Then terminate the PID(s) shown (try TERM first, then KILL if needed)
kill <PID>
kill -9 <PID>
The Playwright webServer runs the worker with STUB_PARSE=1, which always returns a fixed “for time” workout definition. UI tests that depend on specific workout shapes must align with this stub output (e.g., rounds-for-time).
When starting a run from the definition page, use the same flow as existing tests:
await page.locator('#startCountdown').click();
await expect(page).toHaveURL(/\/r\/[^?]+/);
await expect(page.locator('#timerValue')).toBeVisible();
await expect(page.locator('#startOverlay')).toBeVisible();
Rules:
start event ~1s out via API, instead of waiting for the 10s overlay.Preferred helper:
apps/web/e2e/helpers/run.ts → fastStartRun(page, { delayMs?: number })Example:
await page.locator('#startCountdown').click();
await expect(page).toHaveURL(/\/r\/[^?]+/);
await expect(page.locator('#startOverlay')).toBeVisible();
// Avoid waiting for the real 10s countdown in most tests:
await fastStartRun(page, { delayMs: 1000 });
await expect(page.locator('#pause')).toBeEnabled();
Maintain a single E2E that clicks #startOverlay and asserts the real countdown window. This test is allowed to be slower and should cover:
If an overlay is purely visual (e.g. rep celebration), it should not block clicks for seconds in tests or UX.
Guideline:
pointer-events: none on visual celebration overlays, even while active, so tests don’t need waitForTimeout(2600).To test share buttons quickly and deterministically, stub navigator.share:
await page.addInitScript(() => {
(navigator as any).share = async (data: any) => {
(window as any).__lastShare = data;
};
});
await page.locator('#startShareBtn').click();
const share = await page.evaluate(() => (window as any).__lastShare);
expect(share.text.startsWith('Workout at the same time with friends')).toBe(true);
pnpm -C packages/core test && pnpm -w exec playwright test --config /Users/jd/src/wodbrains/playwright.config.ts
documentation
UI design guidelines for WOD Brains app - mobile-first, app-like design with consistent patterns. Use when making UI changes.
development
Run Wodbrains worker parse evals and live Gemini tests locally using Wrangler `.dev.vars` keys. Use when you need to run `parse.evals.test.ts` / `parse.gemini.test.ts` against the real model (RUN_LIVE_AI_TESTS=1).
documentation
Regenerate README screenshots and the demo video for WOD Brains.
testing
Generate and update the WOD Brains OG image PNG/JPG using the mascot SVG and a Playwright-rendered layout. Use when changing OG image copy or layout.