dánwòdánwò

Real stacks

When you need it

Test an app that is more than one process, a frontend, an API and a worker, with every outside call emulated.

Most apps are more than one process. A frontend calls an API, the API hands slow work to a background worker, and all three talk to Stripe, a database and a job queue. danwo can start the whole stack, put every process behind its proxy, and test it end to end.

When you need it

Use the setup that matches what your app is:

Your appUse
One process with a dev command (npm run dev)appEnvironment, what danwo init writes
A frontend, an API, workersstackEnvironment
Background jobs on InngestinngestService
Its own Postgres or Redisdata proxies

You can mix them: a stack with an Inngest worker and a Postgres database is one config.

How it fits together

Browseryour testwebfrontendapibackendworkerbackground jobsdanwo proxyone per workerStripe, Clerk…Inngest devPostgres, Redisevery app's calls, webhooks, sockets and statements go in the flight record
danwo starts every app, in order, behind one proxy. What they call is emulated, recorded and can be faulted.
  1. danwo starts every app in the order you give, each with its own command and folder.
  2. Each app is pointed at the proxy. Their calls to api.stripe.com or api.clerk.com reach emulators. Your code doesn't change.
  3. Local services stay local. The apps reach each other, the Inngest dev server and your databases on this machine as usual.
  4. Everything is recorded. Every app's calls, webhooks, sockets and log lines go into the test's flight record.

A small stack

Here is a frontend that calls an API, with Stripe emulated and every other outside host blocked:

danwo.config.ts
import { defineConfig, stackEnvironment, stripeService } from "@danwo/sdk"

export default defineConfig({
  testDir: "tests",
  readiness: { mode: "page+backend", settle: true },
  environment: () =>
    stackEnvironment({
      unmatched: "block",
      services: [stripeService()],
      apps: [
        {
          name: "web",
          command: "npm run dev",
          cwd: "apps/web",
          url: "http://localhost:3000",
          dependsOn: ["api"],
          env: ({ api }) => ({ VITE_API_URL: api ?? "" }),
        },
        {
          name: "api",
          command: "npm start",
          cwd: "apps/api",
          url: "http://localhost:4000",
          ready: { path: "/health" },
        },
      ],
    }),
})

danwo starts the API first and waits until /health answers. Then it starts the web app, with the API's address in VITE_API_URL. The browser opens the first app in the list, the web app.

Tests stay the same. A test opens pages and clicks buttons as before; the stack runs underneath.

Next

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