Examples
Next.js waitlist
A waitlist on Next.js: the form saves an email to Postgres and sends a welcome email through Resend.
A waitlist on Next.js: the form saves an email to Postgres and sends a welcome email through Resend. See it on GitHub.
What it shows
- An invariant that reads both sides: exactly one row in Postgres and exactly one welcome email in the Resend emulator
danwo matrixfaulting Resend (429, 500, a lost answer), the app's own SQL through the data proxy, and a double submit- A Postgres snapshot per worker, restored before every test and trial, with no app restart
Stack
Next.js App RouterPostgresTailwind CSSEmulates: Resend. Runs on: A Next.js app in Chromium, with Postgres in Docker.
Run it
Copy examples/with-next anywhere, then from its folder:
npm install
npx @danwo/cli testIts scripts:
npm run dev # next dev
npm run build # next build
npm run start # next start
npm run test:e2e # danwo test
npm run matrix # danwo matrix tests/deterministic.danwo.ts --grep "joins the waitlist"
npm run serve # danwo serveIts README says what else it needs and what the last full matrix found.
Until the danwo version it pins is on npm, install it from a local build instead: from the repository's root, bun run release <version> --pack, then node examples/link.ts with-next, which installs a copy and prints where it is.
Your app's data in tests explains what this example leans on.
The test
import { joinedOnce, test } from "./waitlist.ts"
const EMAIL = "ada@lumen.example"
test("shows the waitlist form", async ({ app, screen, expect }) => {
await app.open("/")
await expect(screen.getByRole("heading", { name: "Join the waitlist" })).toBeVisible()
await expect(screen.getByLabel("Work email")).toBeVisible()
})
test("asks for a valid email", async ({ app, screen, expect }) => {
await app.open("/")
await screen.getByLabel("Work email").fill("ada")
await screen.getByRole("button", { name: "Join the waitlist" }).click()
/* Next.js renders its own empty role=alert (the route announcer), so pick ours by its text. */
await expect(
screen.getByRole("alert").filter({ hasText: "Enter a valid email address." }),
).toBeVisible()
})
test("joins the waitlist", async ({ app, screen, expect }) => {
await app.open("/")
await screen.getByLabel("Work email").fill(EMAIL)
/* Joining saves the row and calls Resend; readiness waits for both before the next line. */
await screen.getByRole("button", { name: "Join the waitlist" }).click()
await expect(screen.getByRole("status")).toContainText("You're on the list")
await expect(screen.getByTestId("waitlist-count")).toHaveText("1")
}).invariant((fixtures) => joinedOnce({ ...fixtures, email: EMAIL }))SaaS with integrations
Relay, a team-notes app: workspaces on Clerk organizations, a Stripe trial and billing, Slack and Google Calendar connected by OAuth, live notes over Pusher, and Inngest jobs that send email through Resend.
Shop
A small app that sells credits through Stripe Checkout; danwo tests itself against it.