Test2Doc

website·Indexed 31 days ago

https://www.test2doc.com/

A tool that generates technical documentation based on executable tests, specifically integrating with Playwright. It uses a custom reporter to capture test steps defined via test.step() and can inject arbitrary markdown content into the resulting documentation to ensure docs remain up to date with the codebase.

Tokens
30.1K
Snippets
127
Records
175
Agent score
50%

What's inside Test2Doc

  1. Overview of Narrative-Driven Development (NDD)

    Narrative-Driven Development (NDD) is a testing approach where tests are written like tutorials to describe how to use software. Unlike traditional TDD or BDD, NDD optimizes for the documentation reader. When used with Test2Doc, these tests validate functionality while simultaneously generating comprehensive, up-to-date user guides with screenshots. It follows a red-green-refactor cycle but focuses on user scenarios that translate directly into human-readable documentation.
  2. Overview of Test2Doc for Playwright

    Test2Doc is a project that generates technical documentation automatically based on tests to prevent documentation from falling out of sync with the code. The @test2doc/playwright package is a Playwright reporter that produces markdown files compatible with Docusaurus. It supports capturing screenshots, adding category metadata, and generating audit trails from test behavior.
  3. Overview of RedwoodSDK Database Architecture

    RedwoodSDK utilizes Cloudflare SQLite Durable Objects as its database solution. Each SQLite Durable Object operates as an isolated database instance. For interacting with the database, RedwoodSDK uses Kysely, a type-safe SQL query builder. While Kysely does not provide a full Object Relational Mapper (ORM) abstraction, it allows for full access to SQLite's capabilities and enables RedwoodSDK to infer types and database schemas from migrations.
  4. Implement a side drawer for adding contacts using shadcn/ui

    Use the shadcn/ui Sheet component to create a slide-out panel for the contact form. The SheetTrigger acts as the button to open the panel, and SheetContent holds the form and header information. To maintain a clean architecture, the actual form logic should be encapsulated in a separate ContactForm component.
    import { 
      Sheet, 
      SheetContent, 
      SheetDescription, 
      SheetHeader, 
      SheetTitle, 
      SheetTrigger 
    } from "./ui/sheet"
    import { Icon } from "./Icon"
    import { ContactForm } from "./ContactForm"
    
    // Inside ApplicationForm component
    <div className="box">
      <h3>Contacts</h3>
      <p className="input-description">Invite your team members to collaborate.</p>
      
      <Sheet>
        <SheetTrigger className="flex items-center gap-2 font-poppins text-sm font-bold bg-secondary py-3 px-6 rounded-md cursor-pointer">
          <Icon id="plus" size={16} />
          Add a Contact
        </SheetTrigger>
        <SheetContent className="pt-[100px] px-12">
          <SheetHeader>
            <SheetTitle>Add a Contact</SheetTitle>
            <SheetDescription>Add a Contact to this application.</SheetDescription>
          </SheetHeader>
          <ContactForm />
        </SheetContent>
      </Sheet>
    </div>
  5. Generate documentation from Playwright tests using @test2doc/playwright

    The @test2doc/playwright reporter allows developers to automatically generate generic markdown documentation based on their Playwright test structures. It transforms test.describe blocks into top-level headings and test blocks into sub-headings. When test.step is used within a test, the step descriptions are extracted as a list of actions under the corresponding test heading.
    import { test, expect } from '@playwright/test';
    
    test.describe('Playwright Dev Example ', () => {
      test('has title', async ({ page }) => {
        await page.goto('https://playwright.dev/');
        await expect(page).toHaveTitle(/Playwright/);
      });
    
      test('get started link', async ({ page }) => {
        await test.step('when on the Playwright homepage', async () => {
          await page.goto('https://playwright.dev/');
        });
    
        await test.step('clicks the get started link', async () => {
          await page.getByRole('link', { name: 'Get started' }).click();
        });
    
        await test.step('navigates to the installation page', async () => {
          await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
        });
      });
    });
  6. Use getByRole for accessible element selection

    To ensure a website remains accessible, prefer using page.getByRole() over data-testid attributes. Selecting elements by their role and accessible name mimics how users (including those using screen readers) interact with the site. If an element cannot be uniquely identified via getByRole, it often indicates an accessibility red flag that should be addressed in the HTML rather than bypassed with a test ID.
    // Selects a button with the accessible name "Remove"
    await page.getByRole("button", { name: "Remove" });
  7. Apply global page padding via InteriorLayout

    To ensure consistent spacing across different pages (like Dashboard and New Applications) without duplicating padding in individual page components, apply the padding class px-page-side to the wrapper div in the InteriorLayout component.
    // src/app/layouts/InteriorLayout.tsx
    <div className="px-page-side">{children}</div>
  8. Test breadcrumb navigation with Playwright

    To test breadcrumbs, use a specific selector for the navigation element to distinguish between multiple links with the same text (e.g., 'Dashboard' in the header vs. 'Dashboard' in the breadcrumb). Chain getByRole calls to target the link within the breadcrumb navigation container.
    // tests/util.ts
    export const selectors = {
      navBreadcrumb: ["navigation", { name: "breadcrumb" }],
      linkDashboard: ["link", { name: "Dashboard" }],
      headingApplications: ["heading", { name: "Applications" }],
    };
    
    // tests/loggedin/new-applications.spec.ts
    test("Breadcrumb Navigation", async ({ page }, testInfo) => {
      await page.goto("/applications/new")
    
      const breadcrumbs = page.getByRole(...selectors.navBreadcrumb)
      const backToApplicationsLink = breadcrumbs.getByRole(...selectors.linkDashboard)
    
      await backToApplicationsLink.click()
      await expect(page.getByRole(...selectors.headingApplications)).toBeVisible()
    })
    
  9. Automate Passkey testing in Playwright

    To implement consistent automated testing for Passkeys in Playwright, use the following libraries developed by Test2Doc. These tools allow you to generate passkeys, associate them with users, and handle authentication within Playwright tests.
    # Install passkey generation utility
    npm install @test2doc/playwright-passkey-gen
    
    # Install Playwright passkey integration
    npm install @test2doc/playwright-passkey
  10. Organize documentation categories using withDocCategory

    The withDocCategory helper from @test2doc/playwright/DocMeta creates organized folder structures and __category__.json metadata files in Docusaurus. This allows you to group related documentation pages into a specific category route with a custom label and position.
    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", () => {
              // test logic
            })
          })
      })
  11. Integrate Test2Doc with an existing Docusaurus site

    Test2Doc is fully compatible with Docusaurus as it generates standard Markdown files and _category_.json files. To integrate with an existing site, configure the outputDir in your config file to point to your existing Docusaurus docs folder.
  12. Implement the New Application route and page

    Create a placeholder page component for the New Application experience and register it in the application router. To maintain consistency and reduce duplication, encapsulate the 'New Application' button into a reusable component within the applications list view.
    // src/app/pages/applications/New.tsx
    export const New = () => {
      return (
        <div>
          <h1>Add an Application</h1>
        </div>
      )
    }
    
    // src/app/pages/applications/List.tsx
    const NewApplicationButton = () => (
      <Button asChild>
        <a href={link("/applications/new")}>
          <Icon id="plus" />
          New Application
        </a>
      </Button>
    )
    
    // src/worker.tsx
    import { New } from "./app/pages/applications/New"
    
    prefix("/applications", [
      route("/", [isAuthenticated, List]),
      route("/new", [isAuthenticated, New]),
    ]),