const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); async function runQATests() { const browser = await chromium.launch({ headless: false }); const context = await browser.newContext({ viewport: { width: 1280, height: 720 } }); const page = await context.newPage(); // Monitor console errors const consoleErrors = []; page.on('console', msg => { if (msg.type() === 'error') { consoleErrors.push({ timestamp: new Date().toISOString(), message: msg.text(), url: page.url() }); } }); const results = { themeTests: {}, interactiveTests: {}, mobileTests: {}, consoleErrors: [] }; try { console.log('šŸš€ Starting QA Tests - Theme Functionality and Interactive Components'); // Navigate to login page console.log('\nšŸ“‹ Step 1: Logging in...'); await page.goto('http://localhost:3001/login'); await page.waitForLoadState('networkidle'); // Take screenshot of login page await page.screenshot({ path: 'login-page-qa.png', fullPage: true }); // Login await page.fill('input[type="email"]', 'tmartinez@gmail.com'); await page.fill('input[type="password"]', 'Skittles@420'); await page.click('button[type="submit"]'); // Wait for dashboard await page.waitForURL('**/dashboard', { timeout: 10000 }); await page.waitForLoadState('networkidle'); console.log('āœ… Successfully logged in'); // THEME TESTING console.log('\nšŸŽØ Step 2: Testing Theme Functionality...'); results.themeTests.startingTheme = 'Testing for theme toggle elements'; // Look for theme toggle elements const themeToggleSelectors = [ '[data-theme-toggle]', '.theme-toggle', '.dark-mode-toggle', 'button[aria-label*="theme"]', 'button[aria-label*="dark"]', 'button[aria-label*="light"]', '[role="switch"]' ]; let themeToggleFound = false; let themeToggleElement = null; for (const selector of themeToggleSelectors) { try { const element = await page.$(selector); if (element) { themeToggleFound = true; themeToggleElement = element; results.themeTests.toggleSelector = selector; console.log(`āœ… Found theme toggle: ${selector}`); break; } } catch (e) { // Continue checking other selectors } } if (!themeToggleFound) { // Check navigation area for any button that might be a theme toggle const navButtons = await page.$$('nav button, header button'); console.log(`šŸ” Checking ${navButtons.length} navigation buttons for theme toggle...`); for (let i = 0; i < navButtons.length; i++) { const button = navButtons[i]; const text = await button.textContent(); const ariaLabel = await button.getAttribute('aria-label'); console.log(`Button ${i}: text="${text}", aria-label="${ariaLabel}"`); if (text && (text.toLowerCase().includes('theme') || text.toLowerCase().includes('dark') || text.toLowerCase().includes('light'))) { themeToggleFound = true; themeToggleElement = button; results.themeTests.toggleSelector = `nav button:nth-child(${i+1})`; break; } if (ariaLabel && (ariaLabel.toLowerCase().includes('theme') || ariaLabel.toLowerCase().includes('dark') || ariaLabel.toLowerCase().includes('light'))) { themeToggleFound = true; themeToggleElement = button; results.themeTests.toggleSelector = `button[aria-label="${ariaLabel}"]`; break; } } } if (themeToggleFound && themeToggleElement) { console.log('šŸŽØ Testing theme toggle functionality...'); // Take screenshot before toggle await page.screenshot({ path: 'theme-before-toggle.png', fullPage: true }); results.themeTests.beforeToggleScreenshot = 'theme-before-toggle.png'; // Get initial theme state const initialTheme = await page.evaluate(() => { return { documentClass: document.documentElement.className, bodyClass: document.body.className, localStorage: localStorage.getItem('theme') || localStorage.getItem('dark-mode') || localStorage.getItem('color-theme'), dataTheme: document.documentElement.getAttribute('data-theme') }; }); results.themeTests.initialState = initialTheme; // Click theme toggle await themeToggleElement.click(); await page.waitForTimeout(500); // Wait for theme transition // Get state after toggle const afterToggleTheme = await page.evaluate(() => { return { documentClass: document.documentElement.className, bodyClass: document.body.className, localStorage: localStorage.getItem('theme') || localStorage.getItem('dark-mode') || localStorage.getItem('color-theme'), dataTheme: document.documentElement.getAttribute('data-theme') }; }); results.themeTests.afterToggleState = afterToggleTheme; // Take screenshot after toggle await page.screenshot({ path: 'theme-after-toggle.png', fullPage: true }); results.themeTests.afterToggleScreenshot = 'theme-after-toggle.png'; // Test persistence - reload page await page.reload(); await page.waitForLoadState('networkidle'); const afterReloadTheme = await page.evaluate(() => { return { documentClass: document.documentElement.className, bodyClass: document.body.className, localStorage: localStorage.getItem('theme') || localStorage.getItem('dark-mode') || localStorage.getItem('color-theme'), dataTheme: document.documentElement.getAttribute('data-theme') }; }); results.themeTests.afterReloadState = afterReloadTheme; results.themeTests.persistenceWorks = JSON.stringify(afterToggleTheme) === JSON.stringify(afterReloadTheme); console.log(`āœ… Theme toggle found and tested. Persistence: ${results.themeTests.persistenceWorks ? 'āœ…' : 'āŒ'}`); } else { console.log('āŒ No theme toggle found'); results.themeTests.status = 'No theme toggle functionality found'; } // INTERACTIVE COMPONENTS TESTING console.log('\nšŸ–±ļø Step 3: Testing Interactive Components...'); // Test navigation menu console.log('Testing navigation menu...'); const navLinks = await page.$$('nav a, header a'); results.interactiveTests.navigationLinks = navLinks.length; console.log(`Found ${navLinks.length} navigation links`); // Test event creation form console.log('Testing event creation form...'); try { await page.goto('http://localhost:3001/events/new'); await page.waitForLoadState('networkidle'); // Take screenshot of form await page.screenshot({ path: 'event-creation-form.png', fullPage: true }); // Test form fields const formFields = await page.$$('input, textarea, select'); results.interactiveTests.eventFormFields = formFields.length; console.log(`Found ${formFields.length} form fields`); // Test form validation - submit empty form console.log('Testing form validation...'); const submitButton = await page.$('button[type="submit"], input[type="submit"]'); if (submitButton) { await submitButton.click(); await page.waitForTimeout(1000); // Check for validation messages const validationMessages = await page.$$('.error, .invalid, [role="alert"], .text-red-500, .text-red-600'); results.interactiveTests.validationMessages = validationMessages.length; console.log(`Found ${validationMessages.length} validation messages`); // Take screenshot with validation await page.screenshot({ path: 'form-validation-test.png', fullPage: true }); } } catch (e) { console.log('āŒ Error testing event creation form:', e.message); results.interactiveTests.eventFormError = e.message; } // Test dashboard interactive elements console.log('Testing dashboard interactions...'); await page.goto('http://localhost:3001/dashboard'); await page.waitForLoadState('networkidle'); // Look for buttons, links, and interactive elements const buttons = await page.$$('button'); const links = await page.$$('a'); const inputs = await page.$$('input, select, textarea'); results.interactiveTests.dashboardButtons = buttons.length; results.interactiveTests.dashboardLinks = links.length; results.interactiveTests.dashboardInputs = inputs.length; console.log(`Dashboard: ${buttons.length} buttons, ${links.length} links, ${inputs.length} inputs`); // Look for modals or dropdowns console.log('Looking for modals and dropdowns...'); const modalTriggers = await page.$$('[data-modal], [data-toggle="modal"], .modal-trigger'); const dropdownTriggers = await page.$$('[data-dropdown], .dropdown-toggle, [aria-haspopup]'); results.interactiveTests.modalTriggers = modalTriggers.length; results.interactiveTests.dropdownTriggers = dropdownTriggers.length; // Test any dropdown that exists if (dropdownTriggers.length > 0) { console.log('Testing dropdown functionality...'); try { await dropdownTriggers[0].click(); await page.waitForTimeout(500); const dropdownMenu = await page.$('.dropdown-menu, [role="menu"], .dropdown-content'); results.interactiveTests.dropdownWorks = !!dropdownMenu; if (dropdownMenu) { await page.screenshot({ path: 'dropdown-open.png', fullPage: true }); } } catch (e) { results.interactiveTests.dropdownError = e.message; } } // MOBILE RESPONSIVENESS TESTING console.log('\nšŸ“± Step 4: Testing Mobile Responsiveness...'); // Switch to mobile viewport await page.setViewportSize({ width: 375, height: 667 }); await page.reload(); await page.waitForLoadState('networkidle'); // Test mobile navigation await page.screenshot({ path: 'mobile-dashboard.png', fullPage: true }); // Look for mobile menu toggle const mobileMenuToggle = await page.$('.mobile-menu-toggle, .hamburger, [aria-label*="menu"]'); if (mobileMenuToggle) { console.log('Testing mobile menu...'); await mobileMenuToggle.click(); await page.waitForTimeout(500); await page.screenshot({ path: 'mobile-menu-open.png', fullPage: true }); results.mobileTests.mobileMenuWorks = true; } else { results.mobileTests.mobileMenuWorks = false; } // Test mobile form await page.goto('http://localhost:3001/events/new'); await page.waitForLoadState('networkidle'); await page.screenshot({ path: 'mobile-form.png', fullPage: true }); // Check for horizontal scroll const hasHorizontalScroll = await page.evaluate(() => { return document.body.scrollWidth > window.innerWidth; }); results.mobileTests.hasHorizontalScroll = hasHorizontalScroll; console.log(`Mobile menu: ${results.mobileTests.mobileMenuWorks ? 'āœ…' : 'āŒ'}`); console.log(`Horizontal scroll: ${hasHorizontalScroll ? 'āŒ' : 'āœ…'}`); } catch (error) { console.error('āŒ Test execution error:', error); results.error = error.message; } finally { // Collect final console errors results.consoleErrors = consoleErrors; // Write results to file fs.writeFileSync('qa-test-results.json', JSON.stringify(results, null, 2)); console.log('\nšŸ“Š QA Test Summary:'); console.log('Theme Tests:', Object.keys(results.themeTests).length, 'checks'); console.log('Interactive Tests:', Object.keys(results.interactiveTests).length, 'checks'); console.log('Mobile Tests:', Object.keys(results.mobileTests).length, 'checks'); console.log('Console Errors:', consoleErrors.length); if (consoleErrors.length > 0) { console.log('\nāŒ Console Errors Found:'); consoleErrors.forEach((error, i) => { console.log(`${i+1}. ${error.message} (${error.url})`); }); } console.log('\nšŸ“„ Results saved to qa-test-results.json'); console.log('šŸ–¼ļø Screenshots saved with descriptive names'); await browser.close(); } } // Run the tests runQATests().catch(console.error);