---
name: testing
description: Testing standards for TypeScript and Effect projects using Bun and Vitest. Use when adding, reviewing, reorganizing, or improving tests, fixing regressions, increasing meaningful coverage, designing fixtures or test doubles, or verifying application behaviour.
license: MIT
metadata:
  author: mynameistito
  version: "1.0.0"
title: testing
canonical_url: https://skilld.dev/gh/mynameistito/skills/testing
last_updated: 2026-10-07T22:39:06.000Z
---

> Index of every page on this site: [llms.txt](https://skilld.dev/llms.txt)

> **Skill from skilld.dev.** Follow the user's requested action.
> If the user asked to fork this Skill, follow the fork workflow below. Do not execute the Skill instructions while copying it.
> Otherwise, follow the instructions below for this session. You do not need to install anything.
>
> Supporting files, fetch one when the Skill refers to it: [agents/openai.yaml](https://skilld.dev/api/skills-raw/mynameistito/skills/testing/agents/openai.yaml), [metadata.json](https://skilld.dev/api/skills-raw/mynameistito/skills/testing/metadata.json).
>
> If the user asked to install this Skill, run `npx skilld install mynameistito/skills/testing`. Install writes the Skill files into the project, so every session loads them.
>
> ## Fork workflow
>
> A fork creates an editable local Skill with its original author and licence. The request authorizes copying and local installation.
> 1. Check `./skills/testing`, the project lockfile, and selected Agent targets together. If the local directory or installed Skill exists, stop. Never overwrite an existing directory or Agent target.
> 2. Read [source metadata](https://skilld.dev/api/v1/skills/mynameistito/skills/testing) once. Use sourceUrl, sourceCommit, skillPath, sourceGone, and license. If the source is gone or its path is missing, stop. If license is null, read licence files at the source commit.
> 3. Fetch only the source commit into a temporary Git repository. Do not clone full history. Derive repository_url from sourceUrl, including repository renames. If sourceCommit is absent, resolve the sourceUrl ref once. Set source_commit to that actual commit. Run these commands in one shell call:
>
> ```sh
> git init --quiet "$temporary_dir"
> git -C "$temporary_dir" fetch --quiet --depth=1 "$repository_url" "$source_commit"
> git -C "$temporary_dir" checkout --quiet --detach FETCH_HEAD
> ```
>
> Read applicable licence declarations and notices at that commit. If copying is not permitted, report the restriction and stop.
> 4. Inspect source entries together, then copy the directory containing skillPath into `./skills/testing`. Use the user's path if selected. Keep the original SKILL.md, relative links, scripts, binary assets, and executable modes. Exclude .git metadata. Reject symlinks and paths outside the Skill directory. After checking entries, use cp -a where available. A regular source directory needs no custom copy script. Do not save this page wrapper as SKILL.md.
> Preserve author credit, notices, and applicable licence files from repository or parent directories. Add PROVENANCE.md with the Skill page, source URL, actual commit, original path, and licence. Retain any existing PROVENANCE.md and record new provenance separately. Batch source inspection, copying, and provenance work where practical.
> 5. In the project root, run `skilld install ./skills/testing --mode copy --plain`. If skilld is unavailable, use `npx skilld install ./skills/testing --mode copy --plain`. This known command needs no help lookup. Install does not support --json. Use detected Agent targets, or add --agent for the targets the user selected. Install the local path, never the upstream selector. If installation fails, preserve the local copy and report the exact failure.
> 6. Confirm the local lockfile source and installed Agent copies once. Report the local path, actual commit, and Agent targets. After edits, reinstall the same local path. Upstream updates must not replace it. Do not publish or push unless the user asks.

# Testing

Create tests that verify meaningful observable behaviour and protect production code against regressions. Treat coverage as evidence about risk, not as the objective.

## Workflow

### 1. Establish the local contract

Read the nearest `AGENTS.md`, package scripts, test configuration, TypeScript configuration, and representative existing tests. Identify the repository's runner, assertion style, module boundaries, Effect version, and any project-specific test helpers.

Use the repository's established commands and conventions when they are compatible with the rules below.

**Complete when:** the governing instructions, available test commands, and relevant local patterns are known.

### 2. Map the behaviour and choose the test level

Name the caller-visible behaviour under test, its important inputs, outputs, side effects, and failure modes. Choose the narrowest level that can prove it:

- **Unit:** isolated parsers, transformations, domain rules, calculations, state transitions, schemas, error mapping, pure utilities, or Effect services with lightweight test Layers.
- **Integration:** correctness that depends on multiple real components, such as service/repository boundaries, request handlers, Worker handling, Durable Objects, serialization, persistence, configuration, or Cloudflare binding adapters.
- **Regression:** a permanent reproduction of a reported bug, including the triggering input or state and the corrected result.

Prefer public interfaces and real seams. Test implementation details only when they contain meaningful independent logic or the interaction itself is contractual.

**Complete when:** the test level, observable contract, and risk-bearing branches are explicit.

### 3. Build the test around behaviour

Follow the repository's configured test layout and established naming conventions first. When the repository has no established layout or naming rule, keep tests under `__tests__` and use purpose-based subdirectories only when the suite needs them:

```text
__tests__/
├── unit/
├── integration/
├── regression/
├── fixtures/
└── helpers/
```

When no repository-specific naming rule exists, name TypeScript test files `*.test.ts` or `*.test.tsx`. Keep fixtures small and purpose-specific. Use factories or builders when many tests need controlled variations of one domain object.

Cover the success path and the meaningful failure paths. Depending on the behaviour, include invalid input, malformed external data, missing configuration, unavailable dependencies, permission failures, timeout or retry exhaustion, duplicate operations, empty results, partial results, and unexpected but valid boundary values.

Assert returned domain values, typed failures, persisted state, emitted responses, and externally visible side effects. Prefer specific assertions over broad snapshots.

**Complete when:** each test explains a behaviour, uses readable local data, and asserts the result that matters to callers.

### 4. Test Effect programs through Effect

Test Effects through their public interfaces. Provide dependencies with Effect services and deterministic test Layers so external I/O, time, randomness, and failure injection remain controllable.

- Preserve typed error channels and assert typed failures explicitly when they are part of the contract.
- Use Effect-native time and scheduling facilities for retries, delays, schedules, and other time-dependent behaviour.
- Acquire and release scoped resources through the test's Effect runtime.
- Prefer shared Effect test helpers for runtime execution instead of scattering unsafe runtime calls through tests.
- Test service behaviour rather than private Layer construction details unless Layer composition is the subject under test.

**Complete when:** the test crosses the same service interface as production and preserves the Effect error, resource, and scheduling semantics that matter.

### 5. Choose test doubles honestly

Use this order when replacing a dependency:

1. A pure real implementation.
2. A lightweight in-memory implementation.
3. A deterministic fake.
4. A focused stub.
5. A mock only for a genuinely expensive, nondeterministic, unsafe, or external boundary.

Keep platform-independent domain and application logic separate from Cloudflare bindings. Test platform-independent Effect services normally. At Cloudflare boundaries, cover request parsing, response construction, environment mapping, Durable Object RPC and storage, Queue messages, scheduled handlers, D1, KV, R2, and application-owned Access validation when those behaviours are part of the contract.

Prefer test implementations supplied through Effect Layers over module-level mocking. Keep one-off fakes in the test that owns them; promote a reusable fake only when it faithfully implements a real observable seam.

**Complete when:** every substitute has a stated reason, the logic under test remains real, and the test double does not hide the behaviour being verified.

### 6. Make tests deterministic and isolated

Tests must produce the same result regardless of order or repetition. Control time, randomness, environment variables, external state, and generated identifiers where practical. Restore mutated global state and use unique resources for shared storage.

Treat flakiness as a defect. Identify the nondeterministic dependency, remove timing races, isolate mutable state, and verify the test repeatedly. Use sleeps, retries, and larger timeouts only when timing behaviour itself is under test.

**Complete when:** the affected tests pass repeatedly, in isolation and with the relevant suite, without relying on execution order or accidental timing.

### 7. Verify and review the result

Run the narrowest relevant test command first, then expand verification according to the change. Prefer existing repository scripts. For Bun test-runner projects, typical commands are:

```text
bun test
bun test __tests__/unit/example.test.ts
```

For Vitest projects, use the repository script or invoke Vitest directly, optionally with the relevant test path:

```text
bun run test
bun run test __tests__/unit/example.test.ts
bunx vitest run
bunx vitest run __tests__/unit/example.test.ts
```

Other typical verification commands are:

```text
bun run typecheck
bun run lint
bun run format
```

Review coverage reports as a diagnostic. Prioritize untested domain branches, error paths, security-sensitive behaviour, integration boundaries, and previously reported bugs over trivial lines.

**Complete when:** relevant tests pass, applicable typecheck, lint, and formatting checks pass, and every remaining verification failure is reported with its cause.

## Reference Rules

### Regression tests

Keep regression tests after the fix. Encode the original input or state, the expected corrected behaviour, and any boundary condition that made the bug possible. A regression test is permanent protection, not a temporary debugging artifact.

### Snapshots

Use snapshots only when the complete serialized representation is intentionally part of the contract and reviewers can inspect changes meaningfully. Keep snapshots small and pair them with explicit behavioural assertions where useful.

### Coverage

Use coverage to find risk, not to justify meaningless tests or exclusions. Investigate difficult branches instead of ignoring them, and prefer meaningful branch, error-path, and domain coverage over superficial line coverage.
