import { test, expect } from '@playwright/test'; test.describe('Visual Regression Tests', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); // Wait for all content to load await page.waitForLoadState('networkidle'); }); test('homepage full page screenshot', async ({ page }) => { // Take full page screenshot await expect(page).toHaveScreenshot('homepage-full.png', { fullPage: true, animations: 'disabled' }); }); test('homepage viewport screenshot', async ({ page }) => { // Take viewport screenshot await expect(page).toHaveScreenshot('homepage-viewport.png', { animations: 'disabled' }); }); test('hero banner section screenshot', async ({ page }) => { // Scroll to hero section and take screenshot await page.locator('text=Collaborate').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); // Wait for animations const heroSection = page.locator('section').first(); await expect(heroSection).toHaveScreenshot('hero-banner.png', { animations: 'disabled' }); }); test('logo wall section screenshot', async ({ page }) => { // Scroll to logo wall section await page.locator('text=Trusted by leading cooperators').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const logoSection = page.locator('section').nth(1); await expect(logoSection).toHaveScreenshot('logo-wall.png', { animations: 'disabled' }); }); test('numbered cards section screenshot', async ({ page }) => { // Scroll to numbered cards section await page.locator('h2:has-text("How CommunityRule works")').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const cardsSection = page.locator('section').nth(2); await expect(cardsSection).toHaveScreenshot('numbered-cards.png', { animations: 'disabled' }); }); test('rule stack section screenshot', async ({ page }) => { // Scroll to rule stack section await page.locator('text=Consensus clusters').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const ruleSection = page.locator('section').nth(3); await expect(ruleSection).toHaveScreenshot('rule-stack.png', { animations: 'disabled' }); }); test('feature grid section screenshot', async ({ page }) => { // Scroll to feature grid section await page.locator('h2:has-text("We\'ve got your back")').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const featureSection = page.locator('section').nth(4); await expect(featureSection).toHaveScreenshot('feature-grid.png', { animations: 'disabled' }); }); test('quote block section screenshot', async ({ page }) => { // Scroll to quote block section await page.locator('text=Jo Freeman').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const quoteSection = page.locator('section').nth(5); await expect(quoteSection).toHaveScreenshot('quote-block.png', { animations: 'disabled' }); }); test('ask organizer section screenshot', async ({ page }) => { // Scroll to ask organizer section await page.locator('text=Still have questions?').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const askSection = page.locator('section').nth(6); await expect(askSection).toHaveScreenshot('ask-organizer.png', { animations: 'disabled' }); }); test('header component screenshot', async ({ page }) => { const header = page.locator('header'); await expect(header).toHaveScreenshot('header.png', { animations: 'disabled' }); }); test('footer component screenshot', async ({ page }) => { // Scroll to footer await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); await page.waitForTimeout(500); const footer = page.locator('footer'); await expect(footer).toHaveScreenshot('footer.png', { animations: 'disabled' }); }); test('mobile viewport screenshots', async ({ page }) => { // Test mobile viewport await page.setViewportSize({ width: 375, height: 667 }); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('homepage-mobile.png', { animations: 'disabled' }); // Test mobile hero section await page.locator('text=Collaborate').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const heroSection = page.locator('section').first(); await expect(heroSection).toHaveScreenshot('hero-banner-mobile.png', { animations: 'disabled' }); }); test('tablet viewport screenshots', async ({ page }) => { // Test tablet viewport await page.setViewportSize({ width: 768, height: 1024 }); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('homepage-tablet.png', { animations: 'disabled' }); // Test tablet hero section await page.locator('text=Collaborate').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const heroSection = page.locator('section').first(); await expect(heroSection).toHaveScreenshot('hero-banner-tablet.png', { animations: 'disabled' }); }); test('desktop viewport screenshots', async ({ page }) => { // Test desktop viewport await page.setViewportSize({ width: 1440, height: 900 }); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('homepage-desktop.png', { animations: 'disabled' }); // Test desktop hero section await page.locator('text=Collaborate').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const heroSection = page.locator('section').first(); await expect(heroSection).toHaveScreenshot('hero-banner-desktop.png', { animations: 'disabled' }); }); test('large desktop viewport screenshots', async ({ page }) => { // Test large desktop viewport await page.setViewportSize({ width: 1920, height: 1080 }); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('homepage-large-desktop.png', { animations: 'disabled' }); }); test('button hover states', async ({ page }) => { // Test button hover states const ctaButton = page.locator('button:has-text("Learn how CommunityRule works")'); // Normal state await expect(ctaButton).toHaveScreenshot('button-normal.png', { animations: 'disabled' }); // Hover state await ctaButton.hover(); await page.waitForTimeout(500); await expect(ctaButton).toHaveScreenshot('button-hover.png', { animations: 'disabled' }); }); test('rule card hover states', async ({ page }) => { // Scroll to rule stack section await page.locator('text=Consensus clusters').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const consensusCard = page.locator('[aria-label*="Consensus clusters"]'); // Normal state await expect(consensusCard).toHaveScreenshot('rule-card-normal.png', { animations: 'disabled' }); // Hover state await consensusCard.hover(); await page.waitForTimeout(500); await expect(consensusCard).toHaveScreenshot('rule-card-hover.png', { animations: 'disabled' }); }); test('feature card hover states', async ({ page }) => { // Scroll to feature grid section await page.locator('h2:has-text("We\'ve got your back")').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const featureCard = page.locator('a[href="#decision-making"]'); // Normal state await expect(featureCard).toHaveScreenshot('feature-card-normal.png', { animations: 'disabled' }); // Hover state await featureCard.hover(); await page.waitForTimeout(500); await expect(featureCard).toHaveScreenshot('feature-card-hover.png', { animations: 'disabled' }); }); test('logo hover states', async ({ page }) => { // Scroll to logo wall section await page.locator('text=Trusted by leading cooperators').scrollIntoViewIfNeeded(); await page.waitForTimeout(500); const logo = page.locator('img[alt="Food Not Bombs"]'); // Normal state await expect(logo).toHaveScreenshot('logo-normal.png', { animations: 'disabled' }); // Hover state await logo.hover(); await page.waitForTimeout(500); await expect(logo).toHaveScreenshot('logo-hover.png', { animations: 'disabled' }); }); test('focus states', async ({ page }) => { // Test focus states for interactive elements const ctaButton = page.locator('button:has-text("Learn how CommunityRule works")'); // Focus the button await ctaButton.focus(); await page.waitForTimeout(500); await expect(ctaButton).toHaveScreenshot('button-focus.png', { animations: 'disabled' }); }); test('loading states', async ({ page }) => { // Test loading states by blocking resources await page.route('**/*', route => { // Delay all requests to simulate loading setTimeout(() => route.continue(), 1000); }); // Reload page to trigger loading states await page.reload(); // Take screenshot during loading await expect(page).toHaveScreenshot('homepage-loading.png', { animations: 'disabled' }); }); test('error states', async ({ page }) => { // Test error states by blocking critical resources await page.route('**/*.css', route => { route.abort(); }); // Reload page to trigger error states await page.reload(); // Take screenshot of error state await expect(page).toHaveScreenshot('homepage-error.png', { animations: 'disabled' }); }); test('high contrast mode', async ({ page }) => { // Simulate high contrast mode await page.evaluate(() => { document.body.style.filter = 'contrast(200%)'; }); await expect(page).toHaveScreenshot('homepage-high-contrast.png', { animations: 'disabled' }); // Reset contrast await page.evaluate(() => { document.body.style.filter = 'none'; }); }); test('reduced motion mode', async ({ page }) => { // Simulate reduced motion preference await page.evaluate(() => { document.documentElement.style.setProperty('--prefers-reduced-motion', 'reduce'); }); await expect(page).toHaveScreenshot('homepage-reduced-motion.png', { animations: 'disabled' }); }); test('dark mode simulation', async ({ page }) => { // Simulate dark mode (if supported) await page.evaluate(() => { document.documentElement.classList.add('dark'); document.body.style.backgroundColor = '#000'; document.body.style.color = '#fff'; }); await expect(page).toHaveScreenshot('homepage-dark-mode.png', { animations: 'disabled' }); // Reset to light mode await page.evaluate(() => { document.documentElement.classList.remove('dark'); document.body.style.backgroundColor = ''; document.body.style.color = ''; }); }); });