How to Test Payment Flows End to End Without Moving Real Money
Payment bugs are the most expensive bugs most products ship. They cost revenue directly, they create support tickets, and a double charge can cost you a customer for good. Yet many teams test checkout by hand, once, before launch.
Every major payment provider offers a test mode with test cards and simulated events. Here is how to use them to cover the flows that actually break.
Cover the outcomes, not just the success path
A successful charge is one test. A real payment suite covers at least: success, generic decline, insufficient funds, expired card, incorrect CVC, a 3D Secure challenge that passes, one that fails, and a network error mid-payment. Providers publish specific test card numbers that trigger each outcome, so these are deterministic.
For each outcome, check what the customer sees and what your system records. A decline that shows the right message but leaves an order in "paid" state is still a bug.
Test webhooks, not just the redirect
Most payment systems confirm success asynchronously through webhooks. If you only test the browser redirect, you miss the failures that matter: the webhook that arrives twice, arrives late, arrives before the redirect, or never arrives. Use the provider’s CLI or dashboard to replay events, and assert your system handles duplicates without fulfilling an order twice.
Make retries idempotent
Double charges almost always come from retries: a user double-clicks, a mobile network drops and the app retries, or your server times out and tries again. Send an idempotency key with every payment request and write a test that fires the same request twice and confirms exactly one charge.
Do not forget money moving back
Refunds, partial refunds, cancellations and subscription downgrades are tested far less than purchases and break just as often. Cover proration on plan changes, failed renewal payments and the dunning emails that follow, and confirm that access is removed or kept correctly when a payment fails.
Promotions and currency
Discount codes, free-shipping thresholds, taxes and multi-currency rounding are frequent sources of wrong totals. Assert exact amounts in tests, including the cents. A promo code applied twice is easy to miss in a demo and costly in production.
Run it on every release
Once these tests exist, run them in CI against your provider’s test mode on every pull request that touches checkout, and nightly for everything else. QAShift runs payment journeys like these in test mode on every deploy, with video evidence for every failure, so a broken checkout never reaches your customers.