docs(storybook): render MDX tables + add i18n & testing-strategy docs/skill
- fix: wire remark-gfm into addon-docs so GFM pipe tables in *.mdx render (previously raw text in cibg-gaps/layers/atomic-design docs) - add src/docs/i18n.mdx (Foundations/Internationalization): the $localize locale seam + how to test languages without coupling to copy - add src/docs/testing.mdx (Foundations/Testing strategy): per-layer spec matrix, house style, Storybook a11y gate, GREEN gate - add .claude/skills/test-strategy skill Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: test-strategy
|
||||
description: Place tests the house way — Vitest specs co-located by layer (pure domain, no TestBed; parse* trust boundaries; thin UI via Storybook a11y). Use whenever adding a spec or deciding what to test.
|
||||
---
|
||||
|
||||
# Test strategy (test where it's pure)
|
||||
|
||||
Push logic down to where it's pure, test it there directly, keep the layers above thin.
|
||||
No `TestBed` for domain. Never assert on user-facing copy.
|
||||
|
||||
## Rules
|
||||
|
||||
- **`domain/` + any pure logic → required spec.** Reducers, combinators, `visibleSteps`,
|
||||
policies, parsers. Import the function and call it — no Angular, no `TestBed`.
|
||||
- **Value-object parser → happy path + normalisation + each rejection.** Assert on the
|
||||
`Result` discriminant (`.ok`) and the parsed value, **not** the error message.
|
||||
- **`infrastructure/` `parse*` (trust boundary) → required spec.** Accept a valid DTO;
|
||||
reject `null`, `{}`, and malformed shapes. Name it `describe('… (trust boundary)')`.
|
||||
- **`application/` stores/commands → spec** the pure reduce + optimistic
|
||||
begin→confirm/rollback + the command `Result`.
|
||||
- **`ui/` → Storybook story, not a component test.** Axe runs on every story; add a `play`
|
||||
only for wiring axe can't see.
|
||||
- **Never assert on `$localize` copy.** It changes per locale/edit — assert on the
|
||||
`Result`, the value object, or the message id.
|
||||
|
||||
## Skeleton
|
||||
|
||||
Co-locate `*.spec.ts` next to the unit, in the same layer folder:
|
||||
|
||||
```
|
||||
<context>/domain/<thing>.spec.ts # pure — no TestBed
|
||||
<context>/domain/value-objects/<vo>.spec.ts # parser: ok + normalise + each reject
|
||||
<context>/infrastructure/<x>.adapter.spec.ts# parse* trust boundary
|
||||
<context>/application/<store|command>.spec.ts
|
||||
```
|
||||
|
||||
Minimal parser spec:
|
||||
|
||||
```ts
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parseThing } from './thing';
|
||||
|
||||
describe('parseThing', () => {
|
||||
it('accepts + normalises', () => {
|
||||
const r = parseThing(' raw ');
|
||||
expect(r.ok).toBe(true);
|
||||
if (r.ok) expect(r.value).toBe('RAW');
|
||||
});
|
||||
it('rejects malformed', () => {
|
||||
expect(parseThing('').ok).toBe(false); // asserts the tag, not the copy
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Worked examples
|
||||
|
||||
- `src/app/registratie/domain/value-objects/postcode.spec.ts` — parser style.
|
||||
- `src/app/registratie/infrastructure/brp.adapter.spec.ts` — trust boundary (`null`/`{}`).
|
||||
- `src/app/registratie/domain/registratie-wizard.machine.spec.ts` — pure reducer.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
npm test # Vitest (ng test — no vitest.config)
|
||||
npm run test-storybook # axe over every story (UI a11y gate)
|
||||
cd backend && dotnet test # backend rule + endpoint + golden tests
|
||||
```
|
||||
Reference in New Issue
Block a user