import { test, expect } from '@playwright/test'; /** * Performance Tests * Ensures pages load quickly and perform well */ test.describe('Performance Tests', () => { test('Home page loads within acceptable time', async ({ page }) => { const startTime = Date.now(); await page.goto('/', { waitUntil: 'domcontentloaded' }); await page.waitForLoadState('networkidle'); const loadTime = Date.now() - startTime; // Should load within 5 seconds expect(loadTime).toBeLessThan(5000); }); test('Projects page loads quickly', async ({ page }) => { const startTime = Date.now(); await page.goto('/projects', { waitUntil: 'domcontentloaded' }); await page.waitForLoadState('networkidle'); const loadTime = Date.now() - startTime; // Should load within 5 seconds expect(loadTime).toBeLessThan(5000); }); test('No large layout shifts', async ({ page }) => { await page.goto('/', { waitUntil: 'domcontentloaded' }); // Check for layout stability const layoutShift = await page.evaluate(() => { return new Promise((resolve) => { let maxShift = 0; const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.entryType === 'layout-shift') { const layoutShiftEntry = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number; }; if (!layoutShiftEntry.hadRecentInput && layoutShiftEntry.value !== undefined) { maxShift = Math.max(maxShift, layoutShiftEntry.value); } } } }); observer.observe({ entryTypes: ['layout-shift'] }); setTimeout(() => { observer.disconnect(); resolve(maxShift); }, 3000); }); }); // Layout shift should be minimal (CLS < 0.1 is good) expect(layoutShift as number).toBeLessThan(0.25); }); test('Images are optimized', async ({ page }) => { await page.goto('/', { waitUntil: 'domcontentloaded' }); // Check that Next.js Image component is used const images = page.locator('img'); const imageCount = await images.count(); if (imageCount > 0) { // Check that images have proper attributes const firstImage = images.first(); const src = await firstImage.getAttribute('src'); // Next.js images should have optimized src if (src) { // Should be using Next.js image optimization or have proper format expect(src.includes('_next') || src.includes('data:') || src.startsWith('/')).toBeTruthy(); } } }); test('API endpoints respond quickly', async ({ request }) => { const startTime = Date.now(); const response = await request.get('/api/health'); const responseTime = Date.now() - startTime; expect(response.ok()).toBeTruthy(); // API should respond within 1 second expect(responseTime).toBeLessThan(1000); }); });