Writing tests

Updated May 7, 2026

Mark a code block in any .md file as a runnable test by adding test to its fence info string:

```ts test
expect(1 + 1).toBe(2)
```

Untagged ts blocks render normally and are not run, so you can freely mix illustrative snippets and runnable assertions in the same article.

Test names

The test name comes from the nearest preceding heading. Two blocks under the same heading are auto-suffixed #1, #2, and so on. A block with no preceding heading uses the file's basename. To override naming explicitly, see Per-block options.

Auto-injected helpers

describe, it, and expect are injected at the top of the generated test module — you don't need to import them. Doctest bodies stay clean:

```ts test
const items = [1, 2, 3]
expect(items.length).toBe(3)
```

Imports

Any import statements inside a runnable block are hoisted to the module top and shared across every test in the same .md file. Multi-line imports work because the parser uses a real TypeScript AST (ts-morph), not a regex.

```ts test
import { sum } from "./sum.ts"

expect(sum(1, 2)).toBe(3)
```

Supported languages

Only ts and tsx fences are picked up. js/jsx blocks render but are not run — keep tests typed.

Created with and Livemark