import { test, expect, Page } from '@playwright/test'; test.describe('Checkout Flow - Comprehensive Testing', () => { let page: Page; test.beforeEach(async ({ browser }) => { page = await browser.newPage(); // Navigate to the app and ensure it's loaded await page.goto('/'); // Mock authentication - log in as admin await page.goto('/login'); await page.click('[data-role="admin"]'); await page.waitForURL('/dashboard'); // Ensure page is fully loaded await page.waitForSelector('text=Dashboard'); }); test.afterEach(async () => { await page.close(); }); test.describe('Shopping Cart Functionality', () => { test('should add items to cart and manage quantities', async () => { // Navigate to an event page with ticket purchase option await page.click('text=Events'); await page.waitForSelector('[data-testid="event-card"]'); await page.click('[data-testid="event-card"]'); // Look for ticket purchase component const ticketPurchase = page.locator('[data-testid="ticket-purchase"]'); if (await ticketPurchase.count() > 0) { // Set quantity await page.click('button:has-text("+")') const quantityDisplay = page.locator('text=2'); await expect(quantityDisplay).toBeVisible(); // Add to cart await page.click('button:has-text("Add to Cart")'); // Verify cart button shows item count const cartButton = page.locator('[data-testid="cart-button"]'); await expect(cartButton).toContainText('2'); } }); test('should open cart drawer and display items correctly', async () => { // Add item to cart first (reuse logic from previous test or use mock) // Click cart button await page.click('[data-testid="cart-button"]'); // Verify cart drawer opens await expect(page.locator('[role="dialog"]')).toBeVisible(); await expect(page.locator('text=Shopping Cart')).toBeVisible(); // Check accessibility await expect(page.locator('[aria-labelledby="cart-title"]')).toBeVisible(); await expect(page.locator('#cart-title')).toHaveText('Shopping Cart'); }); test('should update item quantities in cart drawer', async () => { // Open cart with items await page.click('[data-testid="cart-button"]'); // Find quantity controls const increaseBtn = page.locator('[aria-label*="Increase quantity"]').first(); if (await increaseBtn.count() > 0) { await increaseBtn.click(); // Verify quantity updated const quantityText = page.locator('[data-testid="item-quantity"]').first(); await expect(quantityText).not.toBeEmpty(); } }); test('should remove items from cart', async () => { // Open cart await page.click('[data-testid="cart-button"]'); // Click remove button if items exist const removeButton = page.locator('[data-testid="remove-item"]').first(); if (await removeButton.count() > 0) { await removeButton.click(); // Verify item removed await expect(page.locator('text=Your cart is empty')).toBeVisible({ timeout: 5000 }); } }); }); test.describe('Checkout Wizard - Multi-step Flow', () => { test('should open checkout wizard from cart', async () => { // Add item and open checkout await page.click('[data-testid="cart-button"]'); const checkoutButton = page.locator('button:has-text("Proceed to Checkout")'); if (await checkoutButton.count() > 0) { await checkoutButton.click(); // Verify wizard opens await expect(page.locator('[role="dialog"]')).toBeVisible(); await expect(page.locator('#checkout-title')).toHaveText('Checkout'); // Check step indicator await expect(page.locator('[aria-label="Checkout progress"]')).toBeVisible(); } }); test('should navigate through checkout steps', async () => { // Open checkout wizard (mock if needed) await page.evaluate(() => { // Mock opening checkout wizard const event = new CustomEvent('openCheckout'); document.dispatchEvent(event); }); // Navigate through steps const continueButton = page.locator('button:has-text("Continue")'); if (await continueButton.count() > 0) { // Step 1: Cart Review await expect(page.locator('text=Review Your Order')).toBeVisible(); await continueButton.click(); // Step 2: Customer Information await expect(page.locator('text=Customer Information')).toBeVisible(); // Fill out customer form await page.fill('input[placeholder="John"]', 'John'); await page.fill('input[placeholder="Doe"]', 'Doe'); await page.fill('input[placeholder="john.doe@example.com"]', 'test@example.com'); await page.fill('input[placeholder*="555"]', '+1 555-123-4567'); await continueButton.click(); // Step 3: Payment Method await expect(page.locator('text=Payment Method')).toBeVisible(); // Select payment method const creditCardOption = page.locator('text=Credit/Debit Card'); if (await creditCardOption.count() > 0) { await creditCardOption.click(); } await continueButton.click(); // Step 4: Confirmation await expect(page.locator('text=Confirm Your Order')).toBeVisible(); } }); test('should validate customer information form', async () => { // Open checkout wizard // Navigate to customer step const continueButton = page.locator('button:has-text("Continue")'); // Try to continue without filling required fields if (await continueButton.count() > 0) { await continueButton.click(); // Check for validation errors // Validation should prevent advancement } // Fill invalid email await page.fill('input[type="email"]', 'invalid-email'); if (await continueButton.count() > 0) { await continueButton.click(); // Should show email validation error } }); test('should handle payment method selection', async () => { // Navigate to payment step const paymentMethods = page.locator('[data-testid="payment-method"]'); if (await paymentMethods.count() > 0) { // Test selecting different payment methods const cardOption = page.locator('text=Credit/Debit Card'); const paypalOption = page.locator('text=PayPal'); if (await cardOption.count() > 0) { await cardOption.click(); await expect(cardOption).toHaveClass(/border-primary/); } if (await paypalOption.count() > 0) { await paypalOption.click(); await expect(paypalOption).toHaveClass(/border-primary/); } } }); }); test.describe('Error Handling and Recovery', () => { test('should display error screen for checkout failures', async () => { // Mock checkout error await page.evaluate(() => { // Simulate checkout error (window as any).mockCheckoutError = { type: 'payment_failed', message: 'Payment failed', details: 'Your card was declined', retryable: true }; }); // Check if error handler displays const errorHandler = page.locator('[data-testid="checkout-error"]'); if (await errorHandler.count() > 0) { await expect(errorHandler).toBeVisible(); await expect(page.locator('text=Payment Failed')).toBeVisible(); } }); test('should provide retry functionality for retryable errors', async () => { // Test retry button functionality const retryButton = page.locator('button:has-text("Try Again")'); if (await retryButton.count() > 0) { await retryButton.click(); // Should attempt checkout again } }); test('should offer alternative actions for non-retryable errors', async () => { // Test alternative action buttons const changePaymentButton = page.locator('button:has-text("Try Different Card")'); const contactSupportButton = page.locator('button:has-text("Contact Support")'); if (await changePaymentButton.count() > 0) { await changePaymentButton.click(); // Should navigate back to payment step } if (await contactSupportButton.count() > 0) { await contactSupportButton.click(); // Should open support contact method } }); }); test.describe('Order Confirmation and Receipt', () => { test('should display order confirmation after successful checkout', async () => { // Mock successful checkout completion await page.goto('/checkout/success?session_id=test_session_123'); // Wait for success page to load await expect(page.locator('text=Purchase Successful!')).toBeVisible({ timeout: 10000 }); // Check for success elements await expect(page.locator('[data-testid="success-icon"]')).toBeVisible(); await expect(page.locator('text=Your tickets have been confirmed')).toBeVisible(); }); test('should display detailed receipt information', async () => { // On checkout success page await page.goto('/checkout/success?session_id=test_session_123'); // Click view receipt button const viewReceiptButton = page.locator('button:has-text("View Receipt")'); if (await viewReceiptButton.count() > 0) { await viewReceiptButton.click(); // Verify receipt displays await expect(page.locator('text=Order Receipt')).toBeVisible(); await expect(page.locator('text=Customer Details')).toBeVisible(); await expect(page.locator('text=Payment Information')).toBeVisible(); await expect(page.locator('text=Ticket Details')).toBeVisible(); } }); test('should provide receipt download and email options', async () => { // Test receipt action buttons const downloadButton = page.locator('button:has-text("Download PDF")'); const emailButton = page.locator('button:has-text("Email Receipt")'); const calendarButton = page.locator('button:has-text("Add to Calendar")'); // These would typically trigger download/email actions if (await downloadButton.count() > 0) { await downloadButton.click(); // Verify download action (would need to mock in real test) } if (await emailButton.count() > 0) { await emailButton.click(); // Verify email action } if (await calendarButton.count() > 0) { await calendarButton.click(); // Verify calendar integration } }); }); test.describe('Accessibility and Mobile Experience', () => { test('should be fully keyboard navigable', async () => { // Test keyboard navigation through checkout await page.keyboard.press('Tab'); // Verify focus management const focusedElement = page.locator(':focus'); await expect(focusedElement).toBeVisible(); // Test arrow key navigation in step indicator await page.keyboard.press('ArrowRight'); await page.keyboard.press('ArrowLeft'); // Test escape key closes modals await page.keyboard.press('Escape'); }); test('should have proper ARIA labels and roles', async () => { // Check checkout wizard accessibility await expect(page.locator('[role="dialog"]')).toHaveAttribute('aria-modal', 'true'); await expect(page.locator('[aria-labelledby="checkout-title"]')).toBeVisible(); // Check form accessibility const requiredInputs = page.locator('input[required]'); const inputCount = await requiredInputs.count(); for (let i = 0; i < inputCount; i++) { const input = requiredInputs.nth(i); await expect(input).toHaveAttribute('aria-required', 'true'); } // Check button accessibility const buttons = page.locator('button[aria-label]'); const buttonCount = await buttons.count(); for (let i = 0; i < buttonCount; i++) { const button = buttons.nth(i); const ariaLabel = await button.getAttribute('aria-label'); expect(ariaLabel).toBeTruthy(); } }); test('should work well on mobile viewport', async () => { // Set mobile viewport await page.setViewportSize({ width: 375, height: 667 }); // Test cart drawer on mobile await page.click('[data-testid="cart-button"]'); // Verify drawer takes full width on mobile const drawer = page.locator('[role="dialog"]'); if (await drawer.count() > 0) { const boundingBox = await drawer.boundingBox(); expect(boundingBox?.width).toBeGreaterThan(300); // Should be near full width } // Test touch targets are large enough (44px minimum) const buttons = page.locator('button'); const buttonCount = await buttons.count(); for (let i = 0; i < Math.min(buttonCount, 5); i++) { const button = buttons.nth(i); if (await button.isVisible()) { const boundingBox = await button.boundingBox(); if (boundingBox) { expect(boundingBox.height).toBeGreaterThanOrEqual(40); // Close to 44px minimum } } } }); test('should handle screen reader announcements', async () => { // Test aria-live regions await expect(page.locator('[aria-live="polite"]')).toBeVisible(); // Test status announcements // Status messages should be announced to screen readers }); }); test.describe('Performance and Edge Cases', () => { test('should handle large cart quantities', async () => { // Test cart with maximum allowed quantities await page.evaluate(() => { // Mock large cart (window as any).mockLargeCart = true; }); // Verify cart performance with many items await page.click('[data-testid="cart-button"]'); // Should render efficiently await expect(page.locator('text=Shopping Cart')).toBeVisible({ timeout: 3000 }); }); test('should handle network interruptions gracefully', async () => { // Mock network failure during checkout await page.route('**/api/checkout', route => { route.abort('failed'); }); // Attempt checkout const checkoutButton = page.locator('button:has-text("Complete Purchase")'); if (await checkoutButton.count() > 0) { await checkoutButton.click(); // Should display network error await expect(page.locator('text=Connection Problem')).toBeVisible({ timeout: 10000 }); } }); test('should clear cart after successful purchase', async () => { // Complete successful checkout await page.goto('/checkout/success?session_id=test_session_123'); // Navigate back to cart await page.goto('/dashboard'); await page.click('[data-testid="cart-button"]'); // Cart should be empty await expect(page.locator('text=Your cart is empty')).toBeVisible(); }); test('should preserve cart data on page refresh', async () => { // Add items to cart // Refresh page await page.reload(); // Cart should still contain items (localStorage persistence) await page.click('[data-testid="cart-button"]'); // Items should still be there (or empty if not implemented) }); }); test.describe('Integration with Existing System', () => { test('should integrate with event data correctly', async () => { // Test that checkout uses real event data const eventTitle = await page.locator('[data-testid="event-title"]').first().textContent(); if (eventTitle) { // Add to cart and verify event info carries through await page.click('button:has-text("Add to Cart")'); await page.click('[data-testid="cart-button"]'); await expect(page.locator(`text=${eventTitle}`)).toBeVisible(); } }); test('should respect user authentication state', async () => { // Test checkout behavior for different user roles await expect(page.locator('[data-testid="user-role"]')).toContainText('admin'); // Should show admin-appropriate checkout options }); test('should handle organization context properly', async () => { // Verify checkout respects current organization const orgName = await page.locator('[data-testid="current-org"]').textContent(); if (orgName) { // Checkout should use organization-specific settings } }); }); });