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!