Overview
Providers
The third-party APIs danwo emulates, how to add one to your config, seed it and read what it saw.
A provider emulator is a stand-in for a service your app calls, such as Stripe, Resend or Clerk. It answers the provider's real hostnames, keeps state between calls, signs its webhooks and returns the errors the provider's SDK knows how to read.
Your app doesn't change. It keeps its own SDK, its own sk_test_ key and its own code. danwo's
egress proxy sits between your app and the internet, and sends each call to the right
emulator.
Add a provider
Name the services your app uses in danwo.config.ts. Each one is a *Service, started behind
one proxy with your app:
import { appEnvironment, defineConfig, resendService, stripeService } from "@danwo/sdk"
export default defineConfig({
testDir: "tests",
environment: () =>
appEnvironment({
app: { command: "npm run dev", url: "http://localhost:3000" },
services: [stripeService(), resendService()],
}),
})appEnvironment starts your app with the proxy's settings in its environment. When your app
calls api.stripe.com, the Stripe emulator answers.
When emulators apply
Emulators answer only calls that go through danwo's proxy: from the browser danwo drives and the apps danwo starts. A staging site or a remote API that danwo didn't start calls the real providers. Where danwo runs shows what each setup can emulate.
Seed it
Most apps expect some data to exist already: a product, a webhook endpoint, a signed-up user.
Give each service a seed. It's applied when the run starts and again before every test:
stripeService({
seed: () => ({
products: [{ name: "Credits" }],
prices: [{ product_name: "Credits", unit_amount: 500, currency: "usd" }],
}),
})Each provider's page shows what its seed takes.
Read what happened
Every service gives your tests a fixture named after it: stripe, resend, clerk and so
on. Pair it with the provider's read helper to check what your app really did:
import { type ResendFixtures, resendInbox, test as base } from "@danwo/sdk"
const test = base.extend<ResendFixtures>()
test("sends a welcome email", async ({ app, screen, expect, resend }) => {
await app.open("/signup")
await screen.getByLabel("Email").fill("ada@example.com")
await screen.getByRole("button", { name: "Sign up" }).click()
const email = await resendInbox(resend).waitFor("ada@example.com")
expect(email.subject).toBe("Welcome to the app")
})base.extend<ResendFixtures>() tells TypeScript which fixtures the test receives.
Faults and fidelity
Two things come with every provider:
| What it is | |
|---|---|
| Faults | The failures the fault matrix tries on that provider's calls: rate limits, 500s, timeouts, a dropped answer after the provider acted, a webhook that arrives twice. |
| Fidelity | A check that the emulator answers like the real API. danwo fidelity compares the two, field by field; see Fidelity. |
Calls to hosts no service answers pass through to the internet unless you set unmatched: "block". See Real stacks to block them.
Every provider
Payments
Stripe
Payments, Checkout, subscriptions, invoices, the billing portal, a Stripe.js stand-in and signed webhooks, on api.stripe.com and checkout.stripe.com.
Paystack
Transactions paid on the hosted page, plans and subscriptions, transfers, refunds and banks, with signed webhooks.
Flutterwave
Payment links paid on the hosted checkout, verification, plans, transfers and virtual accounts, with signed webhooks.
Bachs
Checkout, payments, subscriptions with recovery, payouts and the customer portal, settling on the emulator's clock.
Email and messaging
Resend
Sending, batches, domains, API keys and delivery webhooks, with every accepted email readable from the test.
Twilio
Messages and Verify, the account and its numbers, and trial accounts' refusals, with every text readable like mail.
Slack
The Web API, OAuth installs and signed Events API deliveries for a seeded workspace.
Identity
Google sign-in, Gmail, Calendar and Drive, with mailboxes and files a test can read and change.
Microsoft
Microsoft sign-in and Graph: Outlook mail and calendar, OneDrive and change subscriptions.
GitHub
The REST API, OAuth Apps and GitHub Apps with installations, check runs and signed webhooks.
Auth0
Universal Login, MFA, the authentication API, OIDC discovery and the Management API, on the tenant's own domain.
Clerk
The Backend and Frontend APIs and the Account Portal, with svix-signed webhooks, stable seeded ids and the signing key as a PEM.
Storage
AI
Model APIs
OpenAI, Anthropic, Gemini, Perplexity, Bedrock and the Vercel AI Gateway answered from scripts: the same answers every run, at no cost.
Composio
Toolkits, tools, connected accounts and triggers, with tool runs that can act on the other emulators.
Connectors
Nylas
Hosted auth and grants, mail, calendars, contacts and the scheduler of Nylas v3, with signed webhooks.
Nango
Connect sessions and the Connect UI, refreshing connections, the proxy to other emulators, actions and signed webhooks.
Unipile
Hosted auth links, LinkedIn, WhatsApp and mail accounts, chats, messages and mail, with webhooks.
Realtime
Pusher
The Channels API and the pusher-js socket with private and presence channels, signed webhooks, and Beams.
Novu
Triggers, subscribers and topics, code-first workflows through the app's bridge, and the Inbox with its realtime socket.
Tiptap
Tiptap Cloud collaboration: documents synced over the Hocuspocus protocol, token permissions and the documents REST API.