Testing Your SaaS
This guide provides a comprehensive testing strategy for your LaunchKit SaaS application, covering user flows, payment processing, email delivery, and system reliability.
Overview
Section titled “Overview”Complete testing ensures your SaaS application works reliably for users. This guide covers:
- End-to-end user flows from signup to purchase
- Payment processing with Stripe integration
- Email delivery and template rendering
- Admin functionality and user management
- Performance and security testing
Pre-Testing Checklist
Section titled “Pre-Testing Checklist”Before beginning comprehensive testing, ensure:
1. Environment Setup
Section titled “1. Environment Setup”- Development server running (
bun dev
) - Database migration completed
- All environment variables configured
- Stripe CLI running (
stripe listen --forward-to localhost:3000/api/webhook/stripe
) - Email service configured (Resend)
2. Test Data Preparation
Section titled “2. Test Data Preparation”- Test user accounts created
- Test products configured in database
- Stripe test products and prices set up
- Admin user account available
3. Service Integrations
Section titled “3. Service Integrations”- Supabase connection verified
- Stripe test mode active
- Email service responsive
- OAuth providers configured (if used)
User Flow Testing
Section titled “User Flow Testing”1. New User Registration Flow
Section titled “1. New User Registration Flow”Test Steps:
- Navigate to
/signin
- Click “Sign Up” tab
- Enter valid test data:
- Name: “Test User”
- Email: “[email protected]”
- Password: “testpass123”
- Submit form
Expected Results:
- User account created in
auth.users
- Profile record created in
profiles
table - Email confirmation sent (check Resend logs)
- Redirect to email confirmation message
Verification:
-- Check user creation
SELECT id, email, email_confirmed_at FROM auth.users WHERE email = '[email protected]';
-- Check profile creation
SELECT id, name, email, created_at FROM profiles WHERE email = '[email protected]';
Test Steps:
- Navigate to
/signin
- Click “Continue with Google”
- Complete OAuth flow
- Authorize application
Expected Results:
- User redirected through OAuth provider
- Account created with OAuth metadata
- Profile auto-populated with OAuth data
- Redirected to
/dashboard
Verification:
-- Check OAuth user data
SELECT raw_user_meta_data FROM auth.users WHERE email = '[email protected]';
Test Steps:
- Navigate to
/magic-link
- Enter email address
- Submit form
- Check email for magic link
- Click magic link
Expected Results:
- Magic link email sent
- User authenticated on link click
- Session established
- Redirected to dashboard
Debug Magic Links:
# Check Supabase auth logs
# Verify email delivery in Resend dashboard
# Test link expiration (links expire after 1 hour)
2. User Authentication Flow
Section titled “2. User Authentication Flow”Login Testing:
// Test different login scenarios
const loginTests = [
{
scenario: 'Valid credentials',
email: '[email protected]',
password: 'testpass123',
expectedResult: 'success'
},
{
scenario: 'Invalid password',
email: '[email protected]',
password: 'wrongpass',
expectedResult: 'error'
},
{
scenario: 'Non-existent user',
email: '[email protected]',
password: 'password123',
expectedResult: 'error'
},
{
scenario: 'Unconfirmed email',
email: '[email protected]',
password: 'password123',
expectedResult: 'confirmation_required'
}
];
Session Management Testing:
- Login successfully
- Verify session cookie set
- Navigate to protected route
- Refresh page (session should persist)
- Logout and verify session cleared
3. Dashboard Access and Navigation
Section titled “3. Dashboard Access and Navigation”Protected Route Testing:
- Access
/dashboard
without authentication- Should redirect to
/signin
- Should redirect to
- Login and access
/dashboard
- Should display dashboard content
- Test navigation between dashboard sections
- Verify user-specific data displayed
Admin Route Testing:
- Access
/dashboard/admin
as regular user- Should redirect to
/dashboard
or show access denied
- Should redirect to
- Promote user to admin in database
- Access
/dashboard/admin
as admin- Should display admin interface
Payment Flow Testing
Section titled “Payment Flow Testing”1. Product Purchase Flow
Section titled “1. Product Purchase Flow”One-Time Purchase Testing:
Test Steps:
- Navigate to pricing page
- Click “Purchase” on test product
- Complete Stripe checkout with test card:
- Card:
4242424242424242
- Expiry:
12/34
- CVC:
123
- Card:
- Complete purchase
Expected Results:
- Stripe checkout session created
- Payment processed successfully
- Webhook
checkout.session.completed
received - Purchase record created in database
- User access granted (
has_access = true
) - Purchase confirmation email sent
- User redirected to success page
Verification:
-- Check purchase record
SELECT * FROM purchases WHERE user_id = 'user-id' ORDER BY created_at DESC LIMIT 1;
-- Check user access granted
SELECT has_access, customer_id FROM profiles WHERE id = 'user-id';
Stripe CLI Output to Monitor:
2025-01-15 10:30:15 --> checkout.session.completed [evt_1234567890]
2025-01-15 10:30:15 <-- [200] POST http://localhost:3000/api/webhook/stripe
Test Steps:
- Navigate to pricing page
- Click “Purchase” on test product
- Use declined card:
4000000000000002
- Attempt purchase
Expected Results:
- Payment declined by Stripe
- User shown error message
- No purchase record created
- No access granted
- User can retry with different payment method
Test Card Numbers:
4000000000000002
- Declined4000000000000069
- Expired card4000000000000127
- Incorrect CVC
Test Steps:
- Set up subscription product in Stripe
- Create corresponding product in database with
billing_type: 'subscription'
- Navigate to pricing page
- Purchase subscription product
- Complete Stripe checkout
Expected Results:
- Subscription created in Stripe
- Initial payment processed
- User access granted
- Subscription confirmation email sent
Test Subscription Management:
- Access
/dashboard/settings/billing
- Click “Manage Billing” (opens Stripe Customer Portal)
- Test subscription changes, cancellation, etc.
2. Webhook Processing Testing
Section titled “2. Webhook Processing Testing”Test All Webhook Events:
# Simulate successful checkout
stripe trigger checkout.session.completed
# Simulate expired checkout
stripe trigger checkout.session.expired
Verify Processing:
- Check server logs for webhook processing
- Verify database updates
- Confirm emails sent
# Simulate subscription events
stripe trigger customer.subscription.updated
stripe trigger customer.subscription.deleted
stripe trigger invoice.paid
stripe trigger invoice.payment_failed
Test Scenarios:
- Subscription renewal (invoice.paid)
- Payment failure (invoice.payment_failed)
- Subscription cancellation (customer.subscription.deleted)
3. Edge Case Testing
Section titled “3. Edge Case Testing”Payment Edge Cases:
-
Interrupted Payment Flow:
- Start checkout, close browser
- Verify no partial records created
-
Duplicate Webhooks:
- Manually trigger same webhook twice
- Verify idempotent processing
-
Webhook Delays:
- Process webhook after delay
- Verify system handles delayed updates
-
Partial Refunds:
- Process refund in Stripe dashboard
- Verify user access remains if partial refund
Email System Testing
Section titled “Email System Testing”1. Email Template Testing
Section titled “1. Email Template Testing”Use Test Email API:
# Test all email templates
curl "http://localhost:3000/api/test-email?type=all&[email protected]"
# Check your email inbox for 7 different emails:
# 1. Purchase confirmation
# 2. Payment failed
# 3. Checkout expired
# 4. Subscription cancelled
# 5. Invoice paid
# 6. New signup
# 7. GitHub access granted
# Test purchase confirmation
curl "http://localhost:3000/api/test-email?type=purchase-confirmation&[email protected]"
# Test new signup email
curl "http://localhost:3000/api/test-email?type=new-signup&[email protected]"
# Test payment failed
curl "http://localhost:3000/api/test-email?type=payment-failed&[email protected]"
# Start email development server
bun run email:dev
# Opens http://localhost:3001
# Preview all email templates
# Test responsive design
# Check across different email clients
2. Email Delivery Testing
Section titled “2. Email Delivery Testing”Production Email Testing:
-
Configure Resend with your domain
-
Test email delivery to different providers:
- Gmail
- Outlook
- Yahoo
- Custom domain emails
-
Check spam folder delivery
-
Verify email authentication (SPF, DKIM)
-
Test unsubscribe links
Email Content Testing:
- Verify all dynamic content renders correctly
- Test with different user data scenarios
- Check responsive design on mobile
- Verify all links work correctly
3. Email Integration Testing
Section titled “3. Email Integration Testing”Webhook-Triggered Emails:
- Complete a purchase → verify purchase confirmation email
- Fail a payment → verify payment failure email
- Cancel subscription → verify cancellation email
- Create new user → verify welcome email
Manual Email Triggers:
// Test email service directly
import { EmailService } from '@/libs/email-service';
await EmailService.sendPurchaseConfirmation({
customerName: 'Test User',
customerEmail: '[email protected]',
orderNumber: 'TEST-001',
productName: 'Test Product',
amount: '$99.00',
// ... other required fields
});
Admin Functionality Testing
Section titled “Admin Functionality Testing”1. Admin Access Testing
Section titled “1. Admin Access Testing”Admin Hook Testing:
// Test useIsAdmin hook
const AdminTestComponent = () => {
const { isAdmin, loading, user } = useIsAdmin();
console.log('Admin status:', { isAdmin, loading, user });
return (
<div>
{loading && <div>Loading admin status...</div>}
{!loading && !isAdmin && <div>Not admin</div>}
{!loading && isAdmin && <div>Admin confirmed</div>}
</div>
);
};
Admin Route Protection:
- Access
/dashboard/admin
as regular user - Promote user to admin:
UPDATE profiles SET is_admin = true WHERE email = '[email protected]'
- Refresh page and verify admin access granted
- Test all admin subsections
2. Admin Operations Testing
Section titled “2. Admin Operations Testing”User Management:
- View users list at
/dashboard/admin/users
- Search and filter users
- Promote user to admin
- Revoke admin access
- Grant/revoke product access
- Export user data
Product Management:
- Create new product
- Edit product details
- Set pricing and features
- Enable/disable products
- Test product synchronization with Stripe
Order Management:
- View orders list
- Filter by date, status, amount
- View order details
- Process refunds (if implemented)
- Export order data
3. Analytics and Reporting
Section titled “3. Analytics and Reporting”Dashboard Metrics:
- Verify user count accuracy
- Check revenue calculations
- Test chart data accuracy
- Verify date range filtering
Data Export:
- Export user data
- Export order data
- Export analytics reports
- Verify data integrity
Performance Testing
Section titled “Performance Testing”1. Load Testing
Section titled “1. Load Testing”Database Performance:
-- Test query performance
EXPLAIN ANALYZE SELECT * FROM profiles WHERE has_access = true;
EXPLAIN ANALYZE SELECT * FROM purchases WHERE created_at > NOW() - INTERVAL '30 days';
-- Monitor connection usage
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
API Endpoint Testing:
# Test API response times
curl -w "@curl-format.txt" -o /dev/null -s "http://localhost:3000/api/products/public"
# Load test with ab (Apache Bench)
ab -n 100 -c 10 http://localhost:3000/api/products/public
2. Browser Performance
Section titled “2. Browser Performance”Core Web Vitals:
- Use Chrome DevTools Lighthouse
- Test on different device sizes
- Check loading performance
- Verify accessibility scores
Memory Usage:
- Monitor memory usage during navigation
- Check for memory leaks
- Test with large datasets
3. Database Performance
Section titled “3. Database Performance”Query Optimization:
-- Check slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
-- Analyze table usage
SELECT schemaname, tablename, n_tup_ins, n_tup_upd, n_tup_del
FROM pg_stat_user_tables
ORDER BY n_tup_ins DESC;
Security Testing
Section titled “Security Testing”1. Authentication Security
Section titled “1. Authentication Security”Session Security:
- Test session timeout
- Verify secure cookie settings
- Test concurrent session limits
- Check CSRF protection
Password Security:
- Test password requirements
- Verify password hashing
- Test rate limiting on login attempts
- Check password reset security
2. Authorization Testing
Section titled “2. Authorization Testing”Row Level Security (RLS):
-- Test RLS policies as different users
SET ROLE authenticated;
SET request.jwt.claims TO '{"sub": "user-id-1"}';
-- Try to access other user's data
SELECT * FROM profiles WHERE id != 'user-id-1';
-- Should return no results
-- Test admin access
SET request.jwt.claims TO '{"sub": "admin-user-id"}';
SELECT * FROM profiles LIMIT 1;
-- Should work for admin users
API Security:
- Test unauthenticated API access
- Verify admin-only endpoints protected
- Test input validation
- Check for SQL injection vulnerabilities
3. Data Protection
Section titled “3. Data Protection”Sensitive Data:
- Verify no passwords in logs
- Check Stripe keys not exposed
- Verify personal data encryption
- Test data deletion compliance
Integration Testing
Section titled “Integration Testing”1. Third-Party Service Integration
Section titled “1. Third-Party Service Integration”Stripe Integration:
# Test Stripe API connectivity
curl -u sk_test_your_secret_key: https://api.stripe.com/v1/customers/limit=1
# Test webhook endpoint
curl -X POST http://localhost:3000/api/webhook/stripe \
-H "Content-Type: application/json" \
-d '{"type": "checkout.session.completed"}'
Supabase Integration:
// Test database connection
const testSupabase = async () => {
const { data, error } = await supabase
.from('profiles')
.select('id')
.limit(1);
if (error) {
console.error('Supabase error:', error);
} else {
console.log('Supabase connected:', data);
}
};
Email Service Integration:
// Test Resend connectivity
const testResend = async () => {
try {
const response = await fetch('https://api.resend.com/domains', {
headers: {
'Authorization': `Bearer ${process.env.RESEND_API_KEY}`,
},
});
console.log('Resend status:', response.status);
} catch (error) {
console.error('Resend error:', error);
}
};
2. Cross-Browser Testing
Section titled “2. Cross-Browser Testing”Browser Compatibility:
- Test on Chrome, Firefox, Safari, Edge
- Verify mobile responsiveness
- Test touch interactions
- Check keyboard navigation
Feature Testing:
- Payment forms in different browsers
- OAuth flows across browsers
- File upload functionality
- Real-time features
Automated Testing Setup
Section titled “Automated Testing Setup”1. Unit Testing
Section titled “1. Unit Testing”// __tests__/utils.test.ts
import { formatCurrency } from '@/libs/utils';
describe('formatCurrency', () => {
test('formats USD correctly', () => {
expect(formatCurrency(99.99, 'USD')).toBe('$99.99');
});
test('handles zero amounts', () => {
expect(formatCurrency(0, 'USD')).toBe('$0.00');
});
});
2. Integration Testing
Section titled “2. Integration Testing”// __tests__/api/products.test.ts
import { GET } from '@/app/api/products/public/route';
describe('/api/products/public', () => {
test('returns active products', async () => {
const response = await GET();
const data = await response.json();
expect(response.status).toBe(200);
expect(Array.isArray(data.products)).toBe(true);
});
});
3. End-to-End Testing
Section titled “3. End-to-End Testing”// e2e/purchase-flow.spec.ts
import { test, expect } from '@playwright/test';
test('complete purchase flow', async ({ page }) => {
// Navigate to pricing
await page.goto('/pricing');
// Click purchase button
await page.click('[data-testid="purchase-button"]');
// Fill Stripe checkout
await page.fill('[data-testid="card-number"]', '4242424242424242');
await page.fill('[data-testid="card-expiry"]', '1234');
await page.fill('[data-testid="card-cvc"]', '123');
// Complete purchase
await page.click('[data-testid="submit-payment"]');
// Verify success
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('[data-testid="purchase-success"]')).toBeVisible();
});
Testing Checklist
Section titled “Testing Checklist”Pre-Launch Testing
Section titled “Pre-Launch Testing”Core Functionality:
- User registration (all methods)
- User authentication (login/logout)
- Password reset flow
- Email verification
- Payment processing (one-time and subscription)
- Webhook processing
- Email delivery
- Admin functionality
- User dashboard
- Product management
Security:
- Authentication security
- Authorization (RLS policies)
- Input validation
- Rate limiting
- HTTPS enforcement
- Secure headers
- No sensitive data exposure
Performance:
- Page load times < 3 seconds
- API response times < 1 second
- Database query optimization
- Image optimization
- Caching implementation
Cross-Platform:
- Desktop browsers (Chrome, Firefox, Safari, Edge)
- Mobile browsers
- Different screen sizes
- Touch interactions
- Keyboard navigation
Integration:
- Stripe payments working
- Supabase database accessible
- Email delivery functioning
- OAuth providers working
- Third-party services responding
Production Monitoring
Section titled “Production Monitoring”Ongoing Monitoring:
// Set up monitoring alerts
const monitoringChecks = [
'Database connection',
'Stripe webhook processing',
'Email delivery rates',
'Error rates < 1%',
'Response times < 2s',
'Uptime > 99.9%'
];
Regular Testing:
- Weekly: Full user flow testing
- Daily: Payment processing verification
- Continuous: Automated test suite
- Monthly: Security audit
- Quarterly: Performance review
Troubleshooting Common Issues
Section titled “Troubleshooting Common Issues”Payment Issues
Section titled “Payment Issues”# Check Stripe webhook logs
stripe logs tail --filter-account=your-account
# Verify webhook endpoint
curl -X POST your-domain.com/api/webhook/stripe \
-H "Stripe-Signature: test"
Database Issues
Section titled “Database Issues”-- Check database connections
SELECT * FROM pg_stat_activity WHERE state = 'active';
-- Monitor query performance
SELECT query, calls, total_time FROM pg_stat_statements
ORDER BY total_time DESC LIMIT 5;
Email Issues
Section titled “Email Issues”// Test email service
const debugEmail = async () => {
try {
const result = await fetch('/api/test-email?type=new-signup');
console.log('Email test result:', await result.json());
} catch (error) {
console.error('Email test failed:', error);
}
};
Testing your SaaS application thoroughly ensures a reliable, secure, and performant experience for your users. Use this guide as a comprehensive checklist before launching your LaunchKit-based application to production.