agentleFS
anchildress1anchildress1/awesome-ai/skills/test-writer/SKILL.md

test-writer

Skill67 starsChanged 59 days agoMITView on GitHub

Write, extend, or review tests in any codebase. Use this skill whenever the user asks to write tests, add test coverage, test a new feature, fix failing tests, or audit existing test files — regardless of language, framework, or project. Also trigger for "add tests for", "write tests for", "cover this with tests", "test this file", "update the tests", "improve coverage", or "this needs tests". This skill enforces universal testing rules (no .skip, no lowering thresholds, full-path coverage) and adapts its mock patterns and tooling to whatever stack the repo uses.

28 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use debug-fix, debugger and 8 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • zebbernSkill

    debug-fix

    Find and fix a bug or issue — from any source (GitHub issue, error message, user report, or observed behavior)

    Also in 4 projects that use this

  • JohnJBorenSkill

    debugger

    Systematic debugging workflows, root cause analysis, and troubleshooting patterns

    Also in 3 projects that use this

  • get-proofpilotSkill

    context-budget

    Audits Claude Code context window consumption across agents, skills, MCP servers, and rules. Identifies bloat, redundant components, and produces prioritized token-savings recommendations.

    Also in 3 projects that use this

  • nimbalystSkill

    prd-writer

    Create structured Product Requirements Documents (PRDs) with prioritized requirements. Use when writing product specs, feature requirements, or project briefs.

    Also in 3 projects that use this

  • GoogleSkill

    code-reviewer

    Also in 4 projects that use this

  • GitHubSkill

    refactor

    Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements.

    Also in 4 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

14 rules. 0 are common, 8 are distinctive, and 6 are very specific to this project.

  • 0

    Common

    Most of the 26 edited versions we read keep these.

  • 8

    Distinctive

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read the source under test completely.

    line 20
  2. Very specific:

    Read existing tests for the module.

    line 25
  3. Very specific:

    Read the test config (vitest.config.ts, jest.config.ts, pytest.ini, pyproject.toml).

    line 28
  4. Distinctive:

    Read shared helpers and fixtures.

    line 30
  5. Distinctive:

    Read CLAUDE.md / AGENTS.md for project test conventions.

    line 33
  6. Very specific:

    Self-contained: No dependence on execution order or on state beforeEach does not reset.

    line 64
  7. Very specific:

    Never it('works'), it('test 1'), it('should be correct').

    line 82
  8. Very specific:

    Use the framework's benchmark tooling: Vitest bench, pytest-benchmark, k6.

    line 181
  9. Distinctive:

    Keep deterministic: isolated run, warm up before asserting, no shared load.

    line 182
  10. Distinctive:

    Run against a local server or staging, never production.

    line 198
  11. Distinctive:

    Run the suite with the command from Step 0, then confirm:

    line 223
  12. Very specific:

    No stray .only, xtest, or xit

    line 226
  13. Distinctive:

    No coverage threshold dropped

    line 227
  14. Distinctive:

    Every source branch exercised — open the HTML coverage report when unsure

    line 228

“Common” is measured: kept by at least 6 in 10 of the 26 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Repo convention beats every preference below. Exception: the hard rules always win.

Step 0 — orient

Complete all of these before the first line of test code. Parallelize the reads.

  1. Read the source under test completely. Map every branch, early return, validation, and error path.
  2. Detect the framework (table below).
  3. Find the test command — package.json scripts.test, Makefile, pyproject.toml, or CI config. Required for the final verification step.
  4. Read existing tests for the module. Extract mock patterns, fixture shapes, naming. New tests must match them. None exist → check for tests/ or __tests__/; if neither, create one mirroring the source tree.
  5. Read the test config (vitest.config.ts, jest.config.ts, pytest.ini, pyproject.toml). Note coverage thresholds and exclusions.
  6. Read shared helpers and fixtures. Use what exists before inventing utilities.
  7. Decide which test types apply — unit, integration, e2e, performance, LHCI. Each has a different mock boundary.
  8. Read CLAUDE.md / AGENTS.md for project test conventions.

Stack detection

SignalFramework
vitest.config.ts or vitest in package.jsonVitest
jest.config.* or jest in package.jsonJest
bunfig.toml, or bun test in scripts.testbun:test
pytest.ini, pyproject.toml [tool.pytest]pytest
.mocharc.*Mocha
cypress.config.*Cypress (e2e)
playwright.config.*Playwright (e2e)

Placement and naming follow the repo, always:

  • Co-located (src/foo.ts → src/foo.test.ts) or separate tree (tests/foo_test.py) — whichever already exists.
  • Bootstrapping from nothing: co-locate unit tests, put integration/e2e in tests/.
  • TS/JS <module>.test.ts or .spec.ts · Python test_<module>.py. Never mix styles inside one project.

Hard rules

  • No .skip. Diagnose the real cause — source, mock, or test logic — and fix it.
  • Never lower a coverage threshold. The config value is a floor. Coverage dropped → write more tests.
  • No copy-pasted bodies. Shared setup → beforeEach. Tests differing only in input/output → parametric (it.each, @pytest.mark.parametrize).
  • Assert result shape AND mock interactions. Return value alone misses wrong downstream calls; mock calls alone miss what the caller produced.
  • Self-contained. No dependence on execution order or on state beforeEach does not reset. Passes alone, fails in-suite → broken test.
  • Fix the source, not the assertion. A bug found while testing gets fixed first, then tested against correct behavior.

