template-saas-frontend-v2/tests/e2e/subscription.spec.ts
Adrian Flores Cortes f59bbfac64 [SYNC] feat: Add query-keys hook and e2e tests
- src/hooks/query-keys.ts
- tests/e2e/registration.spec.ts
- tests/e2e/subscription.spec.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 18:12:21 -06:00

349 lines
13 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { Page } from '@playwright/test';
test.describe('Subscription Flow', () => {
let page: Page;
test.beforeEach(async ({ page }) => {
page = page;
});
test('should display pricing page', async () => {
await page.goto('/pricing');
// Check page title
await expect(page).toHaveTitle(/Pricing/);
// Check pricing plans
await expect(page.locator('[data-testid="pricing-plans"]')).toBeVisible();
await expect(page.locator('[data-testid="plan-basic"]')).toBeVisible();
await expect(page.locator('[data-testid="plan-pro"]')).toBeVisible();
await expect(page.locator('[data-testid="plan-enterprise"]')).toBeVisible();
});
test('should show plan details', async () => {
await page.goto('/pricing');
// Click on Pro plan
await page.locator('[data-testid="plan-pro"]').click();
// Check modal opens with details
await expect(page.locator('[data-testid="plan-modal"]')).toBeVisible();
await expect(page.locator('text=Pro Plan Features')).toBeVisible();
// Check features list
await expect(page.locator('[data-testid="feature-list"]')).toBeVisible();
await expect(page.locator('text=Unlimited users')).toBeVisible();
await expect(page.locator('text=100GB storage')).toBeVisible();
await expect(page.locator('text=Priority support')).toBeVisible();
});
test('should select plan and proceed to checkout', async () => {
await page.goto('/pricing');
// Select Pro plan
await page.locator('[data-testid="plan-pro"] [data-testid="select-plan"]').click();
// Should redirect to checkout
await expect(page).toHaveURL(/checkout/);
// Check checkout page elements
await expect(page.locator('[data-testid="checkout-form"]')).toBeVisible();
await expect(page.locator('[data-testid="plan-summary"]')).toBeVisible();
await expect(page.locator('[data-testid="payment-method"]')).toBeVisible();
});
test('should fill payment form', async () => {
// Mock user is logged in
await page.goto('/checkout?plan=pro');
// Fill card details
await page.locator('[data-testid="card-number"]').fill('4242424242424242');
await page.locator('[data-testid="card-expiry"]').fill('12/25');
await page.locator('[data-testid="card-cvc"]').fill('123');
await page.locator('[data-testid="card-name"]').fill('John Doe');
// Fill billing address
await page.locator('[data-testid="billing-address"]').fill('123 Main St');
await page.locator('[data-testid="billing-city"]').fill('New York');
await page.locator('[data-testid="billing-zip"]').fill('10001');
await page.locator('[data-testid="billing-country"]').selectOption('US');
// Accept terms
await page.locator('[data-testid="accept-terms"]').check();
// Enable auto-renew
await page.locator('[data-testid="auto-renew"]').check();
});
test('should validate payment form', async () => {
await page.goto('/checkout?plan=pro');
// Submit empty form
await page.locator('[data-testid="submit-payment"]').click();
// Check validation errors
await expect(page.locator('text=Card number is required')).toBeVisible();
await expect(page.locator('text=Expiry date is required')).toBeVisible();
await expect(page.locator('text=CVC is required')).toBeVisible();
await expect(page.locator('text=Name on card is required')).toBeVisible();
});
test('should validate card number format', async () => {
await page.goto('/checkout?plan=pro');
// Enter invalid card number
await page.locator('[data-testid="card-number"]').fill('123456');
await page.locator('[data-testid="submit-payment"]').click();
await expect(page.locator('text=Please enter a valid card number')).toBeVisible();
});
test('should process subscription successfully', async () => {
// Mock Stripe success response
await page.route('/api/billing/subscribe', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
success: true,
subscription: {
id: 'sub_123',
status: 'active',
plan: 'pro',
current_period_end: '2026-02-20',
},
}),
});
});
await page.goto('/checkout?plan=pro');
// Fill valid payment details
await page.locator('[data-testid="card-number"]').fill('4242424242424242');
await page.locator('[data-testid="card-expiry"]').fill('12/25');
await page.locator('[data-testid="card-cvc"]').fill('123');
await page.locator('[data-testid="card-name"]').fill('John Doe');
await page.locator('[data-testid="accept-terms"]').check();
// Submit payment
await page.locator('[data-testid="submit-payment"]').click();
// Should show success message
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
await expect(page.locator('text=Subscription successful!')).toBeVisible();
// Should redirect to dashboard
await expect(page).toHaveURL(/dashboard/);
});
test('should handle payment failure', async () => {
// Mock Stripe error response
await page.route('/api/billing/subscribe', route => {
route.fulfill({
status: 400,
contentType: 'application/json',
body: JSON.stringify({
error: {
message: 'Your card was declined.',
code: 'card_declined',
},
}),
});
});
await page.goto('/checkout?plan=pro');
// Fill payment details
await page.locator('[data-testid="card-number"]').fill('4000000000000002');
await page.locator('[data-testid="card-expiry"]').fill('12/25');
await page.locator('[data-testid="card-cvc"]').fill('123');
await page.locator('[data-testid="card-name"]').fill('John Doe');
await page.locator('[data-testid="accept-terms"]').check();
// Submit payment
await page.locator('[data-testid="submit-payment"]').click();
// Should show error message
await expect(page.locator('[data-testid="error-message"]')).toBeVisible();
await expect(page.locator('text=Your card was declined')).toBeVisible();
});
test('should support multiple payment methods', async () => {
await page.goto('/checkout?plan=pro');
// Check available payment methods
await expect(page.locator('[data-testid="payment-card"]')).toBeVisible();
await expect(page.locator('[data-testid="payment-paypal"]')).toBeVisible();
await expect(page.locator('[data-testid="payment-bank-transfer"]')).toBeVisible();
// Select PayPal
await page.locator('[data-testid="payment-paypal"]').click();
// Should show PayPal form
await expect(page.locator('[data-testid="paypal-form"]')).toBeVisible();
await expect(page.locator('[data-testid="paypal-email"]')).toBeVisible();
});
test('should apply discount code', async () => {
await page.goto('/checkout?plan=pro');
// Enter discount code
await page.locator('[data-testid="discount-code"]').fill('SAVE20');
await page.locator('[data-testid="apply-discount"]').click();
// Should show discount applied
await expect(page.locator('[data-testid="discount-applied"]')).toBeVisible();
await expect(page.locator('text=20% discount applied')).toBeVisible();
// Check updated price
await expect(page.locator('[data-testid="final-price"]')).toContainText('$79.20');
});
test('should handle invalid discount code', async () => {
await page.goto('/checkout?plan=pro');
// Enter invalid discount code
await page.locator('[data-testid="discount-code"]').fill('INVALID');
await page.locator('[data-testid="apply-discount"]').click();
// Should show error
await expect(page.locator('[data-testid="discount-error"]')).toBeVisible();
await expect(page.locator('text=Invalid discount code')).toBeVisible();
});
test('should show subscription management', async () => {
// Mock authenticated user with active subscription
await page.goto('/settings/billing');
// Check subscription details
await expect(page.locator('[data-testid="current-plan"]')).toBeVisible();
await expect(page.locator('text=Pro Plan')).toBeVisible();
await expect(page.locator('[data-testid="subscription-status"]')).toContainText('Active');
await expect(page.locator('[data-testid="next-billing"]')).toBeVisible();
// Check management options
await expect(page.locator('[data-testid="update-payment"]')).toBeVisible();
await expect(page.locator('[data-testid="cancel-subscription"]')).toBeVisible();
await expect(page.locator('[data-testid="download-invoices"]')).toBeVisible();
});
test('should handle subscription upgrade', async () => {
await page.goto('/settings/billing');
// Click upgrade button
await page.locator('[data-testid="upgrade-plan"]').click();
// Should show upgrade options
await expect(page.locator('[data-testid="upgrade-modal"]')).toBeVisible();
await expect(page.locator('[data-testid="plan-enterprise"]')).toBeVisible();
// Select Enterprise plan
await page.locator('[data-testid="select-enterprise"]').click();
// Should show prorated billing info
await expect(page.locator('[data-testid="prorated-amount"]')).toBeVisible();
await expect(page.locator('text=Prorated amount due today')).toBeVisible();
});
test('should handle subscription cancellation', async () => {
await page.goto('/settings/billing');
// Click cancel subscription
await page.locator('[data-testid="cancel-subscription"]').click();
// Should show cancellation modal
await expect(page.locator('[data-testid="cancel-modal"]')).toBeVisible();
await expect(page.locator('text=Are you sure you want to cancel?')).toBeVisible();
// Select cancellation reason
await page.locator('[data-testid="cancellation-reason"]').selectOption('too_expensive');
// Add feedback
await page.locator('[data-testid="cancellation-feedback"]').fill('Found a cheaper alternative');
// Confirm cancellation
await page.locator('[data-testid="confirm-cancellation"]').click();
// Should show confirmation
await expect(page.locator('[data-testid="cancellation-success"]')).toBeVisible();
await expect(page.locator('text=Subscription will be cancelled at the end of the billing period')).toBeVisible();
});
test('should handle subscription reactivation', async () => {
// Mock cancelled subscription
await page.goto('/settings/billing');
// Check reactivation option is available
await expect(page.locator('[data-testid="reactivate-subscription"]')).toBeVisible();
// Click reactivate
await page.locator('[data-testid="reactivate-subscription"]').click();
// Should show reactivation modal
await expect(page.locator('[data-testid="reactivate-modal"]')).toBeVisible();
await expect(page.locator('text=Reactivate your subscription')).toBeVisible();
// Confirm reactivation
await page.locator('[data-testid="confirm-reactivation"]').click();
// Should process reactivation
await expect(page.locator('[data-testid="reactivation-success"]')).toBeVisible();
});
test('should display invoice history', async () => {
await page.goto('/settings/billing');
// Click invoices tab
await page.locator('[data-testid="invoices-tab"]').click();
// Check invoice list
await expect(page.locator('[data-testid="invoice-list"]')).toBeVisible();
await expect(page.locator('[data-testid="invoice-item"]')).toHaveCount(3);
// Check invoice details
await expect(page.locator('[data-testid="invoice-date"]')).toBeVisible();
await expect(page.locator('[data-testid="invoice-amount"]')).toBeVisible();
await expect(page.locator('[data-testid="invoice-status"]')).toBeVisible();
await expect(page.locator('[data-testid="download-invoice"]')).toBeVisible();
});
test('should download invoice', async () => {
// Mock download
const downloadPromise = page.waitForEvent('download');
await page.goto('/settings/billing');
await page.locator('[data-testid="invoices-tab"]').click();
// Click download button
await page.locator('[data-testid="download-invoice"]').first().click();
// Wait for download
const download = await downloadPromise;
expect(download.suggestedFilename()).toMatch(/invoice-\d+\.pdf/);
});
test('should update payment method', async () => {
await page.goto('/settings/billing');
// Click update payment method
await page.locator('[data-testid="update-payment"]').click();
// Should show payment form
await expect(page.locator('[data-testid="payment-form"]')).toBeVisible();
// Fill new card details
await page.locator('[data-testid="card-number"]').fill('5555555555554444');
await page.locator('[data-testid="card-expiry"]').fill('10/26');
await page.locator('[data-testid="card-cvc"]').fill('456');
await page.locator('[data-testid="card-name"]').fill('Jane Smith');
// Submit update
await page.locator('[data-testid="update-payment-submit"]').click();
// Should show success message
await expect(page.locator('[data-testid="update-success"]')).toBeVisible();
await expect(page.locator('text=Payment method updated successfully')).toBeVisible();
});
});