Introduction
Updated May 7, 2026
Run TypeScript code blocks from your markdown docs as real vitest or jest
tests. Mark a fenced block with test, and it becomes a runnable assertion —
no separate test file, no boilerplate, no drift between docs and code.
Install
pnpm add -D testdocs
# or
npm install --save-dev testdocsWrite a doctest
Add test to any TypeScript fence in any .md file. The block's body becomes
the body of an it() named after the nearest preceding heading. describe,
it, and expect are injected for you.
```ts test
import { sum } from "./sum.ts"
expect(sum(1, 2)).toBe(3)
```Untagged ts blocks render normally and are not run, so you can mix
illustrative snippets and runnable assertions in the same article.
Wire it into your test runner
For vitest (or vite-plus), add the plugin and put .md in test.include:
import testdocs from "testdocs/vite"
import { defineConfig } from "vitest/config"
export default defineConfig({
plugins: [testdocs()],
test: {
include: ["**/*.test.ts", "docs/**/*.md"],
},
})For jest, register the transformer:
export default {
transform: { "\\.md$": "testdocs/jest" },
testMatch: ["**/*.test.ts", "**/docs/**/*.md"],
}Run your usual pnpm test — your .md files now run alongside your *.test.ts
files. See Writing tests for the marker syntax,
Running tests for what to expect at the terminal, and
Configuration for runner-specific notes.
Created with ❤ and Livemark