# Testing, mocks, and coverage

## Minimal test

```ts title="user_test.ts"
import { assertEquals } from "jsr:@std/assert";

Deno.test("normalizes a user name", () => {
  assertEquals(" Ada ".trim(), "Ada");
});
```

```bash
deno test
deno test --filter "user"
deno test --watch
```

Deno 2.9 has snapshots on the test context with no extra import:

```ts
Deno.test("renders a card", async (t) => {
  await t.assertSnapshot(renderCard({ title: "Deno" }));
});
```

Create or refresh snapshots with `deno test --update-snapshots` and review the `__snapshots__/*.snap` diff. CI runs plain `deno test` and must never update expected output.

Tests are sandboxed too. Grant network or temporary-directory access only to the tests that need it; do not run the whole suite with `-A` because one integration test needs I/O.

## Async cleanup

```ts
Deno.test("fetches health", async () => {
  const controller = new AbortController();
  try {
    // start resource, assert behavior
  } finally {
    controller.abort();
  }
});
```

Deno's sanitizers help detect leaked async operations and resources. Note the defaults: since Deno 2.8, only the exit sanitizer is on by default; the op and resource sanitizers are opt-in. Enable leak detection explicitly on the test or step that needs it instead of relying on defaults:

```ts
Deno.test({
  name: "closes every handle",
  sanitizeOps: true,
  sanitizeResources: true,
  fn: async () => {
    // ...
  },
});
```

Conversely, if a test intentionally keeps background work alive, disable the relevant sanitizer on that test with a note explaining why — never disable them globally.

## Coverage

```bash
deno test --coverage=coverage
deno coverage --lcov --output=coverage.lcov coverage/
```

Coverage does not replace tests for failure paths, denied permissions, timeouts, and cancellation. CI should run at least `fmt --check`, `lint`, `check`, and `test`.

## Large suites

```bash
deno test --changed=origin/main
deno test --shard=1/3
deno test --retry=2
deno test --repeats=3
deno test --trace-leaks
```

`retry` tolerates a known flaky failure and passes after one successful attempt; `repeats` requires every run to pass and helps expose instability. Do not let retries permanently hide a deterministic defect.

Official references: [Testing](https://docs.deno.com/runtime/test/), [Coverage](https://docs.deno.com/runtime/test/coverage/), and [Mocking](https://docs.deno.com/runtime/test/mocking/).
