This guide explains how to test your Stripe integration thoroughly using test mode.
Test Mode Setup
- Switch to test mode in Stripe Dashboard
- Use test API keys:
const iaptic = new IapticStripe({ stripePublicKey: 'pk_test_...', appName: 'com.example.app', apiKey: 'your_test_api_key' });
Test Cards
Successful Payments
// Always succeeds
const CARD_SUCCESS = '4242 4242 4242 4242';
// Requires authentication (3D Secure)
const CARD_3DS = '4000 0000 0000 3220';
Failed Payments
// Generic decline
const CARD_DECLINE = '4000 0000 0000 0002';
// Insufficient funds
const CARD_INSUFFICIENT = '4000 0000 0000 9995';
// Expired card
const CARD_EXPIRED = '4000 0000 0000 0069';
Test Scenarios
1. Basic Subscription
// 1. Create checkout
const response = await iaptic.createStripeCheckout({
offerId: 'stripe:prod_xyz#price_xyz',
applicationUsername: 'test_user',
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/cancel'
});
// 2. Complete checkout with test card
// Use card: 4242 4242 4242 4242
// 3. Verify subscription
const { purchases } = await iaptic.getPurchases();
console.assert(purchases[0].renewalIntent === 'Renew');
2. Failed Payment
// Use card: 4000 0000 0000 0002
// Verify webhook events
const subscription = await iaptic.getPurchases();
console.assert(subscription.isBillingRetryPeriod === true);
3. Plan Change
// 1. Start with basic plan
// 2. Upgrade to premium
await iaptic.changePlan({
offerId: 'stripe:prod_premium#price_xyz'
});
// 3. Verify proration
const { purchases } = await iaptic.getPurchases();
console.assert(purchases[0].productId.includes('premium'));
4. Cancellation
// 1. Create subscription
// 2. Cancel through portal
await iaptic.redirectToCustomerPortal({
returnUrl: 'https://example.com/account'
});
// 3. Verify status
const { purchases } = await iaptic.getPurchases();
console.assert(purchases[0].renewalIntent === 'Cancel');
Test Webhook Events
Use Stripe CLI to simulate events:
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Listen to webhooks
stripe listen --forward-to localhost:3000/webhook
# Trigger specific events
stripe trigger customer.subscription.created
stripe trigger customer.subscription.updated
stripe trigger invoice.payment_failed
Test Access Keys
// 1. Store access key
const accessKey = response.accessKey;
localStorage.setItem('stripe_access_key', accessKey);
// 2. Test expiration
const { new_access_keys } = await iaptic.getPurchases(
'sub_xyz',
'expired_key_123'
);
// 3. Verify rotation
console.assert(new_access_keys?.['sub_xyz'] !== undefined);
Common Test Cases
Subscription Lifecycle
- [x] Initial subscription
- [x] Successful renewal
- [x] Failed payment
- [x] Payment retry
- [x] Cancellation
- [x] Reactivation
Plan Changes
- [x] Upgrade
- [x] Downgrade
- [x] Proration
- [x] Failed change
User Management
- [x] New user
- [x] Transfer subscription
- [x] Multiple users
- [x] Access revocation
Error Handling
- [x] Invalid cards
- [x] Network errors
- [x] Webhook failures
- [x] Access key rotation
Test Environment
class TestEnvironment {
constructor() {
this.iaptic = new IapticStripe({
stripePublicKey: 'pk_test_...',
appName: 'test.app',
apiKey: 'test_key'
});
}
async createTestSubscription(card = '4242424242424242') {
const response = await this.iaptic.createStripeCheckout({
offerId: this.getTestOfferId(),
applicationUsername: 'test_user',
successUrl: 'http://localhost:3000/success',
cancelUrl: 'http://localhost:3000/cancel'
});
// Simulate checkout completion
await this.simulateCheckout(response.sessionId, card);
return response;
}
async simulateCheckout(sessionId, card) {
// Implement checkout simulation
}
getTestOfferId() {
return 'stripe:prod_test#price_test';
}
async cleanup() {
// Clean up test data
}
}
Best Practices
-
Test Data
- Use clear test identifiers
- Clean up after tests
- Isolate test environments
- Use fresh sessions
-
Automation
- Automate common flows
- Test edge cases
- Verify webhooks
- Monitor test coverage
-
Verification
- Check subscription status
- Verify metadata
- Validate access keys
- Monitor webhooks