Unit Test Philosophy (Open Agreements)
Security model
- This skill is guidance only — it does not execute tests or modify code directly.
- All test commands are provided for the user or agent to run in their local environment.
- No network access, credentials, or external services are required.
Use this skill when
- A request asks to add tests, improve coverage, or harden regressions.
- A change touches
src/, integration-tests/, packages/contracts-workspace, or packages/contracts-workspace-mcp.
- You need readable Allure behavior specs.
Core philosophy
- Test highest-risk behavior first.
Focus first on mutating flows, parser/validator boundaries, and policy/safety checks.
- Optimize for regression prevention, not just line coverage.
Prioritize branches where failures could produce wrong legal output or unsafe automation behavior.
- Treat Allure as test style, not test type.
Use normal unit/integration tests with Allure labels, steps, and attachments in the same files.
- Keep assertions behavior-oriented.
Verify user-observable outputs, diagnostics, and mutation outcomes before internals.
- Make failures easy to debug.
Attach structured context for inputs, normalized outputs, and error payloads.
Repo standards
Test structure
- Use Given/When/Then/And wording in Allure step titles.
- Keep scenario steps as top-level test steps; avoid wrapping the full test body in synthetic container steps like
Execute test body.
- Prefer one assertion per step where practical.
- Multiple assertions in one step are acceptable when they validate one cohesive invariant.
- Keep tests deterministic (fixed fixtures, explicit env flags, no timing assumptions).
Allure API
- Prefer repo helpers over direct raw Allure calls:
integration-tests/helpers/allure-test.ts
- Common helpers:
itAllure, testAllure, allureStep, allureJsonAttachment, allurePrettyJsonAttachment, allureWordLikeTextAttachment, allureParameter, allureSeverity
- Do not import from
allure-vitest in tests.
- Keep helper usage consistent across
src/**/*.test.ts and integration-tests/**/*.test.ts.
- For complex fixtures/stateful flows, attach:
- a pretty JSON artifact for request/result payloads
- a human-readable “Word-like” artifact for document/checklist state before and after mutation when relevant
- Rendering note: HTML preview attachments rely on the report post-process sanitizer allowlist patch (
scripts/patch_allure_html_sanitizer.mjs, invoked by npm run report:allure). Do not bypass this pipeline when generating reports for review.
File naming and placement
- Use collocated test files like
src/<module>.test.ts.
- Add Allure style inside these tests; do not split by "allure-only" test types by default.
- Keep one test file focused on one module or capability.
- Migration policy: gradually rename legacy
*.allure.test.ts files to *.test.ts; do not introduce new *.allure.test.ts files.
Coverage expansion workflow
- Read coverage summaries and identify branch-heavy modules in
src/core/** and integration flows.
- Rank by blast radius and mutation risk.
- Add tests in this order:
- Validation and error branches
- Strict vs permissive behavior
- No-partial-mutation / transactional guarantees
- Invariants (deterministic outputs, schema safety, idempotency)
- Run targeted tests first, then full suite and coverage.
Severity recommendation rubric
critical: mutation correctness, legal-output integrity, data-loss risk, security/policy guardrails.
normal: standard behavior and compatibility scenarios.
minor: narrow edge cases with low production impact.
- Apply severity based on failure impact, not module ownership.
Command checklist
npm run test:run
npm run test:coverage
npm run check:allure-labels
Minimal test template (TypeScript)
import { describe, expect } from 'vitest';
import { itAllure as it, allureStep, allureJsonAttachment } from '../../../integration-tests/helpers/allure-test.js';
describe('checklist patch behavior', () => {
it('applies replacement deterministically', async () => {
let result: { ok: boolean };
await allureStep('Given a valid patch payload', async () => {
await allureJsonAttachment('patch-input.json', {
patch_id: 'patch_001',
operations: [{ op: 'replace', path: '/issues/0/status', value: 'CLOSED' }],
});
});
await allureStep('When patch validation runs', async () => {
result = { ok: true };
});
await allureStep('Then validation succeeds', async () => {
expect(result!.ok).toBe(true);
});
});
});
Extended reference
- See
references/allure-test-spec-writing-guide.md for full Allure step-writing guidance.
1---2name: unit-test-philosophy3description: Risk-based unit testing and Allure-readable behavioral spec style for open-agreements. Use when user says "add tests," "test quality," "coverage expansion," "unit test style," or "Allure test spec." Applies when adding/updating tests, expanding coverage, or reviewing test quality across src, integration-tests, and workspace packages.4license: Apache-2.05---67# Unit Test Philosophy (Open Agreements)89## Security model1011- This skill is **guidance only** — it does not execute tests or modify code directly.12- All test commands are provided for the user or agent to run in their local environment.13- No network access, credentials, or external services are required.1415## Use this skill when16- A request asks to add tests, improve coverage, or harden regressions.17- A change touches `src/`, `integration-tests/`, `packages/contracts-workspace`, or `packages/contracts-workspace-mcp`.18- You need readable Allure behavior specs.1920## Core philosophy211. Test highest-risk behavior first.22 Focus first on mutating flows, parser/validator boundaries, and policy/safety checks.232. Optimize for regression prevention, not just line coverage.24 Prioritize branches where failures could produce wrong legal output or unsafe automation behavior.253. Treat Allure as test style, not test type.26 Use normal unit/integration tests with Allure labels, steps, and attachments in the same files.274. Keep assertions behavior-oriented.28 Verify user-observable outputs, diagnostics, and mutation outcomes before internals.296. Make failures easy to debug.30 Attach structured context for inputs, normalized outputs, and error payloads.3132## Repo standards3334### Test structure35- Use Given/When/Then/And wording in Allure step titles.36- Keep scenario steps as top-level test steps; avoid wrapping the full test body in synthetic container steps like `Execute test body`.37- Prefer one assertion per step where practical.38- Multiple assertions in one step are acceptable when they validate one cohesive invariant.39- Keep tests deterministic (fixed fixtures, explicit env flags, no timing assumptions).4041### Allure API42- Prefer repo helpers over direct raw Allure calls:43 - `integration-tests/helpers/allure-test.ts`44 - Common helpers: `itAllure`, `testAllure`, `allureStep`, `allureJsonAttachment`, `allurePrettyJsonAttachment`, `allureWordLikeTextAttachment`, `allureParameter`, `allureSeverity`45- Do not import from `allure-vitest` in tests.46- Keep helper usage consistent across `src/**/*.test.ts` and `integration-tests/**/*.test.ts`.47- For complex fixtures/stateful flows, attach:48 - a pretty JSON artifact for request/result payloads49 - a human-readable “Word-like” artifact for document/checklist state before and after mutation when relevant50- Rendering note: HTML preview attachments rely on the report post-process sanitizer allowlist patch (`scripts/patch_allure_html_sanitizer.mjs`, invoked by `npm run report:allure`). Do not bypass this pipeline when generating reports for review.5152### File naming and placement53- Use collocated test files like `src/<module>.test.ts`.54- Add Allure style inside these tests; do not split by "allure-only" test types by default.55- Keep one test file focused on one module or capability.56- Migration policy: gradually rename legacy `*.allure.test.ts` files to `*.test.ts`; do not introduce new `*.allure.test.ts` files.5758## Coverage expansion workflow591. Read coverage summaries and identify branch-heavy modules in `src/core/**` and integration flows.602. Rank by blast radius and mutation risk.613. Add tests in this order:62 - Validation and error branches63 - Strict vs permissive behavior64 - No-partial-mutation / transactional guarantees65 - Invariants (deterministic outputs, schema safety, idempotency)664. Run targeted tests first, then full suite and coverage.6768## Severity recommendation rubric69- `critical`: mutation correctness, legal-output integrity, data-loss risk, security/policy guardrails.70- `normal`: standard behavior and compatibility scenarios.71- `minor`: narrow edge cases with low production impact.72- Apply severity based on failure impact, not module ownership.7374## Command checklist75```bash76npm run test:run77npm run test:coverage78npm run check:allure-labels79```8081## Minimal test template (TypeScript)82```ts83import { describe, expect } from 'vitest';84import { itAllure as it, allureStep, allureJsonAttachment } from '../../../integration-tests/helpers/allure-test.js';8586describe('checklist patch behavior', () => {87 it('applies replacement deterministically', async () => {88 let result: { ok: boolean };8990 await allureStep('Given a valid patch payload', async () => {91 await allureJsonAttachment('patch-input.json', {92 patch_id: 'patch_001',93 operations: [{ op: 'replace', path: '/issues/0/status', value: 'CLOSED' }],94 });95 });9697 await allureStep('When patch validation runs', async () => {98 result = { ok: true };99 });100101 await allureStep('Then validation succeeds', async () => {102 expect(result!.ok).toBe(true);103 });104 });105});106```107108## Extended reference109- See `references/allure-test-spec-writing-guide.md` for full Allure step-writing guidance.