Agent skill

testing

Test file conventions for setup functions, factory patterns, test organization, type testing, and naming. Use when the user says "write tests", "add a test", "fix this test", or when writing or modifying *.test.ts files, creating test setup functions, or reviewing test structure.

Stars 4,333
Forks 311

Install this agent skill to your Project

npx add-skill https://github.com/EpicenterHQ/epicenter/tree/main/.agents/skills/testing

Metadata

Additional technical details for this skill

author
epicenter
version
2.0

SKILL.md

Test File Conventions

When to Apply This Skill

Use this pattern when you need to:

  • Write or refactor *.test.ts files in this codebase.
  • Structure tests with setup() functions instead of mutable beforeEach setup.
  • Split large test files into focused behavior/type/scenario files.
  • Enforce behavior-based test naming and clear failure intent.
  • Add or review negative type tests using @ts-expect-error.

References

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

  • If working with negative type tests (@ts-expect-error, bun:test type strategy, no as any), read references/type-testing.md
  • If working with test setup architecture (setup() patterns, composable setup, beforeEach avoidance, shared schemas), read references/setup-pattern.md
  • If working with test organization structure (flat tests, describe() boundaries, helper-over-nesting), read references/test-structure.md

External reading:

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

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

typescript
/**
 * [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

typescript
/**
 * 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)

typescript
// Tests for create-tables

Section Headers

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

typescript
// ============================================================================
// 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:

Pattern Use Case
{module}.test.ts Core CRUD behavior, happy paths, edge cases
{module}.types.test.ts Type inference verification, negative type tests
{module}.{scenario}.test.ts Specific 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

typescript
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

typescript
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

Expand your agent's capabilities with these related and highly-rated skills.

EpicenterHQ/epicenter

svelte

Svelte 5 patterns including runes ($state, $derived, $props), TanStack Query, SvelteMap reactive state, shadcn-svelte components, and component composition. Use when the user mentions .svelte files, Svelte components, or when using TanStack Query, fromTable/fromKv, or shadcn-svelte UI.

4,333 311
Explore
EpicenterHQ/epicenter

autumn

Integrate Autumn billing—define features/plans in autumn.config.ts, use autumn-js SDK for credit checks/tracking, manage the atmn CLI for push/pull. Use when working on billing, pricing, credits, plan gating, or metered usage.

4,333 311
Explore
EpicenterHQ/epicenter

handoff-prompt

Draft a self-contained implementation prompt that an agent can execute with zero prior context. Use when the user says "draft a prompt", "write a handoff", "make a prompt I can copy-paste", "create a delegation brief", or wants to hand off a task to another agent, tool, or conversation.

4,333 311
Explore
EpicenterHQ/epicenter

typebox

TypeBox and TypeMap patterns for runtime schema validation and JSON Schema generation. Use when the user mentions TypeBox, TypeMap, Standard Schema, or when working with runtime type validation, JSON Schema, or schema-based validation.

4,333 311
Explore
EpicenterHQ/epicenter

factory-function-composition

Apply factory function patterns to compose clients and services with proper separation of concerns. Use when creating functions that depend on external clients, wrapping resources with domain-specific methods, or refactoring code that mixes client/service/method options together.

4,333 311
Explore
EpicenterHQ/epicenter

progress-summary

This skill should be used when the user asks questions like "can you summarize", "what happened", "what did we do", "what's the situation", "where are we at", "explain what's going on", "give me an overview", "what's been done", "tell me about this", "walk me through what happened", or any question asking to understand the current state of work or changes. Provides conversational, PR-style summaries with visual diagrams.

4,333 311
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results