aidokitwiki

Testing Guidelines

Purpose #

How to write and structure tests in this repo. Companion to concepts/testing-tiers.md and how-to-guides/how-to-run-tests-and-byte-compare.md.

Tiers (recap) #

Tier What Where
Unit Pure logic packages/<pkg>/src/foo.test.ts (co-located)
Integration Real aidokit <cmd> in temp dirs packages/<pkg>/test/integration/
E2E Real Claude Code install e2e/ (gated)
Conformance Harness against the package's exported interface packages/<pkg>/test/conformance.test.ts
Byte-compare Dogfood .claude/ reference packages/cli/test/integration/init-emit.test.ts (+ separate compare step)

Runner: Vitest. (ADR-0001)

Unit-test rules #

Integration-test rules #

Pattern (from packages/cli/test/integration/init-emit.test.ts):

import { test, expect } from 'vitest';
import { computeFilePlan, writeFilesStaged } from '../../src/init/...';

test('init emits the v4-shaped tree', async () => {
  const ctx = await makeFakeProjectContext({ adapter: 'claude-code', stack: ['node-ts'] });
  const plan = await computeFilePlan(ctx);
  const tmp = await mkdtemp();
  await writeFilesStaged(plan, tmp);

  expect(await glob(`${tmp}/.claude/agents/*.md`)).toHaveLength(7);
  expect(await glob(`${tmp}/.claude/commands/*.md`)).toHaveLength(3);
  expect(await glob(`${tmp}/.claude/scripts/*.mjs`)).toHaveLength(19);
  // ...
});

Conformance tests #

Every adapter and stack-pack package ships test/conformance.test.ts:

import { test, expect } from 'vitest';
import { runAdapterConformance } from '@aidokit/core';
import { adapter } from '../src/index.js';

test(`${adapter.manifest.name} conforms to declared level`, async () => {
  const report = await runAdapterConformance(adapter, adapter.manifest.conformance);
  if (report.overall !== 'pass') {
    console.error(JSON.stringify(report.results.filter(r => r.status === 'fail'), null, 2));
  }
  expect(report.overall).toBe('pass');
});

Same pattern with runStackPackConformance for packs. The harness is in @aidokit/core; check ids in reference/conformance-reference.md.

For source-level capability cross-check (AD-STD-CAP-01), pass packagePath:

await runAdapterConformance(adapter, 'standard', { packagePath: path.join(__dirname, '..') });

Dogfood byte-compare #

Live test in CI mirrors the local check from how-to-guides/how-to-run-tests-and-byte-compare.md:

diff -r aidokit/.claude  /tmp/dog/.claude

If you touched @aidokit/adapter-claude-code or @aidokit/base-skills, you must keep both sides in sync.

Determinism #

Every test depends on deterministic output. Sources of non-determinism to avoid:

The harness includes adapter.determinism.repeated-invocation-stable and stack-pack.determinism.repeated-invocation-stable. They catch most leaks.

Coverage #

Targets (CLAUDE.md §7.4):

Run pnpm --filter @aidokit/<pkg> test --coverage. Vitest produces coverage/. Lowering a floor needs an ADR.

Fixture conventions #

Common pitfalls #