Naming

verb + subject + condition — a reader who has never seen the source knows what is verified and when, without opening the body.

it('returns 404 when the card does not exist')
it('normalizes whitespace-only url to undefined')
it('rejects signal above 5')
it('excludes soft-deleted cards from results by default')
it('handles partial batch failure without failing the whole run')

Never it('works'), it('test 1'), it('should be correct').

describe blocks encode shared context: describe('when the database returns an error').

Structure — Arrange / Act / Assert

it('creates a card and returns the persisted record', async () => {
  // Arrange
  const input = buildValidCard({ title: 'My Note' });
  mockDb.upsert.mockResolvedValue({ data: input, error: null });

  // Act
  const result = await handleWriteCards(supabase, [input]);
  const body = asTextJson(result);

  // Assert
  expect(body.written).toBe(1);
  expect(body.results[0].title).toBe('My Note');
  expect(mockDb.upsert).toHaveBeenCalledWith(
    expect.objectContaining({ title: 'My Note' }),
    expect.anything(),
  );
});

Required coverage

Work every row for each function, handler, or route. Never skip a row as obvious.

PathCover
HappyValid input, all required fields, dependencies succeed. Assert full response shape and every mock call argument.
Negative / validationEach required field missing individually · wrong types · out-of-range · whitespace-only strings · empty and oversized collections · bad formats (UUID, URL, email, datetime).
Dependency failureDB/API returns an error object · HTTP call fails · file absent. Assert the caller surfaces it — correct status, message, isError.
Unexpected throwDependency throws synchronously or rejects. Assert the outer handler catches and returns a safe structured response.
Edgenull/undefined optionals · empty arrays · boundaries (min, max, exactly at, one over) · whitespace normalization · timezone offsets · circular refs where serialized · state transitions (soft-delete on/off, flag on/off).

Any input that takes a different code path gets a test.

Schemas and validators — per field: valid full input · each required field missing (error names the field) · wrong type · preprocessing (trim, '' → undefined, tz → UTC ISO) · optional absent gives the default and present is accepted · boundaries · format validation both directions · unknown-key rejection when the schema is strict.

Parametric

// Vitest / Jest
it.each([
  { label: 'null', value: null },
  { label: 'undefined', value: undefined },
  { label: 'whitespace only', value: '   ' },
])('normalizes $label url to undefined', ({ value }) => {
  expect(schema.parse({ ...valid, url: value }).url).toBeUndefined();
});
# pytest
@pytest.mark.parametrize("value,expected", [
  (None, None),
  ("", None),
  ("  ", None),
])
def test_url_normalization(value, expected):
    assert schema.parse({"url": value}).url == expected

Mock boundaries

Mock at the process boundary, never inside the logic.

TargetRule
Network clients (HTTP, DB SDKs, queues)Mock — no real I/O, controlled response shapes
Date.now(), Math.random(), clocksMock — determinism
External service SDKsMock — speed and isolation
Internal helpers in the same moduleDo not — test through the real call chain
Logging side effects under assertionSpy, never replace; restore after
  • Unit — mock the dependency, isolate the logic.
  • Integration — real middleware, validation, routing, business logic. Mock only the true process boundary. Drive through the HTTP layer, not by calling handlers directly.
  • E2E — no mocks. Real services, real data, real cleanup.

Match the repo's existing mock style (vi.mock, factory + _mocks, constructor injection) — consistency beats preference.

Reset in beforeEach: Vitest vi.clearAllMocks() / vi.resetAllMocks() (reset also drops return values and implementations) · Jest equivalents · pytest monkeypatch auto-resets, and unittest.mock uses patch as a context manager or with autospec.

Performance

For any path with a latency or throughput requirement — hot paths, data-heavy queries, network-bound work.

  • Assert against a budget (time, allocation, request count), never just "it ran".
  • Use the framework's benchmark tooling: Vitest bench, pytest-benchmark, k6.
  • Keep deterministic: isolated run, warm up before asserting, no shared load.
bench('processes 1000 cards under 50ms', async () => {
  await processCards(generateCards(1000));
}, { time: 500 });

Lighthouse CI

For user-facing pages. Never wire LHCI into a GitHub Actions workflow — local only.

  • Assert against lighthouserc.js / .json.
  • Cover Performance, Accessibility, Best Practices, SEO.
  • Threshold from current scores — the goal is regression detection, not a day-one perfect score.
  • Run against a local server or staging, never production.
module.exports = {
  ci: {
    assert: {
      assertions: {
        'categories:performance': ['warn', { minScore: 0.8 }],
        'categories:accessibility': ['error', { minScore: 0.9 }],
      },
    },
  },
};

Coverage

Branch coverage over line coverage. Required: branches in core business logic · every error return · every validation rule triggered by at least one test.

Exclude from targets: entry/bootstrap files (index.ts, main.py) · pure type files · generated code · helpers and fixtures.

Exit gate

Run the suite with the command from Step 0, then confirm:

  • Zero failures, zero errors
  • No stray .only, xtest, or xit
  • No coverage threshold dropped
  • Every source branch exercised — open the HTML coverage report when unsure
  • Error paths assert the flag/status and the message content

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.