Show HN: Test JSDoc examples with any test runner, no more outdated doc

3 weeks ago 1

[GitHub Logo]Repository

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.

Read Entire Article