import path from 'path'; import { test, expect } from '@playwright/test'; import type { Page } from '@playwright/test'; const DEMO_ACCOUNTS = { admin: { email: 'admin@example.com', password: 'demo123' }, }; async function takeScreenshot(page: Page, name: string) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const fileName = `components_${name}_${timestamp}.png`; await page.screenshot({ path: path.join('screenshots', fileName), fullPage: true }); return fileName; } async function loginAsAdmin(page: Page) { await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); } test.describe('UI Components', () => { test.beforeEach(async ({ page }) => { // Clear auth storage await page.evaluate(() => { localStorage.removeItem('bct_auth_user'); localStorage.removeItem('bct_auth_remember'); }); }); test('should display button variants correctly', async ({ page }) => { await page.goto('/login'); // Primary button (login button) const loginButton = page.locator('[data-testid="login-button"]'); await expect(loginButton).toBeVisible(); await expect(loginButton).toHaveClass(/bg-blue|bg-primary/); await takeScreenshot(page, 'button-primary-state'); // Test button hover state await loginButton.hover(); await takeScreenshot(page, 'button-primary-hover'); // Test button disabled state await page.fill('[data-testid="email-input"]', 'test@example.com'); await page.fill('[data-testid="password-input"]', 'test123'); await loginButton.click(); // Button should be disabled during loading await expect(loginButton).toBeDisabled(); await takeScreenshot(page, 'button-primary-disabled'); }); test('should display form inputs correctly', async ({ page }) => { await page.goto('/login'); // Email input const emailInput = page.locator('[data-testid="email-input"]'); await expect(emailInput).toBeVisible(); await expect(emailInput).toHaveAttribute('type', 'email'); // Password input const passwordInput = page.locator('[data-testid="password-input"]'); await expect(passwordInput).toBeVisible(); await expect(passwordInput).toHaveAttribute('type', 'password'); await takeScreenshot(page, 'form-inputs-empty'); // Test input focus states await emailInput.focus(); await takeScreenshot(page, 'email-input-focused'); await passwordInput.focus(); await takeScreenshot(page, 'password-input-focused'); // Test input filled states await emailInput.fill('user@example.com'); await passwordInput.fill('password123'); await takeScreenshot(page, 'form-inputs-filled'); // Test input validation states await emailInput.fill('invalid-email'); await passwordInput.click(); // Trigger validation await takeScreenshot(page, 'form-inputs-validation-error'); }); test('should display cards correctly', async ({ page }) => { await loginAsAdmin(page); // Navigate to events to see cards await page.click('[data-testid="nav-events"]'); await expect(page).toHaveURL('/events'); // Check if event cards are displayed const cards = page.locator('[data-testid^="event-card"]'); const cardCount = await cards.count(); if (cardCount > 0) { await expect(cards.first()).toBeVisible(); // Test card hover effects await cards.first().hover(); await takeScreenshot(page, 'card-hover-effect'); // Test card content await expect(cards.first().locator('.card-title, h2, h3')).toBeVisible(); } else { // If no cards, take screenshot of empty state await takeScreenshot(page, 'cards-empty-state'); } await takeScreenshot(page, 'cards-overview'); }); test('should display badges correctly', async ({ page }) => { await loginAsAdmin(page); // Look for badges in the dashboard or events page await page.click('[data-testid="nav-events"]'); // Check for status badges const badges = page.locator('[data-testid^="badge"], .badge, [class*="badge"]'); const badgeCount = await badges.count(); if (badgeCount > 0) { await expect(badges.first()).toBeVisible(); await takeScreenshot(page, 'badges-display'); } // Navigate to dashboard to check for other badges await page.click('[data-testid="nav-dashboard"]'); await takeScreenshot(page, 'dashboard-badges'); }); test('should display alerts correctly', async ({ page }) => { await page.goto('/login'); // Trigger error alert by submitting invalid form await page.fill('[data-testid="email-input"]', 'invalid@example.com'); await page.fill('[data-testid="password-input"]', 'wrong'); await page.click('[data-testid="login-button"]'); // Error alert should appear const errorAlert = page.locator('[data-testid="error-message"], .alert-error, [role="alert"]'); await expect(errorAlert).toBeVisible(); await takeScreenshot(page, 'alert-error-state'); // Check alert styling await expect(errorAlert).toHaveClass(/error|red|danger/); }); test('should display modals correctly', async ({ page }) => { await loginAsAdmin(page); // Look for modal triggers const modalTriggers = page.locator('[data-testid*="modal"], [data-modal], [aria-haspopup="dialog"]'); const triggerCount = await modalTriggers.count(); if (triggerCount > 0) { // Click first modal trigger await modalTriggers.first().click(); // Modal should appear const modal = page.locator('[role="dialog"], .modal, [data-testid*="modal-content"]'); await expect(modal).toBeVisible(); await takeScreenshot(page, 'modal-open'); // Modal should have overlay const overlay = page.locator('.modal-overlay, [data-testid="modal-overlay"]'); if (await overlay.isVisible()) { await takeScreenshot(page, 'modal-with-overlay'); } // Close modal const closeButton = page.locator('[data-testid="modal-close"], .modal-close, [aria-label="Close"]'); if (await closeButton.isVisible()) { await closeButton.click(); await expect(modal).not.toBeVisible(); } } await takeScreenshot(page, 'modal-test-complete'); }); test('should display dropdown menus correctly', async ({ page }) => { await loginAsAdmin(page); // Test user menu dropdown await page.click('[data-testid="user-menu"]'); const dropdown = page.locator('[data-testid="user-dropdown"]'); await expect(dropdown).toBeVisible(); await takeScreenshot(page, 'dropdown-user-menu'); // Test dropdown items await expect(dropdown.locator('[data-testid="profile-link"]')).toBeVisible(); await expect(dropdown.locator('[data-testid="settings-link"]')).toBeVisible(); await expect(dropdown.locator('[data-testid="logout-button"]')).toBeVisible(); // Test dropdown hover effects await dropdown.locator('[data-testid="profile-link"]').hover(); await takeScreenshot(page, 'dropdown-item-hover'); // Close dropdown by clicking outside await page.click('body'); await expect(dropdown).not.toBeVisible(); }); test('should display loading states correctly', async ({ page }) => { await page.goto('/login'); // Fill form and submit to trigger loading state await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); // Click login and quickly capture loading state await page.click('[data-testid="login-button"]'); // Button should show loading state const loadingButton = page.locator('[data-testid="login-button"]'); await expect(loadingButton).toBeDisabled(); // Check for loading spinner or text const loadingIndicator = page.locator('[data-testid="loading-spinner"], .spinner, .loading'); if (await loadingIndicator.isVisible()) { await takeScreenshot(page, 'loading-spinner'); } await takeScreenshot(page, 'button-loading-state'); // Wait for login to complete await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); }); test('should display skeleton loaders correctly', async ({ page }) => { await loginAsAdmin(page); // Navigate to a page that might show skeleton loaders await page.click('[data-testid="nav-events"]'); // Look for skeleton components const skeletons = page.locator('[data-testid="skeleton"], .skeleton, [class*="skeleton"]'); const skeletonCount = await skeletons.count(); if (skeletonCount > 0) { await takeScreenshot(page, 'skeleton-loaders'); } // Check for loading states in general const loadingElements = page.locator('[data-testid*="loading"], .loading, [aria-label*="loading"]'); const loadingCount = await loadingElements.count(); if (loadingCount > 0) { await takeScreenshot(page, 'loading-elements'); } }); test('should handle component interactions', async ({ page }) => { await loginAsAdmin(page); // Test checkbox interactions (if any) const checkboxes = page.locator('input[type="checkbox"]'); const checkboxCount = await checkboxes.count(); if (checkboxCount > 0) { const firstCheckbox = checkboxes.first(); // Test unchecked state await expect(firstCheckbox).not.toBeChecked(); await takeScreenshot(page, 'checkbox-unchecked'); // Test checked state await firstCheckbox.check(); await expect(firstCheckbox).toBeChecked(); await takeScreenshot(page, 'checkbox-checked'); } // Test radio button interactions (if any) const radioButtons = page.locator('input[type="radio"]'); const radioCount = await radioButtons.count(); if (radioCount > 0) { await radioButtons.first().check(); await takeScreenshot(page, 'radio-button-selected'); } // Test select dropdown interactions (if any) const selects = page.locator('select, [data-testid*="select"]'); const selectCount = await selects.count(); if (selectCount > 0) { const firstSelect = selects.first(); await firstSelect.click(); await takeScreenshot(page, 'select-dropdown-open'); // Select first option const options = firstSelect.locator('option'); if (await options.count() > 1) { await options.nth(1).click(); await takeScreenshot(page, 'select-option-selected'); } } }); test('should display tooltips correctly', async ({ page }) => { await loginAsAdmin(page); // Look for elements with tooltips const tooltipTriggers = page.locator('[title], [data-tooltip], [aria-describedby]'); const triggerCount = await tooltipTriggers.count(); if (triggerCount > 0) { // Hover over first element with tooltip await tooltipTriggers.first().hover(); // Look for tooltip content const tooltips = page.locator('[role="tooltip"], .tooltip, [data-testid="tooltip"]'); const tooltipCount = await tooltips.count(); if (tooltipCount > 0) { await expect(tooltips.first()).toBeVisible(); await takeScreenshot(page, 'tooltip-display'); } } }); test('should handle keyboard navigation in components', async ({ page }) => { await page.goto('/login'); // Test tab navigation through form await page.keyboard.press('Tab'); // Skip to content link await page.keyboard.press('Tab'); // Email input await expect(page.locator('[data-testid="email-input"]')).toBeFocused(); await page.keyboard.press('Tab'); // Password input await expect(page.locator('[data-testid="password-input"]')).toBeFocused(); await page.keyboard.press('Tab'); // Remember me checkbox const rememberMeCheckbox = page.locator('[data-testid="remember-me"]'); if (await rememberMeCheckbox.isVisible()) { await expect(rememberMeCheckbox).toBeFocused(); await page.keyboard.press('Tab'); // Login button } await expect(page.locator('[data-testid="login-button"]')).toBeFocused(); await takeScreenshot(page, 'keyboard-navigation-login-button'); // Test Enter key submission await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await page.keyboard.press('Enter'); // Should submit the form await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); }); });