# Testing

> Write tests that catch real regressions — choosing what to test, structuring tests, testing behavior over implementation, handling databases and async, and killing flakiness. Use when adding or improving tests, setting up a test for a bug fix or new feature, deciding what to cover, or dealing with flaky/slow tests. Stack: vitest, `pnpm test`.

- **Type:** Skill
- **Install:** `agentstack add skill-ksed8-cc-loopkit-testing`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [ksed8](https://agentstack.voostack.com/s/ksed8)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ksed8](https://github.com/ksed8)
- **Source:** https://github.com/ksed8/cc-loopkit/tree/main/.claude/skills/testing

## Install

```sh
agentstack add skill-ksed8-cc-loopkit-testing
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Testing

A test earns its place by failing when the behavior breaks and passing otherwise. Tests that never fail are noise; tests coupled to implementation break on every refactor. Aim for the first, avoid the second.

## What to test (and what not to)

- Test **behavior and contracts**, not implementation details. Assert on what a function returns / what the user sees, not which private helper it called.
- Prioritize by risk × traffic: money, auth, permissions, data integrity, and anything in `lib/auth/` get thorough coverage. Trivial getters and framework glue don't.
- Cover the boundaries where bugs live: empty, one, many; null/undefined; zero/negative/overflow; the error path, not just the happy path.
- Every bug fix ships with a test that fails before the fix and passes after. That test is the proof the bug is gone and the guard against its return.
- Don't chase a coverage number. 100% line coverage with no assertions on behavior is theater. Coverage shows what's _untested_, not what's _tested well_.

## The test pyramid

- **Unit** (most): pure logic, one module, no I/O — fast, run constantly.
- **Integration** (some): modules together, real DB/API routes — catch the wiring bugs units miss.
- **E2E** (few): full user flows — expensive and slower, reserve for critical paths (signup, checkout, auth).
- Invert it and your suite gets slow and flaky. Push each test to the lowest level that can still catch the bug.

## Structure

- **Arrange–Act–Assert**, visibly separated. One logical behavior per test.
- Name tests by the behavior: `returns 401 when the session is expired`, not `test auth 3`. The name should read as a spec line.
- Assert on specific values, not just "truthy" or "no throw". `expect(res.status).toBe(403)` beats `expect(res).toBeDefined()`.
- Keep tests independent and order-agnostic — no test may depend on another having run. Reset shared state (DB rows, mocks, module state) in `beforeEach`/`afterEach`.
- Prefer real objects over mocks. Mock only at the true boundary (network, clock, randomness, third-party SDKs). Over-mocking tests your mocks, not your code.

## Databases (Postgres)

- Run integration tests against a real Postgres (a disposable/test database), not an in-memory fake — you want the real query planner, constraints, and types.
- Isolate tests: wrap each in a transaction and roll back, or truncate between tests. Never let one test's rows leak into the next.
- Test the migration and the constraint, not just the query: a `NOT NULL`/`UNIQUE`/FK is behavior worth asserting.
- Seed the minimum data the test needs, inline and visible — a giant shared fixture hides what the test actually depends on.

## Async, time, and flakiness

- `await` every promise and assert after it resolves; a floating promise makes a green test that proves nothing.
- Never `sleep(n)` to wait for async — await the actual signal (the resolved value, the state change, a polled condition). Fixed sleeps are the #1 source of flakiness.
- Freeze time and seed randomness. Tests that read the real clock, timezone, or `Math.random()` fail intermittently.
- A flaky test is a bug — in the test or the code. Quarantine it loudly, then fix the race; don't paper over it with retries.

## Working with the harness

- The Stop gate runs `pnpm test` before letting a task finish, so a red suite blocks completion — keep it green as you go, not at the end.
- Run the focused test while iterating (`pnpm test ` / `-t ""`), the full suite before you consider the work done.
- When you change behavior deliberately, update the test in the same change and say why in the diff — don't delete a failing test to get green.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ksed8](https://github.com/ksed8)
- **Source:** [ksed8/cc-loopkit](https://github.com/ksed8/cc-loopkit)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-ksed8-cc-loopkit-testing
- Seller: https://agentstack.voostack.com/s/ksed8
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
