import { test, expect } from '@playwright/test'; test.describe('Admin Test Data Management', () => { test.beforeEach(async ({ page }) => { test.setTimeout(600000); // 10 minutes - test data creation can take a while with rate limiting // Login await page.goto('http://localhost:5173/login'); await page.locator('button:has-text("Sign in with Auth0")').click(); await page.waitForTimeout(2000); await page.locator('input[name="username"]').fill('test@test.com'); await page.locator('input[name="password"]').fill('P@ssw0rd!'); await page.locator('button[type="submit"][data-action-button-primary="true"]').click(); await page.waitForURL('**/dashboard', { timeout: 30000 }); console.log('āœ… Logged in successfully'); }); test('should load all test data via Admin menu and verify in Events view', async ({ page }) => { console.log('\nšŸ”§ Testing Admin Test Data Management'); // Navigate to Admin Tools console.log('šŸ“‹ Navigating to Admin Tools page'); await page.goto('http://localhost:5173/admin-tools', { waitUntil: 'networkidle' }); // Force reload to ensure latest JavaScript is loaded await page.reload({ waitUntil: 'networkidle' }); await page.screenshot({ path: 'test-results/admin-01-tools-page.png', fullPage: true }); // Verify Admin Tools page loaded const pageTitle = page.locator('h1:has-text("Administrator Tools")'); await expect(pageTitle).toBeVisible(); console.log('āœ… Admin Tools page loaded'); // Step 1: Add Test VIPs console.log('\nšŸ‘„ Adding Test VIPs...'); const addVipsButton = page.locator('button:has-text("Add Test VIPs")'); await addVipsButton.scrollIntoViewIfNeeded(); await expect(addVipsButton).toBeVisible(); // Setup dialog handler for confirmation page.on('dialog', async dialog => { console.log(`šŸ“¢ Confirmation: ${dialog.message()}`); await dialog.accept(); }); await addVipsButton.click(); // Wait for success toast await page.waitForSelector('text=/Added \\d+ test VIPs/', { timeout: 60000 }); console.log('āœ… Test VIPs added successfully'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-02-vips-added.png', fullPage: true }); // Step 2: Add Test Drivers console.log('\nšŸš— Adding Test Drivers...'); const addDriversButton = page.locator('button:has-text("Add Test Drivers")'); await expect(addDriversButton).toBeVisible(); await addDriversButton.click(); await page.waitForSelector('text=/Added .* test [Dd]rivers?/', { timeout: 30000 }); console.log('āœ… Test Drivers added successfully'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-03-drivers-added.png', fullPage: true }); // Step 3: Add Test Vehicles console.log('\n🚐 Adding Test Vehicles...'); const addVehiclesButton = page.locator('button:has-text("Add Test Vehicles")'); await expect(addVehiclesButton).toBeVisible(); await addVehiclesButton.click(); await page.waitForSelector('text=/Added .* test [Vv]ehicles?/', { timeout: 30000 }); console.log('āœ… Test Vehicles added successfully'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-04-vehicles-added.png', fullPage: true }); // Step 4: Add Test Schedule console.log('\nšŸ“… Adding Test Schedule Events...'); const addScheduleButton = page.locator('button:has-text("Add Test Schedule")'); await expect(addScheduleButton).toBeVisible(); await addScheduleButton.click(); // Wait for schedule creation to complete by polling the stats // This can take a while as it creates many events console.log('ā³ Waiting for schedule events to be created...'); let scheduleEventCount = 0; for (let i = 0; i < 60; i++) { // Poll for up to 2 minutes await page.waitForTimeout(2000); // Click refresh button to update stats const refreshButton = page.locator('button:has-text("Refresh")'); if (await refreshButton.isVisible({ timeout: 1000 })) { await refreshButton.click(); await page.waitForTimeout(500); } // Check event count const statsSection = page.locator('text=Database Statistics').locator('..'); const eventsStat = statsSection.locator('text=/Events/').locator('..'); const eventCountText = await eventsStat.locator('.text-3xl, .text-2xl, .text-xl').first().textContent(); scheduleEventCount = parseInt(eventCountText || '0'); if (scheduleEventCount > 0) { console.log(`āœ… Schedule created: ${scheduleEventCount} events found`); break; } if (i % 5 === 0) { console.log(`ā³ Still waiting... (${i * 2}s elapsed)`); } } if (scheduleEventCount === 0) { throw new Error('Schedule creation timed out - no events created after 2 minutes'); } await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-05-schedule-added.png', fullPage: true }); // Step 5: Verify database statistics updated console.log('\nšŸ“Š Verifying database statistics...'); // Refresh the page to get updated stats await page.reload(); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-06-stats-updated.png', fullPage: true }); // Try to verify stats if visible try { const statsSection = page.locator('text=Database Statistics').locator('..'); if (await statsSection.isVisible({ timeout: 3000 })) { console.log('āœ… Database statistics section found'); // Look for any number indicators that show counts const numbers = await statsSection.locator('.text-3xl, .text-2xl, .text-xl').allTextContents(); console.log(`šŸ“Š Stats visible: ${numbers.join(', ')}`); } else { console.log('ā„¹ļø Stats section not found - will verify via Events page'); } } catch (e) { console.log('ā„¹ļø Could not verify stats - will check Events page instead'); } // Step 6: Navigate to Events view console.log('\nšŸ“… Navigating to Events view...'); await page.goto('http://localhost:5173/events'); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/admin-07-events-page.png', fullPage: true }); // Verify Events page loaded const eventsPageTitle = page.locator('h1, h2').filter({ hasText: /Events|Schedule/ }); await expect(eventsPageTitle).toBeVisible(); console.log('āœ… Events page loaded'); // Step 7: Verify events are displayed console.log('\nšŸ” Verifying events are displayed...'); // Wait for table to load await page.waitForSelector('table, .event-list, .event-card', { timeout: 10000 }); // Count event rows (could be in a table or as cards) let eventCount = 0; // Try to find table rows first const tableRows = await page.locator('tbody tr').count(); if (tableRows > 0) { eventCount = tableRows; console.log(`šŸ“Š Found ${eventCount} events in table`); } else { // Try to find event cards const eventCards = await page.locator('.event-card, [class*="event"]').count(); eventCount = eventCards; console.log(`šŸ“Š Found ${eventCount} event cards`); } // Verify we have events expect(eventCount).toBeGreaterThan(0); console.log(`āœ… Events displayed: ${eventCount} events found`); // Step 8: Verify event details show VIPs, drivers, vehicles console.log('\nšŸ” Verifying event details...'); if (tableRows > 0) { // Check first event row has data const firstRow = page.locator('tbody tr').first(); await expect(firstRow).toBeVisible(); // Try to find VIP names const vipCell = firstRow.locator('td').nth(1); // Usually second column const vipCellText = await vipCell.textContent(); console.log(`šŸ“‹ Sample VIP data: ${vipCellText?.substring(0, 50)}...`); // Try to find vehicle info const vehicleCell = firstRow.locator('td').nth(2); // Usually third column const vehicleCellText = await vehicleCell.textContent(); console.log(`šŸš— Sample Vehicle data: ${vehicleCellText?.substring(0, 50)}...`); // Try to find driver info const driverCell = firstRow.locator('td').nth(3); // Usually fourth column const driverCellText = await driverCell.textContent(); console.log(`šŸ‘¤ Sample Driver data: ${driverCellText?.substring(0, 50)}...`); // Verify cells have content (not empty) expect(vipCellText).not.toBe(''); expect(vehicleCellText).not.toBe(''); expect(driverCellText).not.toBe(''); console.log('āœ… Event details contain VIP, Vehicle, and Driver data'); } await page.screenshot({ path: 'test-results/admin-08-events-verified.png', fullPage: true }); // Step 9: Verify multi-VIP events display correctly console.log('\nšŸ‘„ Checking for multi-VIP events...'); // Look for comma-separated VIP names (indicates multi-VIP event) const multiVipRows = await page.locator('tbody tr').filter({ hasText: /,/ }).count(); console.log(`šŸ“Š Found ${multiVipRows} rows with comma-separated data (likely multi-VIP events)`); if (multiVipRows > 0) { const firstMultiVipRow = page.locator('tbody tr').filter({ hasText: /,/ }).first(); const vipCell = firstMultiVipRow.locator('td').nth(1); const vipNames = await vipCell.textContent(); console.log(`šŸ‘„ Sample multi-VIP event: ${vipNames?.substring(0, 100)}...`); console.log('āœ… Multi-VIP events displaying correctly'); } else { console.log('ā„¹ļø No obvious multi-VIP events detected (may be using badges/pills instead of commas)'); } console.log('\nšŸŽ‰ Test Data Load and Verification Complete!'); console.log(`āœ… ${eventCount} events verified in Events view`); }); test('should show error handling for database operations', async ({ page }) => { console.log('\nāš ļø Testing error handling (optional validation)'); await page.goto('http://localhost:5173/admin-tools'); await page.waitForLoadState('networkidle'); // Try clicking Clear All Data button if it exists const clearButton = page.locator('button:has-text("Clear All Data"), button:has-text("Delete All")'); if (await clearButton.isVisible({ timeout: 2000 })) { console.log('šŸ—‘ļø Found Clear All Data button'); // Setup dialog handler for confirmation page.on('dialog', async dialog => { console.log(`šŸ“¢ Confirmation dialog: ${dialog.message()}`); await dialog.accept(); }); await page.screenshot({ path: 'test-results/admin-09-before-clear.png', fullPage: true }); await clearButton.click(); await page.waitForTimeout(3000); await page.screenshot({ path: 'test-results/admin-10-after-clear.png', fullPage: true }); console.log('āœ… Clear operation completed'); // Verify data is cleared by checking Events page await page.goto('http://localhost:5173/events'); await page.waitForLoadState('networkidle'); const eventRows = await page.locator('tbody tr').count(); console.log(`šŸ“Š Event count after clear: ${eventRows}`); if (eventRows === 0) { console.log('āœ… All events cleared successfully'); } else { console.log(`ā„¹ļø ${eventRows} events still present (may be seed data)`); } } else { console.log('ā„¹ļø No Clear All Data button found - skipping clear test'); } }); });