Testing Subscription System - Complete Guide
Date: 2025-01-04 Environment: Stripe Test Mode (Sandbox)
Prerequisites
Before testing, ensure:
- ✅ Dev server running:
pnpm dev - ✅ ngrok tunnel active
- ✅ Webhook configured in Stripe sandbox
- ✅ All environment variables set in
.env.local - ✅ You're signed in to the application
Test Suite
Test 1: Checkout Flow - Personal Tier Monthly
Objective: Verify complete checkout and subscription creation
Steps:
- Go to
http://localhost:3017/pricing - Ensure "Monthly" is selected
- Click "Start Free Trial" on Personal tier ($4/month)
- Should redirect to Stripe Checkout
- Fill in test card details:
- Card:
4242 4242 4242 4242 - Expiry:
12/25 - CVC:
123 - ZIP:
12345 - Email: Your test email
- Card:
- Click "Subscribe"
- Should redirect to
/checkout/success
Expected Results:
- ✅ Success page displays
- ✅ Shows "10-day free trial has started"
- ✅ Console logs:
✅ Received webhook: customer.subscription.created - ✅ Console logs:
Subscription created: sub_... for user user_...
Verification:
# Check Stripe Dashboard
# Go to: Customers → Find your customer → See subscription with trial
# Check Convex Database
# Go to: Convex Dashboard → Data → subscriptions table
# Verify record exists with:
# - userId: your user ID
# - tier: "personal"
# - status: "trialing"
# - trialEndsAt: ~10 days from nowTest 2: Subscription Status Display
Objective: Verify settings page shows correct subscription info
Steps:
- Go to
http://localhost:3017/settings - View Subscription Status Card
Expected Results:
- ✅ Card displays "Personal" tier
- ✅ Status badge shows "Trial Active" (blue)
- ✅ Shows "X days remaining" in trial
- ✅ Shows plan limits:
- Pages: 3
- Tabs per Page: 5
- Cloud Sync: Enabled
- Premium Widgets: Disabled
- ✅ "Manage Subscription" button visible
Test 3: Customer Portal Access
Objective: Verify portal opens and shows correct information
Steps:
- From
/settings, click "Manage Subscription" - Should redirect to Stripe Customer Portal
- Verify portal shows:
- Current plan: Personal
- Status: Trialing
- Trial end date
- Payment method on file
- Click "Return to [your app]"
- Should redirect back to
/settings?portal=true
Expected Results:
- ✅ Portal opens successfully
- ✅ Shows correct subscription info
- ✅ Return link works
- ✅ Returns to settings page
Test 4: Backend Limit Enforcement - Pages
Objective: Verify page creation limits are enforced
Steps:
- Go to your app dashboard
- Create 1st page → Should succeed
- Create 2nd page → Should succeed
- Create 3rd page → Should succeed
- Try to create 4th page → Should FAIL
Expected Results:
- ✅ First 3 pages created successfully
- ✅ 4th page creation blocked
- ✅ Error message shown:
You've reached the 3 page limit for the personal tier. Upgrade to pro for unlimited pages.
Console Verification:
Error: {"code":"LIMIT_REACHED","message":"You've reached the 3 page limit...","upgradeRequired":true,"currentTier":"personal","suggestedTier":"pro","currentUsage":3,"limit":3}Test 5: Backend Limit Enforcement - Tabs
Objective: Verify tabs per page limits are enforced
Steps:
- Open any page in your dashboard
- Create 1st tab → Should succeed
- Create 2nd tab → Should succeed
- Create 3rd tab → Should succeed
- Create 4th tab → Should succeed
- Create 5th tab → Should succeed
- Try to create 6th tab → Should FAIL
Expected Results:
- ✅ First 5 tabs created successfully
- ✅ 6th tab creation blocked
- ✅ Error message shown:
You've reached the 5 tabs per page limit for the personal tier. Upgrade to pro for unlimited tabs.
Test 6: Plan Upgrade via Portal
Objective: Verify plan upgrade works and syncs to Convex
Steps:
- From
/settings, click "Manage Subscription" - In Stripe Portal, click "Update plan"
- Select Pro plan
- Confirm upgrade
- Return to app
Expected Results:
- ✅ Upgrade completes in portal
- ✅ Webhook received:
customer.subscription.updated - ✅ Convex database updated with tier: "pro"
- ✅ Settings page shows "Pro" tier
- ✅ Plan limits updated:
- Pages: Unlimited
- Tabs per Page: Unlimited
- Premium Widgets: Enabled
- ✅ Can now create more than 3 pages
- ✅ Can now create more than 5 tabs per page
Console Verification:
✅ Received webhook: customer.subscription.updated
Subscription updated: sub_...Test 7: Payment Method Update
Objective: Verify payment method can be updated
Steps:
- From
/settings, click "Manage Subscription" - In portal, click "Update payment method"
- Add new test card:
5555 5555 5555 4444(Mastercard) - Set as default
- Return to app
Expected Results:
- ✅ New card added successfully
- ✅ Set as default payment method
- ✅ Old card still visible (can delete if desired)
Test 8: Subscription Cancellation
Objective: Verify cancellation works and syncs correctly
Steps:
- From
/settings, click "Manage Subscription" - In portal, click "Cancel subscription"
- Select "Cancel at end of billing period"
- Confirm cancellation
- Return to app
Expected Results:
- ✅ Cancellation confirmed in portal
- ✅ Webhook received:
customer.subscription.updated - ✅ Subscription status shows "Active" (still in period)
- ✅ Portal shows "Cancels on [date]"
- ✅ Can still use features until period ends
Console Verification:
✅ Received webhook: customer.subscription.updated
Subscription updated: sub_...Database Verification:
Check Convex subscriptions table:
- cancelAtPeriodEnd: true
- status: "active" (still active until period ends)Test 9: Subscription Reactivation
Objective: Verify canceled subscription can be reactivated
Steps:
- From
/settings, click "Manage Subscription" - In portal, should see "Renew subscription" button
- Click "Renew subscription"
- Confirm renewal
- Return to app
Expected Results:
- ✅ Renewal confirmed in portal
- ✅ Webhook received:
customer.subscription.updated - ✅ Status shows "Active" without cancellation notice
- ✅ Portal no longer shows cancel date
Console Verification:
✅ Received webhook: customer.subscription.updated
Subscription updated: sub_...Database Verification:
Check Convex subscriptions table:
- cancelAtPeriodEnd: false
- status: "active"Test 10: Yearly Subscription
Objective: Verify yearly billing works correctly
Steps:
- Go to
/pricing - Toggle to "Yearly"
- Click "Start Free Trial" on Pro tier ($90/year)
- Complete checkout with test card
- Verify subscription created
Expected Results:
- ✅ Checkout shows $90/year pricing
- ✅ Subscription created with yearly interval
- ✅ Shows "$7.50/month billed annually" in portal
- ✅ Next billing date is 1 year from now (after trial)
Test 11: Free Tier User Experience
Objective: Verify free tier users see upgrade prompts
Steps:
- Create a new test user (or cancel subscription to downgrade)
- Go to
/settingsas free tier user - View subscription status
Expected Results:
- ✅ Shows "Free" tier
- ✅ Plan limits:
- Pages: 1
- Tabs per Page: 3
- Cloud Sync: Disabled
- Premium Widgets: Disabled
- ✅ Shows "View Plans" button instead of "Manage Subscription"
- ✅ Button links to
/pricing
Test 12: Failed Payment Simulation
Objective: Verify payment failure handling
Steps:
- In Stripe Dashboard, find your subscription
- Click "Actions" → "Simulate payment failure"
- Or create new subscription with decline card:
4000 0000 0000 0002 - Check webhook and status
Expected Results:
- ✅ Webhook received:
invoice.payment_failed - ✅ Status changes to "past_due"
- ✅ Settings page shows "Payment Due" badge (yellow)
- ✅ Warning message displayed:
Your last payment failed. Please update your payment method to maintain access.
Console Verification:
✅ Received webhook: invoice.payment_failed
Payment failed for subscription: sub_...Webhook Monitoring
Real-time Console Logs
Watch your Next.js console for these webhook events:
# Subscription created
✅ Received webhook: customer.subscription.created
Subscription created: sub_1234567890 for user user_abc123
# Subscription updated (upgrades, downgrades, renewals)
✅ Received webhook: customer.subscription.updated
Subscription updated: sub_1234567890
# Payment succeeded
✅ Received webhook: invoice.payment_succeeded
Payment succeeded for subscription: sub_1234567890
# Payment failed
✅ Received webhook: invoice.payment_failed
Payment failed for subscription: sub_1234567890
# Subscription deleted/canceled
✅ Received webhook: customer.subscription.deleted
Subscription deleted: sub_1234567890ngrok Dashboard
Monitor requests at: http://127.0.0.1:4040
Should see:
- ✅ POST requests to
/api/stripe/webhook - ✅ Status: 200 OK
- ✅ Response:
{"received":true}
Stripe Dashboard
Check webhook delivery:
- Go to: Developers → Webhooks → Your endpoint
- Click "Recent deliveries" tab
- Verify all events show ✅ Success
Quick Verification Checklist
After running tests, verify:
Stripe Dashboard
- Customer created with correct email
- Subscription shows correct tier
- Trial end date is ~10 days from now
- Payment method on file
- Webhooks all show success (200 OK)
Convex Database
-
subscriptionstable has record -
userIdmatches your user -
tieris correct ("personal", "pro", or "team") -
statusis correct ("trialing" or "active") -
stripeSubscriptionIdstarts with "sub_" -
stripeCustomerIdstarts with "cus_" -
trialEndsAtis ~10 days from now
Application UI
- Settings page loads without errors
- Subscription status card shows correct info
- Trial countdown displays correctly
- Manage subscription button works
- Customer portal opens and returns correctly
- Pricing page checkouts work
Backend Enforcement
- Page creation limits enforced
- Tab creation limits enforced
- Error messages include upgrade suggestions
- Limits update after plan upgrade
Test Cards Reference
Success Cards
4242 4242 4242 4242- Visa5555 5555 5555 4444- Mastercard3782 822463 10005- Amex
Failure Cards
4000 0000 0000 0002- Card declined4000 0000 0000 9995- Insufficient funds4000 0000 0000 0069- Expired card
For all cards: Any future expiry, any CVC, any ZIP
Troubleshooting
Issue: Webhook not received
Check:
- ngrok tunnel still active? Run
ngrok http 3017 - Webhook URL correct in Stripe? Should match ngrok URL
- Dev server running? Run
pnpm dev - Check ngrok dashboard:
http://127.0.0.1:4040
Issue: "No subscription found" in portal
Cause: Subscription not created or webhook failed
Fix:
- Check console logs for webhook errors
- Verify subscription exists in Stripe Dashboard
- Manually trigger webhook test from Stripe
- Check Convex database for subscription record
Issue: Limits not enforced
Cause: User tier not detected correctly
Fix:
- Check subscription record in Convex
- Verify
tierfield is set correctly - Check mutations are importing tier limits helper
- Test with TypeScript compilation:
npx tsc --noEmit
Issue: Settings page doesn't load
Cause: Missing Badge component import
Fix: Badge component should be available in @workspace/ui/primitives/badge
Success Criteria
✅ All tests pass ✅ Webhooks deliver successfully ✅ Database records correct ✅ UI displays accurate info ✅ Limits enforced properly ✅ Portal works end-to-end ✅ No console errors
When all tests pass, the subscription system is fully functional and ready for production! 🎉
Next step: Switch to live Stripe keys when ready to accept real payments.