Harness-engineering test-snapshot-patterns

Test Snapshot Patterns

install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/test-snapshot-patterns" ~/.claude/skills/intense-visions-harness-engineering-test-snapshot-patterns-b13af8 && rm -rf "$T"
manifest: agents/skills/codex/test-snapshot-patterns/SKILL.md
source content

Test Snapshot Patterns

Use snapshot testing selectively for stable outputs, knowing when to avoid it

When to Use

  • Testing serialized output (JSON, HTML, error messages) that should not change unexpectedly
  • Verifying component render output for regression detection
  • Capturing complex object shapes that are tedious to assert manually
  • NOT for rapidly changing UI or non-deterministic output

Instructions

  1. Basic snapshot:
it('serializes user data correctly', () => {
  const user = formatUser({ id: '1', name: 'Alice', email: 'alice@test.com' });

  expect(user).toMatchSnapshot();
});

First run creates the snapshot file. Subsequent runs compare against it.

  1. Inline snapshots — store the expected value in the test file:
it('formats the error message', () => {
  const error = formatError({ code: 404, resource: 'User' });

  expect(error).toMatchInlineSnapshot(`"User not found (404)"`);
});

Vitest/Jest auto-fills the inline snapshot on first run.

  1. Snapshot specific properties:
it('creates a user with generated fields', () => {
  const user = createUser({ name: 'Alice' });

  expect(user).toMatchSnapshot({
    id: expect.any(String),
    createdAt: expect.any(Date),
  });
});

This snapshots the structure but uses matchers for non-deterministic fields.

  1. Update snapshots when intentional changes occur:
vitest --update  # or vitest -u

Review the diff before committing updated snapshots.

  1. Prefer inline snapshots for small values — they are easier to review in PRs:
it('generates correct SQL', () => {
  const query = buildQuery({ table: 'users', where: { role: 'admin' } });

  expect(query).toMatchInlineSnapshot(`
    "SELECT * FROM users WHERE role = 'admin'"
  `);
});
  1. Snapshot file-based output for large payloads:
it('generates correct API response', () => {
  const response = buildResponse(testData);
  expect(response).toMatchSnapshot(); // Stored in __snapshots__/
});
  1. Avoid snapshots for:

    • UI components that change frequently (use specific assertions instead)
    • Non-deterministic output (timestamps, random IDs)
    • Very large objects (snapshots become unreadable)
    • Behavior testing (use explicit assertions)
  2. Good snapshot candidates:

    • Serialization formats (JSON output, GraphQL schema)
    • Error messages and validation output
    • Configuration generation
    • CLI output formatting

Details

Snapshot testing captures the serialized output of a value and compares it against a stored reference. It is a regression detection tool — it tells you when output changes, but not whether the change is correct.

Snapshot workflow:

  1. First run: snapshot is created and stored (in
    __snapshots__/
    or inline)
  2. Subsequent runs: output is compared against the stored snapshot
  3. On mismatch: test fails with a diff
  4. To accept the change: run with
    --update
    flag and review the diff

Snapshot hygiene:

  • Review snapshot diffs in PRs as carefully as code changes
  • Delete snapshots for removed tests — stale snapshots cause confusion
  • Keep snapshots small — large snapshots are rubber-stamped in review
  • Use
    toMatchInlineSnapshot
    for values under 5 lines — inline snapshots are easier to review

toMatchSnapshot
vs
toMatchInlineSnapshot
:

  • File-based: stored separately, good for large output, harder to review in PRs
  • Inline: stored in the test file, easy to review, best for small values

Trade-offs:

  • Snapshots catch unintentional changes with minimal effort — but also flag intentional changes, requiring update ceremonies
  • Large snapshot files are easy to create — but become "approve without reading" in code review
  • Inline snapshots are reviewable — but clutter test files with literal output
  • Snapshot tests are fast to write — but can mask poor test design (asserting everything instead of specific behavior)

Source

https://vitest.dev/guide/snapshot.html

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. Verify your implementation against the details and edge cases listed above.

Harness Integration

  • Type: knowledge — this skill is a reference document, not a procedural workflow.
  • No tools or state — consumed as context by other skills and agents.

Success Criteria

  • The patterns described in this document are applied correctly in the implementation.
  • Edge cases and anti-patterns listed in this document are avoided.