1---
2name: testing
3description: The meirlabs automated-testing standard. How every project sets up, writes, and runs tests, and how Claude reports results to a non-coder owner in plain language. Use when the user says "set up tests", "add tests", "write a test for this", "run the tests", "run the tests again", "why is CI red?", "is it safe to deploy?", "did I break anything?", or reports a bug (write a failing test first, then fix). Wiring a project is done by the test-wirer agent; the deploy skill hard-gates on green tests.
4---
5
6# Testing
7
8Tests are how the owner, who does not read code, knows the software works. The owner never
9writes or reads a test. Claude ALWAYS writes and maintains them, and reports back in plain
10words: what passed, what broke, and what happens next. Treat the test suite as the owner's
11eyes on the codebase. If the suite is green, the owner can trust the app. That trust only
12holds if Claude keeps the suite honest, so the rules below are not optional.
13
14## The canonical stack (meirlabs testing standard v1)
15
16Every wired project uses exactly this. Do not substitute Jest, Cypress, or ad-hoc scripts.
17
18**Unit and integration** (Vitest, jsdom):
19- `vitest@^3`, `@testing-library/react@^16`, `@testing-library/jest-dom@^6`, `jsdom@^25`,
20 `@vitejs/plugin-react@^5` as devDependencies, plus an explicit `vite@^7` devDependency
21 (plugin-react@4 peer-conflicts with vite 7).
22- `vitest.config.ts`: jsdom environment, `globals: true`, `setupFiles: ['./test/setup.ts']`,
23 `exclude` covering `e2e/**` and `node_modules` (Playwright specs must never run under Vitest).
24- `test/setup.ts`: imports `@testing-library/jest-dom/vitest` and runs Testing Library
25 `cleanup()` in `afterEach`. This is the same setup ui-kit uses, so behavior stays consistent
26 across the whole codebase.
27
28**End to end** (Playwright, real browser):
29- `@playwright/test` as a devDependency, chromium project only.
30- Specs live in `e2e/`, named `e2e/*.spec.ts`.
31- `playwright.config.ts` has a `webServer` block: locally it runs the dev server with
32 `reuseExistingServer: !process.env.CI`; in CI it does a production `build` then `start` so
33 E2E runs against the real build, not dev.
34
35**Conventions:**
36- Unit and integration tests sit next to the code they test: `lib/pricing.ts` gets
37 `lib/pricing.test.ts`; `components/Card.tsx` gets `components/Card.test.tsx`.
38- E2E specs live only in `e2e/`, as `e2e/*.spec.ts`.
39- Every project ships at least three real tests: one `lib/` unit test (pure logic), one
40 component render test (a component mounts and shows what it should), and one E2E smoke spec
41 (home page renders, the key nav works, and there are no console errors).
42
43**Scripts** (in `package.json`):
44```json
45"test": "vitest run",
46"test:watch": "vitest",
47"test:e2e": "playwright test",
48"test:all": "vitest run && playwright test"
49```
50
51## Standing rules for every session in a wired project
52
53These apply to Claude on every task, not just testing tasks:
54
551. **Every new feature ships with tests.** New logic gets unit/integration tests. A new user
56 flow gets an E2E update. A feature is not done until its tests exist and pass.
572. **A reported bug starts with a failing test.** When the owner reports a bug, FIRST write a
58 test that reproduces it and fails, then fix the code until that test passes. This matches the
59 owner's global rule. Never fix a bug without leaving a test that would catch it again.
603. **Never delete or skip a failing test to make the suite green.** A red test is information.
61 Fix the code, or if the test itself is wrong, explain to the owner why and get a yes before
62 changing it. Silently deleting, `.skip`-ing, or commenting out a failing test is forbidden:
63 it hands the owner a green light that lies.
644. **Keep the suite fast.** The unit suite should stay under about 30 seconds. Slow tests get
65 skipped, and skipped tests protect nothing. Push slow things (real network, real DB) into a
66 small number of E2E specs, keep unit tests pure.
67
68## Plain-language reporting
69
70The owner cannot read a stack trace, so do not paste one. After any test run, report like this.
71
72On success:
73> All 34 checks passed (24 logic, 7 component, 3 browser). Safe to deploy.
74
75On failure, name what broke in owner terms and say what you will do:
76> 1 check failed. The article page stopped showing the publish date. I am fixing the date
77> formatting now and will re-run.
78
79Rules for the report:
80- Group counts as logic (Vitest lib tests), component (Vitest render tests), browser (Playwright).
81- Describe failures as user-visible effects ("the login button did nothing"), not by test name
82 or assertion.
83- No raw stack traces, no jargon walls. Show them only if the owner asks "show me the error".
84- Always end with the practical answer the owner cares about: safe to deploy, or not yet.
85
86## How to run
87
88Exact commands (from the project root):
89```bash
90npm run test # unit + integration, one pass (vitest run)
91npm run test:watch # re-run on save while developing
92npm run test:e2e # Playwright browser tests
93npm run test:all # everything, the pre-deploy gate
94```
95Use whatever package manager the project uses (`pnpm run test` if it has a `pnpm-lock.yaml`,
96`npm run test` for `package-lock.json`). Do not introduce a second lockfile.
97
98What the owner types in plain words, and what Claude does:
99- **"run the tests"** → `npm run test:all`, then report in plain language.
100- **"add tests for X"** → write unit/integration tests for X's logic, an E2E update if X is a
101 user flow, run them, report.
102- **"why is CI red?"** → open the failing GitHub Actions run, find the failing step, translate
103 it into what broke and how you will fix it.
104- **"is it safe to deploy?"** → run `test:all`; safe only if everything is green.
105
106## Wiring a project
107
108Do not hand-assemble the config. The **`test-wirer` agent** (`agents/test-wirer.md`) installs the
109stack, writes the config files, adds the scripts and CI, writes real starter tests against the
110project's own code, and iterates until green. It is idempotent: on a project that already has
111Vitest or Playwright (ui-kit, for example, already ships Vitest and 28 tests) it fills gaps and
112upgrades instead of clobbering.
113
114- **New project:** the test-wirer runs as a stage of the `new-project` pipeline, after the
115 scaffolder and alongside the other wiring agents. A project is not "scaffolded" until it has a
116 passing suite and a CI workflow.
117- **Existing project:** run the test-wirer standalone to retrofit the stack.
118
119## CI
120
121Wired projects get `.github/workflows/ci.yml`, running on every push and pull request:
122setup-node with dependency caching → install → typecheck → `vitest run` → build →
123`npx playwright install chromium --with-deps` → `playwright test`.
124
125On GitHub, the green check on a commit or PR means the whole suite passed on a clean machine;
126the red X means something is broken and it is NOT safe to deploy. "Why is CI red?" means: open
127that run, find the red step, and translate it.
128
129Two gotchas the workflow must handle (the test-wirer sets these up, but know them when CI is red):
130- **Hugeicons Pro auth.** Projects using Hugeicons Pro have an authed `.npmrc`, so the CI
131 install fails with a 401 on `@hugeicons-pro` unless a `HUGEICONS_TOKEN` repo secret exists.
132 Set it once per repo: `gh secret set HUGEICONS_TOKEN`. A CI install that dies on
133 `@hugeicons-pro` is almost always the missing secret.
134- **Build-time env vars.** A Next build (and the E2E `webServer` build) reads
135 `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`, and the PostHog vars. If they are
136 absent the build can fail. The workflow provides harmless placeholder values as env vars for
137 the build and E2E steps unless real staging values are configured as secrets. Placeholders are
138 fine: the smoke spec checks that pages render, not that live data loads.
139
140**The deploy skill hard-gates on green tests.** Do not deploy with a red or unrun suite. Run
141`test:all` (or confirm CI is green on the commit) before shipping. A green suite is the owner's
142permission slip.
143
144## Notes
145- Package managers vary across projects (npm vs pnpm). Always use the project's existing
146 lockfile and its matching commands. Never add a competing lockfile.
147- Consistency with ui-kit is deliberate: same Vitest setup, same Testing Library cleanup, so a
148 test written in one meirlabs project reads the same in the next.
149- If a project has genuinely no pure logic to unit test, the test-wirer says so rather than
150 writing fake `expect(true).toBe(true)` tests. A test that cannot fail protects nothing.
151