dánwòdánwò

Get started

Introduction

danwo tests your app through its UI, then checks what happened behind it.

danwo is an open-source testing framework for web and mobile apps. A test clicks through your app like a user. Then danwo checks what that click did behind the screen: the payment, the email, the database row.

tests/buy-credits.danwo.ts
import { type StripeFixtures, test as base } from "@danwo/sdk"

const test = base.extend<StripeFixtures>()

test("buys 500 credits", async ({ app, screen, expect }) => {
  await app.open("/")
  await screen.getByRole("button", { name: "Buy 500 credits" }).click()
  await screen.getByRole("button", { name: "Pay" }).click()

  await expect(screen.getByText("Credits: 500")).toBeVisible()
})

The problem

Most end-to-end tests stop at the screen. The page says "Thank you", so the test passes.

The bugs that cost money live behind that page. Did Stripe charge the card once or twice? Did the receipt email go out? Did the webhook that grants the credits arrive, and what happens if it arrives twice? A screen can't tell you.

How it works

Your test*.danwo.tsBrowserclicks, typesYour appunchangeddanwo proxyrecords callsStripeResendSlack…and morecalls, webhooks anddatabase statementsgo in the flight record
Your app keeps calling the real hostnames. The proxy answers them with emulators and records every call.
  1. Your test drives the app, with locators like getByRole, or with plain-English steps that an AI agent carries out.
  2. Your app calls Stripe, Resend, Slack and the rest as usual. danwo starts it behind an egress proxy: a proxy that every outgoing request goes through. The proxy answers those hostnames with emulators, local copies of each service's API. Your app needs no code changes and no sandbox keys.
  3. Everything is recorded. Every call, webhook and database statement the test caused goes in a flight record, with a video of the screen.
  4. Then danwo breaks it on purpose. The fault matrix replays the test once per thing that could go wrong: a declined card, a 500, a duplicate webhook, a double-clicked button. A rule you write, the invariant, says whether your app coped.

What you get

Fast, cheap rerunsAgent steps are recorded once, then replayed with no AI calls.
Real provider behaviourAbout twenty emulators, checked against the real APIs.
Bugs before productionThe fault matrix finds what only breaks when something fails.
Clear failuresA dashboard with video, every call, and a prompt to paste into your coding agent.
Where you workA GitHub check, a pull request comment, and an MCP server for coding agents.

Get started

On this page

Run it on every pull request

A GitHub check and one comment per pull request, with the flight records attached.

Set up CI