import { test, expect } from '@playwright/test'; /** * User Workflow Test * * Tests complete user workflow: * 1. Login with Auth0 * 2. Refresh browser * 3. Create a VIP entry * 4. Save it * 5. Refresh browser */ test.describe('User Workflow', () => { test('login, refresh, create VIP, save, refresh', async ({ page }) => { // Increase timeout to 5 minutes for manual login + workflow test.setTimeout(300000); // ======================================== // SETUP: Comprehensive logging // ======================================== const logs: string[] = []; const errors: string[] = []; const networkErrors: any[] = []; page.on('console', (msg) => { const text = `[BROWSER ${msg.type()}]: ${msg.text()}`; logs.push(text); console.log(text); }); page.on('pageerror', (error) => { const text = `[PAGE ERROR]: ${error.message}\n${error.stack}`; errors.push(text); console.error(text); }); page.on('request', (request) => { const text = `[→ REQUEST] ${request.method()} ${request.url()}`; console.log(text); }); page.on('response', async (response) => { const request = response.request(); const text = `[← RESPONSE] ${response.status()} ${request.method()} ${request.url()}`; console.log(text); // Log failed requests if (response.status() >= 400) { const errorInfo = { status: response.status(), url: request.url(), method: request.method(), }; networkErrors.push(errorInfo); console.error(`[NETWORK ERROR] ${response.status()} ${request.url()}`); // Try to log response body for API errors if (request.url().includes('/api/')) { try { const body = await response.text(); console.error(`[ERROR BODY] ${body}`); } catch (e) { // Can't read body } } } }); // ======================================== // STEP 1: Navigate to Login Page // ======================================== console.log('\n========================================'); console.log('STEP 1: Navigate to Login Page'); console.log('========================================\n'); await page.goto('/login'); await page.waitForLoadState('networkidle'); // Take screenshot of login page await page.screenshot({ path: 'test-results/01-login-page.png', fullPage: true }); console.log('Screenshot saved: 01-login-page.png'); // Check if we see the login button const loginButton = page.locator('button:has-text("Sign in with Auth0")'); await expect(loginButton).toBeVisible({ timeout: 10000 }); console.log('✓ Login button is visible'); // ======================================== // STEP 2: Click Login and Authenticate // ======================================== console.log('\n========================================'); console.log('STEP 2: Click Login (Auth0)'); console.log('========================================\n'); // Click login button await loginButton.click(); console.log('Clicked "Sign in with Auth0" button'); // Wait for Auth0 redirect or dashboard // This will either go to Auth0 login page or directly to dashboard if already logged in await page.waitForTimeout(3000); await page.screenshot({ path: 'test-results/02-after-login-click.png', fullPage: true }); console.log('Screenshot saved: 02-after-login-click.png'); // Check current URL const currentUrl = page.url(); console.log(`Current URL: ${currentUrl}`); // If we're on Auth0 login page, we need to authenticate if (currentUrl.includes('auth0.com') || currentUrl.includes('login')) { console.log('⚠ Auth0 login page detected - attempting automatic login'); try { // Fill in email const emailInput = page.locator('input[name="username"], input[type="email"]').first(); await emailInput.fill('test@test.com'); console.log('✓ Entered email'); // Fill in password const passwordInput = page.locator('input[name="password"], input[type="password"]').first(); await passwordInput.fill('P@ssw0rd!'); console.log('✓ Entered password'); // Click submit button const submitButton = page.locator('button[type="submit"], button:has-text("Continue"), button:has-text("Log in")').first(); await submitButton.click(); console.log('✓ Clicked login button'); // Wait for navigation to dashboard (indicating successful login) await page.waitForURL('**/dashboard', { timeout: 30000 }); console.log('✓ Successfully logged in - redirected to dashboard'); } catch (error) { console.error('❌ Automatic login failed:', error); console.log('\n🔵 PAUSING TEST - Please log in manually in the browser window'); console.log('🔵 After logging in, the test will continue automatically\n'); await page.waitForURL('**/dashboard', { timeout: 180000 }); } } else if (currentUrl.includes('dashboard')) { console.log('✓ Already authenticated - on dashboard'); } else if (currentUrl.includes('pending-approval')) { console.log('⚠ User is not approved yet - on pending approval page'); throw new Error('User needs to be approved by an administrator first'); } await page.screenshot({ path: 'test-results/03-logged-in.png', fullPage: true }); console.log('Screenshot saved: 03-logged-in.png'); // ======================================== // STEP 3: Refresh Browser // ======================================== console.log('\n========================================'); console.log('STEP 3: Refresh Browser'); console.log('========================================\n'); await page.reload(); await page.waitForLoadState('networkidle'); console.log('✓ Browser refreshed'); await page.screenshot({ path: 'test-results/04-after-refresh.png', fullPage: true }); console.log('Screenshot saved: 04-after-refresh.png'); // Verify we're still logged in by checking for Sign Out button const signOutButton = page.locator('button:has-text("Sign Out")'); await expect(signOutButton).toBeVisible({ timeout: 10000 }); console.log('✓ Still logged in after refresh'); // ======================================== // STEP 4: Navigate to VIPs Page // ======================================== console.log('\n========================================'); console.log('STEP 4: Navigate to VIPs Page'); console.log('========================================\n'); // Click on VIPs in navigation const vipsLink = page.locator('a:has-text("VIPs")').first(); await vipsLink.click(); console.log('Clicked VIPs navigation link'); await page.waitForLoadState('networkidle'); await page.screenshot({ path: 'test-results/05-vips-page.png', fullPage: true }); console.log('Screenshot saved: 05-vips-page.png'); // ======================================== // STEP 5: Create New VIP // ======================================== console.log('\n========================================'); console.log('STEP 5: Create New VIP'); console.log('========================================\n'); // Look for "Add VIP" or "New VIP" button const addVipButton = page.locator('button').filter({ hasText: /Add VIP|New VIP|Create VIP|\+/i }).first(); await expect(addVipButton).toBeVisible({ timeout: 10000 }); console.log('✓ Found Add VIP button'); await addVipButton.click(); console.log('Clicked Add VIP button'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/06-vip-form.png', fullPage: true }); console.log('Screenshot saved: 06-vip-form.png'); // ======================================== // STEP 6: Fill Out VIP Form // ======================================== console.log('\n========================================'); console.log('STEP 6: Fill Out VIP Form'); console.log('========================================\n'); // Generate unique test data const timestamp = Date.now(); const testVipName = `Test VIP ${timestamp}`; const testVipOrg = `Test Organization ${timestamp}`; console.log(`Creating VIP: ${testVipName}`); // Fill in the form fields // Note: Adjust selectors based on your actual form structure // Name field const nameInput = page.locator('input[name="name"], input[id="name"]').first(); await nameInput.fill(testVipName); console.log(`✓ Filled name: ${testVipName}`); // Organization field (if exists) const orgInput = page.locator('input[name="organization"], input[id="organization"]').first(); if (await orgInput.count() > 0) { await orgInput.fill(testVipOrg); console.log(`✓ Filled organization: ${testVipOrg}`); } // Contact Info field (if exists) const contactInput = page.locator('input[name="contactInfo"], input[id="contactInfo"], input[placeholder*="contact" i]').first(); if (await contactInput.count() > 0) { await contactInput.fill('test@example.com'); console.log('✓ Filled contact info'); } // Arrival Mode dropdown (if exists) const arrivalSelect = page.locator('select[name="arrivalMode"], select[id="arrivalMode"]').first(); if (await arrivalSelect.count() > 0) { await arrivalSelect.selectOption('FLIGHT'); console.log('✓ Selected arrival mode: FLIGHT'); } // Expected Arrival date (if exists) const arrivalDateInput = page.locator('input[name="expectedArrival"], input[id="expectedArrival"], input[type="datetime-local"]').first(); if (await arrivalDateInput.count() > 0) { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 7); const dateString = futureDate.toISOString().slice(0, 16); await arrivalDateInput.fill(dateString); console.log(`✓ Set expected arrival: ${dateString}`); } await page.screenshot({ path: 'test-results/07-vip-form-filled.png', fullPage: true }); console.log('Screenshot saved: 07-vip-form-filled.png'); // ======================================== // STEP 7: Save VIP // ======================================== console.log('\n========================================'); console.log('STEP 7: Save VIP'); console.log('========================================\n'); // Find and click Save button const saveButton = page.locator('button').filter({ hasText: /Save|Create|Submit/i }).first(); await expect(saveButton).toBeVisible({ timeout: 5000 }); console.log('✓ Found Save button'); await saveButton.click(); console.log('Clicked Save button'); // Wait for save to complete (look for success message or redirect) await page.waitForTimeout(2000); await page.screenshot({ path: 'test-results/08-after-save.png', fullPage: true }); console.log('Screenshot saved: 08-after-save.png'); // Check for success message or new VIP in list const successIndicators = [ page.locator('text=/success/i'), page.locator('text=/created/i'), page.locator(`text="${testVipName}"`), ]; let saveSuccess = false; for (const indicator of successIndicators) { if (await indicator.count() > 0) { saveSuccess = true; console.log('✓ VIP save appears successful'); break; } } if (!saveSuccess) { console.log('⚠ Could not confirm VIP was saved - check screenshots'); } // ======================================== // STEP 8: Final Browser Refresh // ======================================== console.log('\n========================================'); console.log('STEP 8: Final Browser Refresh'); console.log('========================================\n'); await page.reload(); await page.waitForLoadState('networkidle'); console.log('✓ Browser refreshed'); await page.screenshot({ path: 'test-results/09-final-refresh.png', fullPage: true }); console.log('Screenshot saved: 09-final-refresh.png'); // Verify VIP is still visible after refresh const vipInList = page.locator(`text="${testVipName}"`); if (await vipInList.count() > 0) { console.log('✓ VIP still visible after refresh - data persisted!'); } else { console.log('⚠ VIP not visible after refresh - may need to navigate back to VIPs list'); } // ======================================== // FINAL REPORT // ======================================== console.log('\n========================================'); console.log('TEST COMPLETE - FINAL REPORT'); console.log('========================================\n'); console.log(`Total console logs: ${logs.length}`); console.log(`Page errors: ${errors.length}`); console.log(`Network errors: ${networkErrors.length}`); if (errors.length > 0) { console.log('\n❌ PAGE ERRORS FOUND:'); errors.forEach((error, i) => { console.log(`\n${i + 1}. ${error}`); }); } if (networkErrors.length > 0) { console.log('\n❌ NETWORK ERRORS FOUND:'); networkErrors.forEach((error, i) => { console.log(`\n${i + 1}. ${error.status} ${error.method} ${error.url}`); }); } if (errors.length === 0 && networkErrors.length === 0) { console.log('\n✅ NO ERRORS DETECTED - Test completed successfully!'); } console.log('\n📸 Screenshots saved in test-results/ directory'); console.log('========================================\n'); // Fail test if there were errors expect(errors.length).toBe(0); expect(networkErrors.length).toBe(0); }); });