Skip to main content

Your Tests Are Writing Your Docs (You Just Don't Know It Yet)

· 3 min read
William "dethstrobe" Johnson
Ex-Googler, Founder Null Sweat, Deadly Ninja Cyborg from the Future

Ever wished your documentation could write itself? What if every time you wrote a test, you automatically got beautiful, up-to-date docs with screenshots?

That's exactly what Test2Doc does - a Playwright reporter that automatically generates Docusaurus documentation from your tests - and with the latest release, we've hit MVP with three game-changing features that turn your Playwright tests into living documentation.

Tired of manually organizing docs?​

The withDocMeta helper automatically generates the frontmatter that controls how your pages appear in Docusaurus sidebars.

import { withDocMeta } from "@test2doc/playwright/DocMeta";

test.describe(withDocMeta("Title of Page", {
title: "Title in Sidebar",
sidebar_position: 1,
}), () => {
test("test block", () => {
...
})
})

This will add the yml metadata to the top of a page to control how it displays in Docusaurus.

---
title: Title in Sidebar
sidebar_position: 1
---

# Title of Page

## test block
...

The withDocCategory helper creates organized folder structures and category metadata automatically.

import { withDocCategory, withDocMeta } from "@test2doc/playwright/DocMeta";

...

test.describe(withDocCategory("Title of Category Route", {
label: "Category Sidebar Label",
position: 1,
className: "class-to-add-on-sidebar-label",
}),
() => {
test.describe(withDocMeta("Title of Page in Category", {
title: "Title in Sidebar under Category",
sidebar_position: 1,
}), () => {
test("test block", () => {
...
})
})
})

This will add a new route based off of the description and add a _category.json to that route.

docs/
└── title-of-category-route/
├── __category__.json
└── title-of-page-in-category.md
{
"label": "Category Sidebar Label",
"position": 1,
"className": "class-to-add-on-sidebar-label"
}

Screenshots worth a thousand words?​

The screenshot helper captures your UI automatically and embeds it right into your docs - no more manual screenshot management.

import { screenshot } from "@test2doc/playwright/screenshots"
...

test.describe(withDocMeta("describe block"), async () => {
test("test block", async ({ page }, testInfo) => {
...
test.step("step block", async () => {
await page.goto("http://localhost:5173/")
await screenshot(testInfo, page)
})
})
})

If you want to take a screenshot of a specific element, you can pass in a locator.

import { screenshot } from "@test2doc/playwright/screenshots"
...

test.describe("describe block", async () => {
test("test block", async ({ page }, testInfo) => {
test.step("step block", async () => {
const form = page.getByRole("form", {
name: "My form",
})
await screenshot(testInfo, form)
})
})
})

This will generate markdown with the screenshot in it.

# describe block

## test block

step block
![screenshot](./test2doc-1752070842402-1.png)

The magic?​

All of this happens automatically when you run your tests. No separate documentation process, no manually updating screenshots, no forgetting to update docs when code changes.

Next up: I'm taking Test2Doc for a real-world test drive by building the complete RedwoodSDK tutorial using TDD + automated documentation. Stay tuned to see how this plays out in practice!