Project
Environments
Starting the app and the emulators a worker's tests run against.
A config's environment() starts what a worker's tests run against: the app plus provider emulators behind danwo's egress proxy. Each provider's seed takes the shape listed under its SeedConfig.
appEnvironment
function
appEnvironment( options: AppEnvironmentOptions = {}, ): Promise<WorkerEnvironment>A worker environment for any app: the services behind one proxy, the app started through it (so its calls to Stripe, Resend and the rest reach the emulators with no code change), and the lifecycle danwo matrix needs. The app keeps running between tests and matrix trials; resets put the services back to their seeds.
NangoEnvironment
type
OAuthEnvironment<"nango">What nangoEnvironment() starts: Nango, and any backends, behind one proxy.
nangoEnvironment
function
nangoEnvironment( options: NangoOptions & Unrouted = {}, ): Promise<NangoEnvironment>A worker-scoped Nango emulator behind its own proxy, with its backends on the same proxy.
nangoService
function
nangoService(options: NangoOptions = {}): OAuthServiceNango for startServices: integrations, connect sessions and the hosted Connect UI, connections whose tokens refresh on the emulator's clock, the proxy, actions, records and signed auth webhooks on api.nango.dev and connect.nango.dev; gives tests the nango fixture. Read it and revoke connections with nangoProject(nango). List the backends before it.
NylasEnvironment
type
OAuthEnvironment<"nylas">What nylasEnvironment() starts: the Nylas emulator behind its own proxy.
nylasEnvironment
function
nylasEnvironment(options: NylasOptions & Unrouted = {}): Promise<NylasEnvironment>A worker-scoped Nylas emulator behind its own proxy; combine services with startServices.
nylasService
function
nylasService(options: NylasOptions = {}): OAuthServiceNylas for startServices: hosted auth and grants, mail, calendars and events, contacts, the scheduler and signed webhooks on api.us.nylas.com and api.eu.nylas.com; gives tests the nylas fixture. Read and act on it with nylasApplication(nylas).
ResendEnvironment
type
OAuthEnvironment<"resend">What resendEnvironment() starts: the Resend emulator behind its own proxy.
resendEnvironment
function
resendEnvironment( options: ResendOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<ResendEnvironment>A worker-scoped Resend emulator behind its own proxy; combine services with startServices.
resendService
function
resendService(options: ResendOptions = {}): OAuthServiceResend for startServices: sending email, domains, API keys and signed webhooks on api.resend.com; gives tests the resend fixture and resendMail(resend) as a mail source.
UnipileEnvironment
type
OAuthEnvironment<"unipile">What unipileEnvironment() starts: the Unipile emulator behind its own proxy.
unipileEnvironment
function
unipileEnvironment( options: UnipileOptions & Unrouted = {}, ): Promise<UnipileEnvironment>A worker-scoped Unipile emulator behind its own proxy; combine services with startServices.
unipileService
function
unipileService(options: UnipileOptions = {}): OAuthServiceUnipile for startServices: hosted auth links, connected LinkedIn, WhatsApp and mail accounts, chats, messages, mail and webhooks on every *.unipile.com DSN; gives tests the unipile fixture. Act as the other side with unipileWorkspace(unipile).
stackEnvironment
function
stackEnvironment( options: StackEnvironmentOptions, ): Promise<WorkerEnvironment>A worker environment for a stack of apps: the services behind one proxy, every app started through it in dependsOn order, and the lifecycle danwo matrix needs. Apps keep running between tests; resets put the services back to their seeds.
UnroutedHosts
interface
What happens to calls for hosts no service answers.
| Member | Description |
|---|---|
unmatched?: "passthrough" | "block" | passthrough (default) sends them to the real host; block answers 502. This machine (localhost, 127.0.0.1), where the apps run, always passes, and so does the allow list. |
blocked?: readonly string[] | Hosts answered as blocked even when others pass through, e.g. ANDROID_BACKGROUND_HOSTS. |
allow?: readonly string[] | Hosts that always pass through, even under unmatched: "block". |
telemetry?: "block" | "passthrough" | Analytics and telemetry hosts: blocked by default; passthrough lets them go. |
assets?: "passthrough" | "block" | A page's images, fonts, stylesheets and media from unrouted hosts while unmatched is block: passthrough (default) lets them load, so the page looks right; block refuses them. Scripts and the page's fetch() calls stay blocked either way. |
InngestService
interface
extends ServiceWhat inngestService() returns: the service, and the environment the apps need.
| Member | Description |
|---|---|
env: Readonly<Record<string, string>> | Environment for every app that sends events or serves functions: the dev-mode flag and the routed base URL, e.g. env: { ...inngest.env }. |
inngestService
function
inngestService(options: InngestOptions = {}): Promise<InngestService>Inngest for startServices: events the apps send to inngest.danwo.test reach the dev server through the proxy, settle waits for the runs they triggered, and state lists those runs.
Auth0Environment
type
OAuthEnvironment<"auth0">What auth0Environment() starts: the Auth0 emulator behind its own proxy.
auth0Environment
function
auth0Environment( options: Auth0Options & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<Auth0Environment>A worker-scoped Auth0 emulator behind its own proxy; combine services with startServices.
auth0Service
function
auth0Service(options: Auth0Options = {}): OAuthServiceAuth0 for startServices: Universal Login (the browser logs in, signs up and passes MFA on the tenant's domain through the same proxy), the authentication API's grants, OIDC discovery and keys, logout and the Management API v2; gives tests the auth0 fixture. Read users, logins and verification emails with auth0Tenant(auth0).
AwsEnvironment
interface
What awsEnvironment() starts: AWS hosts sent to MiniStack through its own proxy.
| Member | Description |
|---|---|
endpoint: string | |
proxy: Proxy | |
travel: (ms: number) => Promise<void> | Moves the app's clock and the emulator's time forward by ms; see time.travel. |
reset(): Promise<void> | MiniStack wiped (unless reset: false), proxy log and fault rules cleared. |
fixtures: { readonly aws: AwsFixture readonly proxy: Proxy readonly settle: () => Promise<void> } | Fixtures for tests: aws, proxy, settle. |
close(): Promise<void> |
awsEnvironment
function
awsEnvironment( options: AwsOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<AwsEnvironment>A worker-scoped MiniStack behind its own danwo proxy. To combine it with emulators behind one proxy (e.g. Stripe and S3 emulators, MiniStack for SQS), use awsService with startServices.
AwsOptions
interface
Options of awsService() and awsEnvironment(): where MiniStack runs and what it answers.
| Member | Description |
|---|---|
endpoint?: string | A MiniStack (or LocalStack) the user runs, e.g. http://127.0.0.1:4566. Ignored when docker is set. |
docker?: boolean | { readonly image?: string } | Start a MiniStack container for this service and remove it on close. Each worker then has its own, so resets never touch another worker's state. true uses MINISTACK_IMAGE. |
hosts?: readonly string[] | Hosts sent to MiniStack. Default *.amazonaws.com (every AWS service and region). |
reset?: boolean | Wipe MiniStack's state between danwo matrix runs with POST /_ministack/reset (default true). The reset is global: with a shared endpoint and several workers, turn it off or use docker. |
awsService
function
awsService(options: AwsOptions = {}): Promise<Service & AwsFixture>AWS through MiniStack for startServices: AWS hosts are forwarded to a MiniStack the user runs (endpoint) or one started per worker (docker), with their original Host, so an unmodified app keeps calling sqs.us-east-1.amazonaws.com or <bucket>.s3.amazonaws.com.
EnvironmentContext
interface
What a config's environment() is called with, once per worker.
| Member | Description |
|---|---|
workerIndex: number | 0-based worker slot; use it to keep ports and data apart between workers. |
FlutterwaveEnvironment
type
OAuthEnvironment<"flutterwave">What flutterwaveEnvironment() starts: the Flutterwave emulator behind its own proxy.
flutterwaveEnvironment
function
flutterwaveEnvironment( options: FlutterwaveOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<FlutterwaveEnvironment>A worker-scoped Flutterwave emulator behind its own proxy; combine services with startServices.
flutterwaveService
function
flutterwaveService(options: FlutterwaveOptions = {}): OAuthServiceFlutterwave for startServices: Standard payment links with their hosted checkout (the browser pays on checkout.flutterwave.com through the same proxy), verification, refunds, plans and subscriptions, transfers and virtual accounts, with webhooks and transfer settlements on a manual clock that settle plays to the end; gives tests the flutterwave fixture. Read the books with flutterwaveLedger(flutterwave).
GithubEnvironment
type
OAuthEnvironment<"github">What githubEnvironment() starts: the GitHub emulator behind its own proxy.
githubEnvironment
function
githubEnvironment( options: GithubOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<GithubEnvironment>A worker-scoped GitHub emulator behind its own proxy; combine services with startServices.
GithubOptions
interface
Options of githubService() and githubEnvironment().
| Member | Description |
|---|---|
seed?: Seed<GithubSeedConfig> | Users, orgs, repos, OAuth and GitHub Apps, installations and repository webhooks. |
githubService
function
githubService(options: GithubOptions = {}): OAuthServiceGitHub for startServices: sign-in, GitHub Apps, the REST API and signed webhooks; gives tests the github fixture.
ComposioEnvironment
type
OAuthEnvironment<"composio">What composioEnvironment() starts: Composio, and any backends, behind one proxy.
composioEnvironment
function
composioEnvironment( options: ComposioOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<ComposioEnvironment>A worker-scoped Composio emulator behind its own proxy, with its backends on the same proxy; combine services with startServices instead when the app talks to more.
composioService
function
composioService(options: ComposioOptions = {}): OAuthServiceComposio for startServices: toolkits and tools, tool execution, auth configs, connected accounts with hosted connect links (the browser connects through the same proxy), triggers and the project's signed webhooks; gives tests the composio fixture. Read accounts and tool runs, and fire triggers, with composioProject(composio); answer tools with composioTools(composio). List the backends before it when starting the services together.
NovuEnvironment
type
OAuthEnvironment<"novu">What novuEnvironment() starts: the Novu emulator behind its own proxy.
novuEnvironment
function
novuEnvironment(options: NovuOptions & Unrouted = {}): Promise<NovuEnvironment>A worker-scoped Novu emulator behind its own proxy; combine services with startServices.
novuService
function
novuService(options: NovuOptions = {}): OAuthServiceNovu for startServices: the server API the app's backend triggers workflows and manages subscribers with, code-first workflows run through the app's bridge (seed.bridgeUrl), and the Inbox's API and socket the browser uses; gives tests the novu fixture. settle waits for the workflow runs. Read runs and messages with novuProject(novu).
PusherEnvironment
type
OAuthEnvironment<"pusher">What pusherEnvironment() starts: the Pusher emulator behind its own proxy.
pusherEnvironment
function
pusherEnvironment( options: PusherOptions & Unrouted = {}, ): Promise<PusherEnvironment>A worker-scoped Pusher emulator behind its own proxy; combine services with startServices.
pusherService
function
pusherService(options: PusherOptions = {}): OAuthServicePusher for startServices: the Channels API the app's server triggers events on, the socket pusher-js connects to from the browser, signed webhooks and Beams; gives tests the pusher fixture. Read what was published and who it reached with pusherChannels(pusher).
TiptapEnvironment
type
OAuthEnvironment<"tiptap">What tiptapEnvironment() starts: the Tiptap emulator behind its own proxy.
tiptapEnvironment
function
tiptapEnvironment( options: TiptapOptions & Unrouted = {}, ): Promise<TiptapEnvironment>A worker-scoped Tiptap emulator behind its own proxy; combine services with startServices.
tiptapService
function
tiptapService(options: TiptapOptions = {}): OAuthServiceTiptap Cloud collaboration for startServices: the socket editors sync documents over and the documents REST API on <appId>.collab.tiptap.cloud; gives tests the tiptap fixture. Read a document with tiptapCollab(tiptap).text(name).
GoogleEnvironment
type
OAuthEnvironment<"google">What googleEnvironment() starts: the Google emulator behind its own proxy.
googleEnvironment
function
googleEnvironment( options: GoogleOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<GoogleEnvironment>A worker-scoped Google emulator behind its own proxy; combine services with startServices.
GoogleOptions
interface
Options of googleService() and googleEnvironment().
| Member | Description |
|---|---|
seed?: Seed<GoogleSeedConfig> | OAuth clients, users, and their Gmail, Calendar, Drive and Pub/Sub push data. |
googleService
function
googleService(options: GoogleOptions = {}): OAuthServiceGoogle for startServices: sign-in, Gmail, Calendar and Drive on Google's real hosts; gives tests the google fixture.
LlmEnvironment
type
OAuthEnvironment<"llm">What llmEnvironment() starts: the model API emulator behind its own proxy.
llmEnvironment
function
llmEnvironment( options: LlmOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<LlmEnvironment>A worker-scoped model API emulator behind its own proxy; combine services with startServices.
llmService
function
llmService(options: LlmOptions = {}): OAuthServiceModel APIs for startServices: api.openai.com, api.anthropic.com, ai-gateway.vercel.sh, generativelanguage.googleapis.com, api.perplexity.ai and bedrock-runtime.<region>.amazonaws.com answered from the seed's scripts, streamed when asked; gives tests the llm fixture. Read the calls back with llmCalls(llm) and add scripts with llmScripts(llm).
MicrosoftEnvironment
type
OAuthEnvironment<"microsoft">What microsoftEnvironment() starts: the Microsoft emulator behind its own proxy.
microsoftEnvironment
function
microsoftEnvironment( options: MicrosoftOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<MicrosoftEnvironment>A worker-scoped Microsoft emulator behind its own proxy; combine services with startServices.
MicrosoftOptions
interface
Options of microsoftService() and microsoftEnvironment().
| Member | Description |
|---|---|
seed?: Seed<MicrosoftSeedConfig> | Registrations, users, and their Outlook mail, calendar events and OneDrive files. |
microsoftService
function
microsoftService(options: MicrosoftOptions = {}): OAuthServiceMicrosoft for startServices: sign-in and Graph mail, calendar, OneDrive and subscriptions; gives tests the microsoft fixture.
MINISTACK_IMAGE
value
"ministackorg/ministack:1.5.28"The MiniStack image docker: true runs; MiniStack is MIT-licensed (ministack.org).
PaystackEnvironment
type
OAuthEnvironment<"paystack">What paystackEnvironment() starts: the Paystack emulator behind its own proxy.
paystackEnvironment
function
paystackEnvironment( options: PaystackOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<PaystackEnvironment>A worker-scoped Paystack emulator behind its own proxy; combine services with startServices.
paystackService
function
paystackService(options: PaystackOptions = {}): OAuthServicePaystack for startServices: the API and the hosted payment page the customer's browser opens, with events, transfers, refunds and subscription renewals on a manual clock that settle plays to the end; gives tests the paystack fixture. Read what was paid with paystackLedger(paystack).
S3Environment
interface
What s3Environment() starts: the S3 emulator behind its own proxy.
| Member | Description |
|---|---|
emulator: Emulator | |
proxy: Proxy | |
env(options?: { readonly endpoint?: string }): Record<string, string> | The S3 and Tigris variables for the app; see S3Service.env. |
travel: (ms: number) => Promise<void> | Moves the app's clock and the emulator's time forward by ms; see time.travel. |
reset(): Promise<void> | Emulator back to its seed, proxy log and fault rules cleared. |
snapshot(slot?: string): Promise<void> | Keeps the emulator's state now (right after a reset), for restore. |
restore(slot?: string): Promise<void> | Emulator back to the kept state, faster than a reset; proxy log and fault rules cleared. |
snapshotSlots: boolean | Whether snapshot and restore keep a state per slot. |
fixtures: { readonly s3: Emulator readonly proxy: Proxy readonly settle: () => Promise<void> } | Fixtures for tests: s3 (the emulator), proxy, settle. |
close(): Promise<void> |
s3Environment
function
s3Environment( options: S3Options & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<S3Environment>A worker-scoped S3 emulator behind its own danwo proxy. To combine it with other services behind one proxy, use s3Service with startServices.
S3Options
interface
Options of s3Service() and s3Environment(): buckets to seed and endpoints to answer.
| Member | Description |
|---|---|
seed?: S3SeedConfig | Buckets (and objects) to create on start and after every reset. |
endpoints?: readonly string[] | S3 endpoints the emulator answers, path-style and virtual-hosted (<bucket>.<endpoint>). Default: Tigris (t3.storage.dev, fly.storage.tigris.dev), s3.amazonaws.com and s3.us-east-1.amazonaws.com; add s3.<region>.amazonaws.com for other regions. |
s3Service
function
s3Service(options: S3Options = {}): S3ServiceAn S3 emulator for startServices, for apps on AWS S3 or Tigris; gives tests the s3 fixture.
Seed
type
Config | (() => Config | undefined)Seed data applied on start and after every reset. A function runs each time, so it can use values only known once the app is up, such as its push or notification URL.
Services
interface
Services started together; its fields slot straight into a WorkerEnvironment.
| Member | Description |
|---|---|
proxy: Proxy | |
webhooks: Readonly<Record<string, WebhookDispatcher>> | undefined | Every webhook-delivering service's dispatcher, by service name; undefined when none deliver. |
fixtures: Readonly<Record<string, unknown>> | Every service's fixtures, plus proxy and settle. |
mail?: readonly MailSource[] | Every service's mail sources, so the mail fixture and the agent read what they send. |
state(): Readonly<Record<string, unknown>> | Every service's state(), by service name. |
settle(): Promise<readonly string[]> | Lets every service's background work finish, and says what each waited for and how long. |
travel(ms: number): Promise<void> | Moves the apps' clocks (through the proxy) and every service's time forward by ms. |
reset(): Promise<void> | Every service back to its seed; proxy log, fault rules and the apps' clock offset cleared. |
snapshot(slot?: string): Promise<void> | Keeps every service's state now, for restore, under slot when they keep slots. |
restore(slot?: string): Promise<void> | Every service back to its kept state (or its seed, when it keeps none); log and faults cleared. |
snapshotSlots: boolean | Whether every service that keeps a state keeps one per slot. |
close(): Promise<void> |
SlackEnvironment
type
OAuthEnvironment<"slack">What slackEnvironment() starts: the Slack emulator behind its own proxy.
slackEnvironment
function
slackEnvironment( options: SlackOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<SlackEnvironment>A worker-scoped Slack emulator behind its own proxy; combine services with startServices.
SlackOptions
interface
Options of slackService() and slackEnvironment().
| Member | Description |
|---|---|
seed?: Seed<SlackSeedConfig> | The team, users, channels, apps and installs; app URLs for events, commands and interactivity. |
slackService
function
slackService(options: SlackOptions = {}): OAuthServiceSlack for startServices: OAuth installs, the Web API, incoming webhooks and signed events; gives tests the slack fixture.
startServices
function
startServices( services: readonly Service[], options: UnroutedHosts = {}, ): Promise<Services>Starts one proxy in front of services, e.g. a Stripe emulator, an S3 emulator and MiniStack for the rest of AWS. Other hosts pass through unless unmatched is block.
StripeEnvironment
interface
What stripeEnvironment() starts: the Stripe emulator behind its own proxy, on a manual clock.
| Member | Description |
|---|---|
emulator: Emulator | |
proxy: Proxy | |
clock: ManualClock | |
settle: () => Promise<readonly string[]> | Plays every pending webhook delivery and retry to the end on the manual clock. |
travel: (ms: number) => Promise<void> | Moves the app's clock and the emulator's time forward by ms; see time.travel. |
reset(): Promise<void> | Emulator back to its seed, proxy log and fault rules cleared. |
snapshot(slot?: string): Promise<void> | Keeps the emulator's state now (right after a reset), for restore. |
restore(slot?: string): Promise<void> | Emulator back to the kept state, faster than a reset; proxy log and fault rules cleared. |
snapshotSlots: boolean | Whether snapshot and restore keep a state per slot. |
fixtures: { readonly stripe: Emulator readonly proxy: Proxy readonly settle: () => Promise<void> } | Fixtures for tests: stripe (the emulator), proxy, settle. |
close(): Promise<void> |
stripeEnvironment
function
stripeEnvironment( options: StripeOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<StripeEnvironment>A worker-scoped Stripe emulator behind its own danwo proxy: api.stripe.com and checkout.stripe.com route to it, other hosts pass through. To combine it with other services behind one proxy, use stripeService with startServices.
StripeOptions
interface
Options of stripeService() and stripeEnvironment().
| Member | Description |
|---|---|
seed?: () => StripeSeedConfig | undefined | Runs on start and after every reset; a function, so it can use values only known later (the app's webhook URL). |
stripeService
function
stripeService(options: StripeOptions = {}): StripeServiceA Stripe emulator for startServices: answers api.stripe.com, checkout.stripe.com and js.stripe.com, delivers webhooks on a manual clock, and gives tests the stripe fixture.
TwilioEnvironment
type
OAuthEnvironment<"twilio">What twilioEnvironment() starts: the Twilio emulator behind its own proxy.
twilioEnvironment
function
twilioEnvironment( options: TwilioOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<TwilioEnvironment>A worker-scoped Twilio emulator behind its own proxy; combine services with startServices.
twilioService
function
twilioService(options: TwilioOptions = {}): OAuthServiceTwilio for startServices: messages with status callbacks, texts to the app's numbers and Verify, with message statuses moving on a manual clock that settle plays to the end; gives tests the twilio fixture. Read texts and codes with twilioInbox(twilio), or with twilioSms(twilio) as a session's message source.
BachsEnvironment
type
OAuthEnvironment<"bachs">What bachsEnvironment() starts: the Bachs emulator behind its own proxy.
bachsEnvironment
function
bachsEnvironment( options: BachsOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<BachsEnvironment>A worker-scoped Bachs emulator behind its own proxy; combine services with startServices.
bachsService
function
bachsService(options: BachsOptions = {}): OAuthServiceBachs for startServices: the API on its live and sandbox hosts, the hosted checkout, overlay script, recovery page and customer portal, with payments settling, subscriptions renewing and payouts completing on a manual clock that settle plays to the end; gives tests the bachs fixture. Read what happened with bachsLedger(bachs).
WorkerEnvironment
interface
What a worker runs its tests against, set up once per worker by the config's environment hook: the app's URL, the proxy its browser and app go through, emulators, and any values tests receive as fixtures. Worker-scoped: it lives as long as the worker and is reset between matrix runs.
| Member | Description |
|---|---|
baseUrl?: string | undefined | The app's base URL; overrides the config's baseUrl. |
proxy?: Proxy | Routes the browser (and the app, through its own env) to emulators. Required for danwo matrix. |
webhooks?: RunWebhooks | undefined | Webhook delivery to fault in danwo matrix: one dispatcher, or several keyed by service ({ stripe, resend }). Without it the matrix plans outbound faults only. |
data?: readonly DataProxy[] | undefined | Proxies in front of the app's own database and cache, e.g. startPostgresProxy(…): the app connects through them, and danwo matrix faults the statements and commands its tests send (a lost COMMIT reply, a serialization failure, a cache that answers OOM). |
device?: DeviceTarget | A mobile device the worker's tests run on instead of a browser, e.g. androidDevice() from @danwo/device: each attempt resets and launches the app on it, and screen, app and expect act on the device. |
fixtures?: Readonly<Record<string, unknown>> | Extra fixtures every test in this worker receives, e.g. stripe, inbox, settle. |
mail?: readonly MailSource[] | Where mail the app sends lands, e.g. [resendMail(resend)]: tests read it through the mail fixture, and the agent reads codes and links from it that replays read again. |
settle?(): Promise<void | readonly string[]> | Lets pending background work finish (e.g. webhook deliveries on a manual clock) before a test's invariant or a matrix run's evidence is read. It may say what it waited for, one line each; the flight record shows that on the settle step. |
travel?(ms: number): Promise<void> | Moves time forward by ms for everything behind the app: the apps' clocks (through the proxy) and every emulator's clock, running renewals, retries and expiries as they fall due. The service environments (stripeEnvironment, startServices…) provide it; without it, time.travel moves only the apps' clocks and the browser's. |
reset?(): Promise<void> | Back to a clean state (emulators to their seeds, app state, fault rules), before the tests and matrix trials that need one; see the config's isolation. |
snapshot?(slot?: string): Promise<void> | Keeps the state it is in now for restore() to return to: e.g. emulator stores in memory, a Postgres template database, a copy of a data folder. Called right after a reset(), and again after setup the next tests start from (a file's beforeAll, a saved session's sign-in). Optional, and only used together with restore. With snapshotSlots, slot names which of several kept states this one is (pristine, file, pristine+<session>, ...); without it there is one, and slot is not passed. |
restore?(slot?: string): Promise<void> | Back to what snapshot() kept (in slot, with snapshotSlots), faster than reset(). A worker resets its environment once, snapshots it, and restores it before every later test and trial. Like reset, it also clears the proxy's log, fault rules and the apps' clock offset. The app's own memory is the environment's to reset here (e.g. by calling a test-reset endpoint). Without it, each test resets. |
snapshotSlots?: boolean | Whether snapshot(slot) and restore(slot) keep a separate state per slot. With it, a saved session's sign-in is kept beside the seeded state, so a test that names the session starts signed in and one that does not starts from the seeded state. Without it, there is one kept state: the seeded one, and a session signs in again for every test that names it. |
notes?(): readonly string[] | Facts to print next to a matrix run's verdict. |
stopped?(): readonly string[] | Apps the environment started that have since stopped on their own, e.g. api exited with code 1: a test that fails after one went down says so, rather than leaving only its symptoms (a refused connection, a page that never loads). |
logs?(): Readonly<Record<string, ProcessLog>> | What each app the environment started has written, by app: the flight record keeps the lines written during each run. |
state?(): Readonly<Record<string, unknown>> | State the flight recorder keeps when a run ends, by service (what an invariant reads from). Default: a snapshot of every emulator among fixtures. |
close(): Promise<void> |
postgresSnapshot
function
postgresSnapshot(options: PostgresSnapshotOptions): DatabaseSnapshotA snapshot of a Postgres database for an environment's snapshot() and restore(). Needs a role that may create databases, and Postgres 14 or later.
ts const db = postgresSnapshot({ url: process.env.DATABASE_URL }) return { ..., snapshot: (slot) => db.snapshot(slot), restore: (slot) => db.restore(slot), snapshotSlots: true, close: () => db.close() }
postgresWorkerDatabase
function
postgresWorkerDatabase( url: string, workerIndex: number, options: WorkerDatabaseOptions = {}, ): Promise<string>A database of its own for one worker, <base>_w<workerIndex>, copied fresh from base, so parallel workers never share rows. Resolves to its connection URL. Run migrations and seeds on base first: nobody may be connected to it while the copy is made.
ts async environment({ workerIndex }) { const url = await postgresWorkerDatabase(process.env.DATABASE_URL, workerIndex) const db = postgresSnapshot({ url }) // start the app with DATABASE_URL=url, then snapshot and restore `db` }
redisSnapshot
function
redisSnapshot(options: RedisSnapshotOptions): DatabaseSnapshotA snapshot of one Redis or Valkey database for an environment's snapshot() and restore().
ts const cache = redisSnapshot({ url: "redis://127.0.0.1:6379/0" })
sqliteSnapshot
function
sqliteSnapshot(options: SqliteSnapshotOptions): DatabaseSnapshotA snapshot of a SQLite database file for an environment's snapshot() and restore().
ts const db = sqliteSnapshot({ file: "data/app.db" }) return { ..., snapshot: (slot) => db.snapshot(slot), restore: (slot) => db.restore(slot), snapshotSlots: true, close: () => db.close() }
sqliteWorkerFile
function
sqliteWorkerFile(file: string, workerIndex: number): Promise<string>A copy of a SQLite database for one worker, e.g. of a seeded database every worker starts from: await sqliteWorkerFile("seed.db", workerIndex) resolves to seed.w0.db. Made with SQLite's backup, so rows still in the write-ahead log are copied too.
ClerkEnvironment
type
OAuthEnvironment<"clerk">What clerkEnvironment() starts: the Clerk emulator behind its own proxy.
clerkEnvironment
function
clerkEnvironment( options: ClerkOptions & { readonly unmatched?: "passthrough" | "block" } = {}, ): Promise<ClerkEnvironment>A worker-scoped Clerk emulator behind its own proxy; combine services with startServices.
clerkService
function
clerkService(options: ClerkOptions = {}): OAuthServiceClerk for startServices: a development instance on its real hosts. The app's server reaches the Backend API on api.clerk.com; the browser loads ClerkJS and <SignIn/> from the Frontend API on <slug>.clerk.accounts.dev, or signs in on the Account Portal at <slug>.accounts.dev, through the same proxy. With social, its "Continue with Google" signs in on the Google emulator. Its webhooks go to the seeded endpoints, signed the Svix way. Gives tests the clerk fixture (read keys, sessions and codes with clerkInstance(clerk)), and the codes it emails reach the mail fixture and the agent.
StripeSeedConfig
type
Partial<{ readonly customers: readonly SeedCustomer[] readonly products: readonly SeedProduct[] readonly prices: readonly SeedPrice[] readonly webhookEndpoints: readonly SeedWebhookEndpoint[] readonly paymentMethodConfigurations: readonly SeedPaymentMethodConfiguration[] }>Data to load into a Stripe emulator, on top of its defaults.
ResendSeedConfig
type
Partial<{ /** When set, only these addresses may receive mail, as on a sandboxed account. */ readonly allowlist: readonly string[] /** Sending domains, in `us-east-1` unless a `region` says otherwise. */ readonly domains: readonly { readonly name: string readonly region?: "us-east-1" | "eu-west-1" | "sa-east-1" | "ap-northeast-1" }[] /** * API keys the account has issued. Any `re_` key is accepte…Data to load into a Resend emulator.
S3SeedConfig
type
Partial<{ readonly buckets: readonly { readonly name: string readonly region?: string readonly acl?: Acl readonly objects?: readonly SeedObject[] }[] /** * Access keys whose signatures are checked: a request signed with one of these must carry the * signature its secret makes, and once any is seeded an unknown key is refused * (InvalidAccessKeyId). Without any, every well-formed signature is acce…Buckets (and objects in them) to load into an S3 emulator, and the access keys it knows.
GoogleSeedConfig
type
Partial<{ readonly users: readonly GoogleSeedUser[] readonly oauth_clients: readonly GoogleSeedClient[] /** Mailbox contents by account email. */ readonly gmail: Readonly<Record<string, readonly GmailSeedMessage[]>> /** Where Gmail's Pub/Sub notifications are pushed. */ readonly pubsub: readonly PubSubSeedSubscription[] /** Primary calendar events by account email. */ readonly calendar: Readonly<…Accounts, OAuth clients and API data to load into a Google emulator.
MicrosoftSeedConfig
type
Partial<{ readonly users: readonly MicrosoftSeedUser[] readonly oauth_clients: readonly MicrosoftSeedClient[] readonly mail: readonly MicrosoftSeedMessage[] readonly events: readonly MicrosoftSeedEvent[] readonly files: readonly MicrosoftSeedFile[] }>Accounts, app registrations and their mail, calendars and files, to load into an emulator.
SlackSeedConfig
type
Partial<{ readonly team: { readonly name: string } & Partial<Readonly<Record<"id" | "domain", string>>> readonly users: readonly SlackSeedUser[] readonly channels: readonly SlackSeedChannel[] readonly apps: readonly SlackSeedApp[] readonly installations: readonly SlackSeedInstall[] }>A workspace to load into a Slack emulator.
GithubSeedConfig
type
Maybe<{ users: readonly GithubSeedUser[] orgs: readonly GithubSeedOrg[] repos: readonly GithubSeedRepo[] issues: readonly GithubSeedIssue[] oauthApps: readonly GithubSeedOAuthApp[] apps: readonly GithubSeedApp[] installations: readonly GithubSeedInstallation[] tokens: readonly GithubSeedToken[] hooks: readonly GithubSeedHook[] }>People, organisations, repositories, apps and credentials to load into a GitHub emulator.