mcpField
T
testing

testing

github.com/epicenterhqTesting & quality4.8k52 installsUpdated 2w ago
Repository

About testing

A testing skill that documents conventions for organizing TypeScript tests, naming assertions, and separating tests from benchmarks. It also provides guidance for type tests, setup patterns, and reviewing or pruning tests.

Key features

  1. 01Result assertion helpers
  2. 02Test and benchmark separation
  3. 03Test file documentation rules
  4. 04Focused test file organization
  5. 05Behavior-based test naming

Use cases

  1. 01Writing tests for wellcrafted Results
  2. 02Separating performance reports from CI tests
  3. 03Splitting tests across distinct behaviors
  4. 04Auditing or pruning existing tests

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/epicenterhq/epicenter --skill testing

After installing, type/testingin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
honest-tests.md
setup-pattern.md
test-deletion-grill.md
test-structure.md
type-testing.md

Details

From the project README

Test File Conventions

References

Load these on demand based on what you're working on:

External reading:

Related Skills: See services-layer for the service patterns being tested. See typescript for type testing conventions.

Result Assertions

When a test asserts a wellcrafted Result, use expectOk and expectErr from wellcrafted/testing instead of hand-rolled error checks.

import { expectErr, expectOk } from 'wellcrafted/testing';

const data = expectOk(await service.doThing());
expect(data.id).toBe('1');

const error = expectErr(await service.doThing({ invalid: true }));
expect(error.name).toBe('InvalidInput');

Avoid local helper clones, expect(error).toBeNull() success checks, and if (error) throw ... unwrapping when the value is a wellcrafted Result.

This rule does not apply to plain response bodies, UI snapshots, or other objects that merely have an error property.

Tests vs. Benchmarks

Two distinct file extensions, two distinct purposes:

  • *.test.ts : asserts behavior with expect(). Runs under bun test (repo default, CI). A test file without at least one expect() call does not belong under this extension.
  • *.bench.ts : measures and reports. Prints tables, timings, or storage sizes. Runs under bun bench only. No assertions required (perf thresholds on shared hardware flake; prefer visual trends).

A single file is one or the other, never both. Benchmarks live under src/__benchmarks__/ within a package; tests are colocated with the module they cover. The bun test default-discovery glob picks up only *.test.ts and friends, so renaming a report from .test.ts → .bench.ts is what excludes it from CI.

File-Level Doc Comments

Every .test.ts file MUST start with a JSDoc block explaining what is being tested and the key behaviors verified. This serves as documentation for the module's contract.

Structure
/**
 * [Module Name] Tests
 *
 * [1-3 sentences explaining what this file tests and why these tests matter.]
 *
 * Key behaviors:
 * - [Behavior 1]
 * - [Behavior 2]
 * - [Behavior 3]
 *
 * See also:
 * - `related-file.test.ts` for [related aspect]
 */
Good Example
/**
 * Cell-Level LWW CRDT Sync Tests
 *
 * Verifies cell-level LWW conflict resolution where each field
 * has its own timestamp. Unlike row-level LWW, concurrent edits to
 * DIFFERENT fields merge independently.
 *
 * Key behaviors:
 * - Concurrent edits to SAME field: latest timestamp wins
 * - Concurrent edits to DIFFERENT fields: BOTH preserved (merge)
 * - Delete removes all cells for a row
 */
Bad Example (Too Minimal)
// Tests for create-tables
Section Headers

For long test files (100+ lines), use comment headers to separate logical sections:

// ============================================================================
// MESSAGE_SYNC Tests
// ============================================================================

Multi-Aspect Test File Splitting

When a module has distinct behavioral aspects, split into focused test files rather than one monolithic file:

PatternUse Case
{module}.test.tsCore CRUD behavior, happy paths, edge cases
{module}.types.test.tsType inference verification, negative type tests
{module}.{scenario}.test.tsSpecific scenarios (CRDT sync, offline, integration)
When to Split
  • File exceeds ~500 lines
  • Tests cover genuinely distinct concerns (CRUD vs sync vs types)
  • Different setup requirements per concern
When NOT to Split
  • Splitting would create files with fewer than 3 tests
  • All tests share the same setup and concern

Test Naming

Test descriptions MUST be behavior assertions, not vague descriptions. The name should tell you what broke when the test fails.

Rules
  1. State what happens, not "should work" or "handles correctly"
  2. Include the condition when testing edge cases
  3. No filler words: "should", "correctly", "properly" add nothing
Good Names
test('upsert stores row and get retrieves it', () => { ... });
test('filter returns only published posts', () => { ... });
test('concurrent edits to different fields: both preserved', () => { ... });
test('delete vs update race: update wins (rightmost entry)', () => { ... });
test('observer fires once per transaction, not per operation', () => { ... });
test('get() throws for undefined tables with helpful message', () => { ... });
Bad Names
test('should work correctly', () => { ... });         // What works? What's correct?
test('should handle batch operations', () => { ... }); // Handle how?
test('basic test', () => { ... });                     // Says nothing
test('should create and retrieve rows correctly', () => { ... }); // Vague "correctly"
Pattern: {action} {outcome} [condition]
"upsert stores row and get retrieves it"
 ^^^^^^ ^^^^^^^^^^   ^^^ ^^^^^^^^^^^^^
 action  outcome    action  outcome

"observer fires once per transaction, not per operation"
 ^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 subject   outcome              condition

"get() returns not_found for non-existent rows"
 ^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
 action     outcome            condition

Comments

Markdown supported