import { test, expect } from '@playwright/test'; import { loginAsUser, TEST_CONFIG } from './utils/test-helpers'; /** * Visual Regression Tests * * These tests capture screenshots of UI components and pages * to detect visual regressions. Screenshots are stored in: * - test-results/visual-regression.spec.ts-snapshots/ * * To update screenshots after intentional changes: * - Run: npx playwright test --update-snapshots * * To run only visual tests: * - Run: npx playwright test visual-regression */ test.describe('Visual Regression Tests', () => { // Use authenticated state for most tests test.use({ storageState: 'e2e/.auth/user.json' }); test.describe('Authentication Pages', () => { test('login page visual snapshot', async ({ page }) => { // Use unauthenticated state for login page await page.context().clearCookies(); await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`); await page.waitForLoadState('networkidle'); // Wait for form to be fully rendered await page.waitForSelector('form', { timeout: 5000 }); await page.waitForTimeout(500); // Allow animations to settle await expect(page).toHaveScreenshot('login-page.png', { fullPage: true, maxDiffPixels: 100, // Allow small differences (fonts, anti-aliasing) }); }); test('register page visual snapshot', async ({ page }) => { // Use unauthenticated state for register page await page.context().clearCookies(); await page.goto(`${TEST_CONFIG.FRONTEND_URL}/register`); await page.waitForLoadState('networkidle'); // Wait for form to be fully rendered await page.waitForSelector('form', { timeout: 5000 }); await page.waitForTimeout(500); await expect(page).toHaveScreenshot('register-page.png', { fullPage: true, maxDiffPixels: 100, }); }); }); test.describe('Dashboard Pages', () => { test('dashboard page visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`); await page.waitForLoadState('networkidle'); // Wait for main content to load await page.waitForSelector('main, [role="main"]', { timeout: 10000 }); await page.waitForTimeout(1000); // Allow data to load await expect(page).toHaveScreenshot('dashboard-page.png', { fullPage: true, maxDiffPixels: 200, }); }); test('dashboard header visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`); await page.waitForLoadState('networkidle'); // Wait for header const header = page.locator('header').first(); await header.waitFor({ timeout: 5000 }); await page.waitForTimeout(500); await expect(header).toHaveScreenshot('dashboard-header.png', { maxDiffPixels: 50, }); }); test('dashboard sidebar visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`); await page.waitForLoadState('networkidle'); // Wait for sidebar const sidebar = page.locator('aside').first(); await sidebar.waitFor({ timeout: 5000 }); await page.waitForTimeout(500); await expect(sidebar).toHaveScreenshot('dashboard-sidebar.png', { maxDiffPixels: 50, }); }); }); test.describe('Profile Page', () => { test('profile page visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/profile`); await page.waitForLoadState('networkidle'); // Wait for profile content await page.waitForSelector('main, [role="main"]', { timeout: 10000 }); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('profile-page.png', { fullPage: true, maxDiffPixels: 200, }); }); }); test.describe('Tracks Pages', () => { test('tracks list page visual snapshot', async ({ page }) => { // Navigate to tracks page (adjust route as needed) await page.goto(`${TEST_CONFIG.FRONTEND_URL}/tracks`); await page.waitForLoadState('networkidle'); // Wait for tracks list to load await page.waitForTimeout(2000); // Allow tracks to load await expect(page).toHaveScreenshot('tracks-list-page.png', { fullPage: true, maxDiffPixels: 200, }); }); }); test.describe('Playlists Pages', () => { test('playlists page visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/playlists`); await page.waitForLoadState('networkidle'); // Wait for playlists to load await page.waitForTimeout(2000); await expect(page).toHaveScreenshot('playlists-page.png', { fullPage: true, maxDiffPixels: 200, }); }); }); test.describe('UI Components', () => { test('button variants visual snapshot', async ({ page }) => { // Create a test page with button variants await page.setContent(`
`); await page.waitForTimeout(500); await expect(page).toHaveScreenshot('button-variants.png', { maxDiffPixels: 50, }); }); test('card component visual snapshot', async ({ page }) => { await page.setContent(`

Card Title

This is a card component with some content.

`); await page.waitForTimeout(500); await expect(page).toHaveScreenshot('card-component.png', { maxDiffPixels: 50, }); }); test('form elements visual snapshot', async ({ page }) => { await page.setContent(`
`); await page.waitForTimeout(500); await expect(page).toHaveScreenshot('form-elements.png', { maxDiffPixels: 50, }); }); }); test.describe('Error States', () => { test('404 page visual snapshot', async ({ page }) => { await page.goto(`${TEST_CONFIG.FRONTEND_URL}/non-existent-page`); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('404-page.png', { fullPage: true, maxDiffPixels: 100, }); }); }); test.describe('Responsive Design', () => { test('mobile viewport dashboard snapshot', async ({ page }) => { // Set mobile viewport await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('dashboard-mobile.png', { fullPage: true, maxDiffPixels: 200, }); }); test('tablet viewport dashboard snapshot', async ({ page }) => { // Set tablet viewport await page.setViewportSize({ width: 768, height: 1024 }); await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); await expect(page).toHaveScreenshot('dashboard-tablet.png', { fullPage: true, maxDiffPixels: 200, }); }); }); });