Major fixes and improvements: - Fixed edit event button functionality with proper event handlers and DOM ready state checking - Added status column to tickets table via Supabase migration to resolve 500 API errors - Updated stats API to correctly calculate revenue from decimal price values - Resolved authentication redirect loops by fixing cookie configuration for Docker environment - Fixed Permissions-Policy header syntax errors - Added comprehensive debugging and error handling for event management - Implemented modal-based event editing with form validation and API integration - Enhanced event data loading with proper error handling and user feedback 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
302 lines
13 KiB
JavaScript
302 lines
13 KiB
JavaScript
const { chromium } = require('playwright');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
async function runComprehensiveQAAudit() {
|
||
console.log('🔍 Starting Comprehensive QA Audit...');
|
||
|
||
const browser = await chromium.launch({
|
||
headless: false,
|
||
slowMo: 1000 // Slow down for visibility
|
||
});
|
||
|
||
const context = await browser.newContext({
|
||
viewport: { width: 1280, height: 720 },
|
||
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||
});
|
||
|
||
const page = await context.newPage();
|
||
|
||
// Track console errors
|
||
const consoleErrors = [];
|
||
page.on('console', msg => {
|
||
if (msg.type() === 'error') {
|
||
consoleErrors.push(`${new Date().toISOString()}: ${msg.text()}`);
|
||
}
|
||
});
|
||
|
||
// Track network failures
|
||
const networkErrors = [];
|
||
page.on('response', response => {
|
||
if (response.status() >= 400) {
|
||
networkErrors.push(`${response.status()}: ${response.url()}`);
|
||
}
|
||
});
|
||
|
||
try {
|
||
// Step 1: Login
|
||
console.log('📝 Step 1: Logging in...');
|
||
await page.goto('http://localhost:3001/login');
|
||
await page.waitForSelector('input[type="email"]', { timeout: 10000 });
|
||
|
||
await page.fill('input[type="email"]', 'tmartinez@gmail.com');
|
||
await page.fill('input[type="password"]', 'Skittles@420');
|
||
|
||
// Take login form screenshot
|
||
await page.screenshot({ path: 'login-form-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: login-form-qa.png');
|
||
|
||
await page.click('button[type="submit"]');
|
||
await page.waitForNavigation({ timeout: 15000 });
|
||
|
||
console.log(`✅ Login successful - Current URL: ${page.url()}`);
|
||
|
||
// Step 2: Test Dashboard
|
||
console.log('\n📊 Step 2: Testing Dashboard...');
|
||
await page.goto('http://localhost:3001/dashboard');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000); // Let content load
|
||
|
||
await page.screenshot({ path: 'dashboard-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: dashboard-qa.png');
|
||
|
||
// Test dashboard interactions
|
||
try {
|
||
// Look for "Create Event" or "New Event" button
|
||
const createEventBtn = await page.locator('a[href*="events/new"], button:has-text("Create Event"), a:has-text("New Event")').first();
|
||
if (await createEventBtn.count() > 0) {
|
||
console.log('✅ Create Event button found');
|
||
}
|
||
|
||
// Check for event cards or tables
|
||
const eventElements = await page.locator('[data-testid*="event"], .event-card, table tr').count();
|
||
console.log(`📋 Found ${eventElements} event-related elements`);
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ Dashboard interaction test failed:', error.message);
|
||
}
|
||
|
||
// Step 3: Test Events New Page
|
||
console.log('\n🎫 Step 3: Testing Event Creation...');
|
||
await page.goto('http://localhost:3001/events/new');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'events-new-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: events-new-qa.png');
|
||
|
||
// Test form interactions
|
||
try {
|
||
const eventNameInput = await page.locator('input[name="name"], input[name="title"], input[placeholder*="event"], input[placeholder*="name"]').first();
|
||
if (await eventNameInput.count() > 0) {
|
||
await eventNameInput.fill('QA Test Event');
|
||
console.log('✅ Event name field working');
|
||
}
|
||
|
||
// Look for form submit button
|
||
const submitBtn = await page.locator('button[type="submit"], button:has-text("Create"), button:has-text("Save")').first();
|
||
if (await submitBtn.count() > 0) {
|
||
console.log('✅ Form submit button found');
|
||
}
|
||
} catch (error) {
|
||
console.log('⚠️ Event creation form test failed:', error.message);
|
||
}
|
||
|
||
// Step 4: Test QR Scan Page
|
||
console.log('\n📱 Step 4: Testing QR Scanner...');
|
||
await page.goto('http://localhost:3001/scan');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'scan-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: scan-qa.png');
|
||
|
||
// Test scanner interactions
|
||
try {
|
||
// Look for camera permission or scanner elements
|
||
const scannerElements = await page.locator('[data-testid*="scanner"], video, canvas, .scanner').count();
|
||
console.log(`📷 Found ${scannerElements} scanner-related elements`);
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ Scanner test failed:', error.message);
|
||
}
|
||
|
||
// Step 5: Test Templates Page
|
||
console.log('\n📋 Step 5: Testing Templates...');
|
||
await page.goto('http://localhost:3001/templates');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'templates-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: templates-qa.png');
|
||
|
||
// Step 6: Test Admin Dashboard
|
||
console.log('\n🔧 Step 6: Testing Admin Dashboard...');
|
||
await page.goto('http://localhost:3001/admin/dashboard');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'admin-dashboard-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: admin-dashboard-qa.png');
|
||
|
||
// Step 7: Test Calendar Page
|
||
console.log('\n📅 Step 7: Testing Calendar...');
|
||
await page.goto('http://localhost:3001/calendar');
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'calendar-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: calendar-qa.png');
|
||
|
||
// Test calendar interactions
|
||
try {
|
||
// Look for calendar navigation
|
||
const calendarNav = await page.locator('button:has-text("Today"), button:has-text("Next"), button:has-text("Previous"), .calendar-nav').count();
|
||
console.log(`📅 Found ${calendarNav} calendar navigation elements`);
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ Calendar interaction test failed:', error.message);
|
||
}
|
||
|
||
// Step 8: Test Event Management (need an event ID)
|
||
console.log('\n⚙️ Step 8: Testing Event Management...');
|
||
|
||
// First, try to get an event ID from the dashboard
|
||
await page.goto('http://localhost:3001/dashboard');
|
||
await page.waitForTimeout(2000);
|
||
|
||
let eventId = null;
|
||
try {
|
||
// Look for event links that might contain IDs
|
||
const eventLinks = await page.locator('a[href*="/events/"][href*="/manage"], a[href*="/events/"][href$="/manage"]').all();
|
||
|
||
if (eventLinks.length > 0) {
|
||
const href = await eventLinks[0].getAttribute('href');
|
||
const match = href.match(/\/events\/([^\/]+)\/manage/);
|
||
if (match) {
|
||
eventId = match[1];
|
||
console.log(`✅ Found event ID: ${eventId}`);
|
||
}
|
||
}
|
||
|
||
// If no existing event, check if we can create one quickly
|
||
if (!eventId) {
|
||
console.log('📝 No existing events found, will use test ID');
|
||
eventId = 'test-event-id'; // Use a test ID to see the error page
|
||
}
|
||
|
||
// Test the event management page
|
||
await page.goto(`http://localhost:3001/events/${eventId}/manage`);
|
||
await page.waitForSelector('body', { timeout: 10000 });
|
||
await page.waitForTimeout(2000);
|
||
|
||
await page.screenshot({ path: 'event-manage-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: event-manage-qa.png');
|
||
|
||
// Test management tabs if present
|
||
const tabs = await page.locator('[role="tab"], .tab, button:has-text("Tickets"), button:has-text("Venue"), button:has-text("Analytics")').count();
|
||
console.log(`📑 Found ${tabs} management tab elements`);
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ Event management test failed:', error.message);
|
||
}
|
||
|
||
// Step 9: Test Mobile Responsiveness
|
||
console.log('\n📱 Step 9: Testing Mobile Responsiveness...');
|
||
await page.setViewportSize({ width: 375, height: 667 }); // iPhone size
|
||
|
||
await page.goto('http://localhost:3001/dashboard');
|
||
await page.waitForTimeout(2000);
|
||
await page.screenshot({ path: 'dashboard-mobile-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: dashboard-mobile-qa.png');
|
||
|
||
await page.goto('http://localhost:3001/scan');
|
||
await page.waitForTimeout(2000);
|
||
await page.screenshot({ path: 'scan-mobile-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: scan-mobile-qa.png');
|
||
|
||
// Step 10: Test Navigation
|
||
console.log('\n🧭 Step 10: Testing Navigation...');
|
||
await page.setViewportSize({ width: 1280, height: 720 }); // Back to desktop
|
||
|
||
await page.goto('http://localhost:3001/dashboard');
|
||
await page.waitForTimeout(2000);
|
||
|
||
// Test navigation menu
|
||
try {
|
||
const navItems = await page.locator('nav a, .nav-item, [role="navigation"] a').count();
|
||
console.log(`🧭 Found ${navItems} navigation items`);
|
||
|
||
// Test menu toggle if present
|
||
const menuToggle = await page.locator('button[aria-label*="menu"], .menu-toggle, .hamburger').first();
|
||
if (await menuToggle.count() > 0) {
|
||
await menuToggle.click();
|
||
await page.waitForTimeout(1000);
|
||
await page.screenshot({ path: 'navigation-open-qa.png', fullPage: true });
|
||
console.log('📸 Screenshot: navigation-open-qa.png');
|
||
}
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ Navigation test failed:', error.message);
|
||
}
|
||
|
||
// Final Report
|
||
console.log('\n📊 QA AUDIT RESULTS:');
|
||
console.log('=====================');
|
||
console.log(`✅ Total screenshots taken: 10+`);
|
||
console.log(`❌ Console errors: ${consoleErrors.length}`);
|
||
console.log(`🌐 Network errors: ${networkErrors.length}`);
|
||
|
||
if (consoleErrors.length > 0) {
|
||
console.log('\n🚨 CONSOLE ERRORS:');
|
||
consoleErrors.forEach(error => console.log(` - ${error}`));
|
||
}
|
||
|
||
if (networkErrors.length > 0) {
|
||
console.log('\n🌐 NETWORK ERRORS:');
|
||
networkErrors.forEach(error => console.log(` - ${error}`));
|
||
}
|
||
|
||
// Create summary report
|
||
const report = {
|
||
timestamp: new Date().toISOString(),
|
||
routes_tested: [
|
||
'/login',
|
||
'/dashboard',
|
||
'/events/new',
|
||
'/scan',
|
||
'/templates',
|
||
'/admin/dashboard',
|
||
'/calendar',
|
||
`/events/${eventId}/manage`
|
||
],
|
||
screenshots_taken: [
|
||
'login-form-qa.png',
|
||
'dashboard-qa.png',
|
||
'events-new-qa.png',
|
||
'scan-qa.png',
|
||
'templates-qa.png',
|
||
'admin-dashboard-qa.png',
|
||
'calendar-qa.png',
|
||
'event-manage-qa.png',
|
||
'dashboard-mobile-qa.png',
|
||
'scan-mobile-qa.png',
|
||
'navigation-open-qa.png'
|
||
],
|
||
console_errors: consoleErrors,
|
||
network_errors: networkErrors,
|
||
status: consoleErrors.length === 0 && networkErrors.length === 0 ? 'PASSED' : 'ISSUES_FOUND'
|
||
};
|
||
|
||
fs.writeFileSync('qa-audit-report.json', JSON.stringify(report, null, 2));
|
||
console.log('\n💾 Report saved to: qa-audit-report.json');
|
||
|
||
} catch (error) {
|
||
console.error('❌ QA Audit failed:', error);
|
||
} finally {
|
||
await browser.close();
|
||
console.log('\n🏁 QA Audit completed');
|
||
}
|
||
}
|
||
|
||
runComprehensiveQAAudit(); |