Compare

Stripe test mode, the Stripe CLI, and stripe-mock: what each is for

These are three tools answering three different questions, and each is the right answer to its own: Stripe test mode gives you the highest-fidelity payment, including fraud decisions and 3D Secure challenges; the Stripe CLI delivers real, correctly signed events to localhost on demand; stripe-mock answers API calls against the OpenAPI specification with no state and no events. What none of them gives you is a sequence of deliveries you chose and can repeat exactly, which is the only way to prove that after a duplicate, a reorder, or a decline, the row in your own database is still correct.

Add to Chrome

Three tools, three different questions

Each answers a different question, and the confusion comes from asking one of them a question another answers.

Stripe test mode Stripe CLI stripe-mock Finxture
Choose the event order? Not guaranteed One trigger at a time No events Yes — an authored plan
Repeat one delivery? Only by chance Yes — events resend No events Yes — it is a scenario
Same result on a re-run? New identifiers New identifiers Stateless, nothing varies Same ids, same bodies
Stage fraud or 3DS? Yes — the only one No — it fires events No — validates, forgets Not today
Answer an API read? Yes — the real API Yes — drives the real API Yes — no state No API at all
Account or network? Account, and a browser Account, live connection Neither Neither — localhost

What each one is for

Stripe test mode

The concession first, and it is large: a sandbox is isolated, and its test cards cover far more than they get credit for — declines by reason code, disputes, refunds, 3D Secure. 4100000000000019 produces a charge Radar blocks whatever your rules say; 4000000000003220 forces a 3DS2 challenge. Anyone who says a provider sandbox cannot do fraud or 3DS is out of date; this is the only tool here that can.

Where it stops is control: every outcome is chosen by the value you put in, and that input has to reach Stripe through a browser.

The Stripe CLI

stripe listen forwards events to a local address over a direct connection to Stripe’s API — no Dashboard endpoint, and a signing secret that survives restarts. For getting a genuine, correctly signed event into a handler on port 4242, it is very good.

stripe trigger is not “fake” either: its events come from real API objects created by real HTTP requests, so related events fire too. stripe fixtures scripts a multi-step flow, and stripe events resend gives a genuine duplicate delivery — worth knowing before anyone sells you one.

What it does not give is a sequence you chose.

stripe-mock

A mock HTTP server built on Stripe’s OpenAPI specification: it accepts the same parameters, rejects the ones it does not recognize, and needs no account. Right for a CI job asking whether your client calls the right URL.

Its README is blunt about its own boundary: basic sanity checks, and if you need more, test against testmode instead. It answers API calls rather than delivering events — not a gap someone found but a different job.

What none of them stages: the awkward middle

What falls through is the difficult part of a payment — an antifraud decision, a 3DS challenge, where the question is not whether the event arrived but what your system decided, and whether the row it wrote is right. The CLI fires an event; it does not stage a problem. Test mode stages it, but only through a browser and a real account a test suite cannot drive.

Finxture does not run those scenarios either. If you came for a tool that reproduces a 3DS challenge deterministically, nobody here has one.

Where Finxture fits

Narrower than any of them, and aimed at one thing: run a corner case on purpose against your own localhost, then check what your database holds.

A scenario is an authored, reviewed definition executed through a versioned Stripe adapter and delivered to a loopback address you approved. Take duplicate delivery: the same projected payment_intent.succeeded arrives twice, same raw body, each with its own valid signature — something you can assert on.

What is runnable is the list, and it grows; the value being built here is the list rather than the runner. For the narrower question — a webhook onto localhost without a tunnel — there is a different page.

The problem underneath: two providers, one row in your database

This does not come from Stripe — I have used Stripe once, on my own project. It is the first adapter because it is what everyone reaches for first, not where the pain was.

The pain was dLocal, Braintree, and local banks like Emirates NBD, and it never began inside one provider but at the seam, where two doing the same job met in one scenario: the same real-world event has to leave the same artifacts in your database whichever one handled it. Finxture cannot do that today — one adapter, one provider per run. Motivation, not a feature.

When not to use Finxture

Two cases, stated plainly, because a comparison that ends in a call to action has not told you anything.

Your integration is very small. One payment method, one flow, a handful of orders a day. Opening the provider’s dashboard now and then and looking at what happened with your own eyes is genuinely easier than installing anything, and it will keep being easier. Do that instead.

Your test coverage is already mature. If the corner cases are covered by something that works — fixtures you trust, a test double you built, a suite that has caught real regressions — then a second way of producing the same events is a migration, not an upgrade, and migrations always cost more than they look like they will.

The floor underneath both of those is the honest close. If the product is not for you, the set of cases probably still is, once it is complete. Read the list, check your own tests against it, and if there is a row on it you have never exercised, that is worth knowing whatever you end up using to fix it.

What goes wrong

Choosing a testing tool by the output it happens to produce rather than by the question you need answered. A suite wired to whatever the tool emits quietly narrows itself to what that tool can emit, so the duplicate delivery, the reversed order, and the decline no magic value produces are never exercised at all — and the first time one of them happens, it happens in production against a handler nothing ever tested.

Updated 2026-08-03