Payment integrations are among the hardest things to test in software. Real money is on the line, edge cases abound, and third-party sandboxes are notoriously unreliable.
In this guide, we'll cover how to comprehensively test payment integrations using Stage.
The Testing Pyramid for Payments
Level 1: Happy Path Test that payments work when everything goes right: - Card is valid - Sufficient funds - No fraud flags - Network is fast
Level 2: Validation Errors Test input validation: - Invalid card numbers - Expired cards - Missing fields - Invalid amounts
Level 3: Processing Failures Test what happens when the payment processor fails: - Card declined - Insufficient funds - Fraud detected - Account frozen
Level 4: Network Failures Test network-level failures: - Timeouts - Connection refused - Partial responses - Rate limiting
Level 5: Edge Cases Test the weird stuff: - Currency conversion failures - Webhook delivery failures - Duplicate charges - Refund edge cases
Setting Up Stage for Payment Testing
1. Configure Your Dependencies
{
"name": "stripe-api",
"slug": "stripe",
"baseUrl": "https://api.stripe.com",
"auth": {
"type": "bearer",
"token": "sk_live_xxx"
}
}
2. Create Test Scenarios
Scenario: Card Declined
{
"name": "card-declined",
"rules": [{
"match": { "path": "/v1/charges", "method": "POST" },
"action": {
"type": "override",
"status": 402,
"body": {
"error": {
"type": "card_error",
"code": "card_declined",
"message": "Your card was declined."
}
}
}
}]
}
Scenario: Timeout
{
"name": "payment-timeout",
"rules": [{
"match": { "path": "/v1/charges", "method": "POST" },
"action": {
"type": "latency",
"ms": 35000
}
}]
}
3. Run Your Tests
describe('Payment Processing', () => {
it('handles card declined gracefully', async () => {
// Activate the scenario
await stage.activateScenario('card-declined');
const result = await processPayment({
amount: 1000,
currency: 'usd',
source: 'tok_visa'
});
expect(result.status).toBe('failed');
expect(result.error.code).toBe('card_declined');
expect(ui.getByText('Payment failed')).toBeVisible();
});
});
Common Patterns
Testing Idempotency Payment systems must handle duplicate requests. Test this by: 1. Send a payment request 2. Stage returns success 3. Send the same request again 4. Verify your system doesn't double-charge
Testing Webhook Failures 1. Process a payment 2. Stage simulates a webhook delivery failure 3. Verify your system retries or handles gracefully
Testing Partial Refunds 1. Create a charge 2. Request a partial refund 3. Stage returns success 4. Verify your system tracks the partial refund correctly
Best Practices
- Never test with real payment credentials: Always use Stage or test mode keys
- Test every error code: Payment processors have dozens of error codes—test them all
- Test timeout handling: What happens if the payment processor is slow?
- Test reconciliation: Does your system match payment records correctly?
- Test webhooks: Don't assume webhooks always arrive
Conclusion
Payment testing doesn't have to be painful. With Stage, you can simulate any payment scenario without touching real money or relying on flaky sandboxes.
Get started with Stage and ship payment features with confidence.