Introducing generate-jsdoc-example-tests v0.1.0 🎉
Intro – the why, the how and the ugly truth
To me, documentation by example is the best kind of documentation. As the saying goes: one example is worth a thousand words. However, I was tired of my examples getting obsolete.
Elixir has ExUnit’s DocTest ; I wondered if could we have something in that fashion in the JS/TS ecosystem.
Then I figured: why not reconcile the 2 ? Write JSDoc examples, and generate tests from them…
Plus JsDoc `@example` provide in-IDE documentation for free.
So here comes… generate-jsdoc-example-tests 🎉.
Demo
Let’s take a date format function, for instance.
1. Add the JSDoc example in the source code
// src/date-formatter.ts
/**
* @example
* ```ts
* import { formatDateYear } from './date-formatter'
*
* expect(formatDateYear(new Date('2026-01-01')).toBe('2026')
* ```
*/
export function formatDateYear(date: Date): string {…}
2. Generate the test using npx gen-jet
npx gen-jet ./src \
--header 'import { expect, test } from "vitest"' \
--test-file-extension '.example.test' # do not provide the `.ts` or `.js`
# --watch enables watch mode
3. The generated test:
// src/date-formatter.example.test.ts
// DO NOT EDIT …
import { expect, test } from 'vitest' // the provided header
import { formatDateYear } from './date-formatter'
test('Example 1', () => {
expect(formatDateYear(new Date('2026-01-01'))).toBe('2026')
})
Contributions are more than welcome! If anyone is interested, please do get in touch 😊 (I rarely bite).
What can you document with that ?
Any developer-oriented documentation, really:
- Libraries, internal or external – in conjunction with TSDoc or TypeDoc for instance.
- APIs of your product’s domain, for other domains to consume.
For now it supports functions, methods, interfaces/types & constants.
Bonus: if you have a prettier config, it uses it to format the generated test files.
Test-Runner Agnostic
To adapt the generated test files to your test runner, you can override the test function and add imports using options – see usage and the Vitest example.
Why
I’d rather integrate with test runners to benefit from goodies like coverage and reports rather than building my own micro test runner.
How I use it in my projects
I used it to implement yet-another schema library called unhoax – a type-driven one, you can check it out.
I managed to reach >99% of coverage just by using example tests. Bonus: The examples are re-used to
generate the full reference.
Project setup
- NPM script to generate test files
- NPM script to remove generated test files
- git-ignore the generated test files
Sources files: package.json | .gitignore
In the CI
Generate test files after linting, type checking, … and before running the tests.
That way, I could benefit from my test runner’s coverage capabilities and generate the coverage badge.
Sources file: .github/workflows/coverage.yml
Final considerations
I personally enjoyed working that way. The only downside was writing code in comments, losing syntax checking and code completions for instance. I considered this trade-off acceptable.