Skip to content
GitHubTwitterDiscord

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.

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

Before beginning comprehensive testing, ensure:

  • 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)
  • Test user accounts created
  • Test products configured in database
  • Stripe test products and prices set up
  • Admin user account available
  • Supabase connection verified
  • Stripe test mode active
  • Email service responsive
  • OAuth providers configured (if used)

Test Steps:

  1. Navigate to /signin
  2. Click “Sign Up” tab
  3. Enter valid test data:
  4. 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]';

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:

  1. Login successfully
  2. Verify session cookie set
  3. Navigate to protected route
  4. Refresh page (session should persist)
  5. Logout and verify session cleared

Protected Route Testing:

  1. Access /dashboard without authentication
    • Should redirect to /signin
  2. Login and access /dashboard
    • Should display dashboard content
  3. Test navigation between dashboard sections
  4. Verify user-specific data displayed

Admin Route Testing:

  1. Access /dashboard/admin as regular user
    • Should redirect to /dashboard or show access denied
  2. Promote user to admin in database
  3. Access /dashboard/admin as admin
    • Should display admin interface

One-Time Purchase Testing:

Test Steps:

  1. Navigate to pricing page
  2. Click “Purchase” on test product
  3. Complete Stripe checkout with test card:
    • Card: 4242424242424242
    • Expiry: 12/34
    • CVC: 123
  4. 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 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

Payment Edge Cases:

  1. Interrupted Payment Flow:

    • Start checkout, close browser
    • Verify no partial records created
  2. Duplicate Webhooks:

    • Manually trigger same webhook twice
    • Verify idempotent processing
  3. Webhook Delays:

    • Process webhook after delay
    • Verify system handles delayed updates
  4. Partial Refunds:

    • Process refund in Stripe dashboard
    • Verify user access remains if partial refund

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

Production Email Testing:

  1. Configure Resend with your domain

  2. Test email delivery to different providers:

    • Gmail
    • Outlook
    • Yahoo
    • Custom domain emails
  3. Check spam folder delivery

  4. Verify email authentication (SPF, DKIM)

  5. Test unsubscribe links

Email Content Testing:

  1. Verify all dynamic content renders correctly
  2. Test with different user data scenarios
  3. Check responsive design on mobile
  4. Verify all links work correctly

Webhook-Triggered Emails:

  1. Complete a purchase → verify purchase confirmation email
  2. Fail a payment → verify payment failure email
  3. Cancel subscription → verify cancellation email
  4. 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 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:

  1. Access /dashboard/admin as regular user
  2. Promote user to admin: UPDATE profiles SET is_admin = true WHERE email = '[email protected]'
  3. Refresh page and verify admin access granted
  4. Test all admin subsections

User Management:

  1. View users list at /dashboard/admin/users
  2. Search and filter users
  3. Promote user to admin
  4. Revoke admin access
  5. Grant/revoke product access
  6. Export user data

Product Management:

  1. Create new product
  2. Edit product details
  3. Set pricing and features
  4. Enable/disable products
  5. Test product synchronization with Stripe

Order Management:

  1. View orders list
  2. Filter by date, status, amount
  3. View order details
  4. Process refunds (if implemented)
  5. Export order data

Dashboard Metrics:

  1. Verify user count accuracy
  2. Check revenue calculations
  3. Test chart data accuracy
  4. Verify date range filtering

Data Export:

  1. Export user data
  2. Export order data
  3. Export analytics reports
  4. Verify data integrity

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

Core Web Vitals:

  1. Use Chrome DevTools Lighthouse
  2. Test on different device sizes
  3. Check loading performance
  4. Verify accessibility scores

Memory Usage:

  1. Monitor memory usage during navigation
  2. Check for memory leaks
  3. Test with large datasets

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;

Session Security:

  1. Test session timeout
  2. Verify secure cookie settings
  3. Test concurrent session limits
  4. Check CSRF protection

Password Security:

  1. Test password requirements
  2. Verify password hashing
  3. Test rate limiting on login attempts
  4. Check password reset security

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:

  1. Test unauthenticated API access
  2. Verify admin-only endpoints protected
  3. Test input validation
  4. Check for SQL injection vulnerabilities

Sensitive Data:

  1. Verify no passwords in logs
  2. Check Stripe keys not exposed
  3. Verify personal data encryption
  4. Test data deletion compliance

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);
  }
};

Browser Compatibility:

  1. Test on Chrome, Firefox, Safari, Edge
  2. Verify mobile responsiveness
  3. Test touch interactions
  4. Check keyboard navigation

Feature Testing:

  1. Payment forms in different browsers
  2. OAuth flows across browsers
  3. File upload functionality
  4. Real-time features
// __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');
  });
});
// __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);
  });
});
// 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();
});

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

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
# 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"
-- 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;
// 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.