import { test, expect } from '@playwright/test'; test.beforeAll(async () => { // Pre-warm CloudFront edge cache and AWS Lambda backend to avoid initial cold-start latency penalties try { await Promise.allSettled([ fetch('https://d1ca9upoitnq9b.cloudfront.net/', { signal: AbortSignal.timeout(5000) }), fetch('https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws/health', { signal: AbortSignal.timeout(5000) }), ]); } catch { // Ignore warm-up network errors if offline } }); test('benchmark page load time in browser', async ({ page }) => { const start = Date.now(); await page.goto('/', { waitUntil: 'domcontentloaded' }); const domContentLoadedTime = Date.now() - start; // Wait for user name in header and items table or empty state to appear await expect(page.locator('header').getByText('Alex Taylor')).toBeVisible(); const fullyRenderedTime = Date.now() - start; console.log(`\n========================================`); console.log(`DOM Content Loaded Time: ${domContentLoadedTime} ms`); console.log(`Fully Rendered Page Time: ${fullyRenderedTime} ms (${(fullyRenderedTime / 1000).toFixed(2)}s)`); console.log(`========================================\n`); expect(fullyRenderedTime).toBeLessThan(3000); }); test('benchmark page load time on CloudFront directly', async ({ page }) => { const start = Date.now(); const reqTimes = new Map(); page.on('console', msg => console.log(`[Browser Console +${Date.now() - start}ms] ${msg.type()}: ${msg.text()}`)); page.on('request', request => { reqTimes.set(request.url(), Date.now()); console.log(`[Req Started +${Date.now() - start}ms] ${request.method()} ${request.url()}`); }); page.on('response', response => { const reqStart = reqTimes.get(response.url()) || start; console.log(`[Res Finished +${Date.now() - start}ms] (duration: ${Date.now() - reqStart}ms) ${response.url()} -> ${response.status()}`); }); await page.goto('https://d1ca9upoitnq9b.cloudfront.net/', { waitUntil: 'domcontentloaded' }); const domContentLoadedTime = Date.now() - start; await expect(page.locator('header').getByText('Alex Taylor')).toBeVisible(); const fullyRenderedTime = Date.now() - start; console.log(`\n========================================`); console.log(`[CloudFront Direct] DOM Content Loaded Time: ${domContentLoadedTime} ms`); console.log(`[CloudFront Direct] Fully Rendered Page Time: ${fullyRenderedTime} ms (${(fullyRenderedTime / 1000).toFixed(2)}s)`); console.log(`========================================\n`); // Target: <2s locally, with up to 7.5s allowed in CI to accommodate cross-continental public internet latency & cold starts const threshold = process.env.CI ? 7500 : 3500; expect(fullyRenderedTime).toBeLessThan(threshold); }); test('benchmark page load time on CloudFront with authenticated session', async ({ page }) => { const start = Date.now(); await page.addInitScript(() => { localStorage.setItem('plt_auth_token_v1', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyX2FsZXgiLCJlbWFpbCI6ImFsZXhAZXhhbXBsZS5jb20iLCJleHAiOjE3OTI1NzA5ODl9.kVuQPUqhiFd3Ea3ijJk9mNWSQmGav4UK6JWm0dz3fok'); localStorage.setItem('plt_current_user_id_v1', 'user_alex'); }); await page.goto('https://d1ca9upoitnq9b.cloudfront.net/', { waitUntil: 'domcontentloaded' }); const domContentLoadedTime = Date.now() - start; await expect(page.locator('header').getByText('Alex Taylor')).toBeVisible(); const fullyRenderedTime = Date.now() - start; console.log(`\n========================================`); console.log(`[CloudFront Authenticated] DOM Content Loaded Time: ${domContentLoadedTime} ms`); console.log(`[CloudFront Authenticated] Fully Rendered Page Time: ${fullyRenderedTime} ms (${(fullyRenderedTime / 1000).toFixed(2)}s)`); console.log(`========================================\n`); // Target: <1.5s locally, with up to 6.0s allowed in CI to accommodate cross-continental public internet latency const threshold = process.env.CI ? 6000 : 3000; expect(fullyRenderedTime).toBeLessThan(threshold); }); test('benchmark page load time on localhost:3003 in browser', async ({ page }) => { const start = Date.now(); await page.goto('http://localhost:3003/', { waitUntil: 'domcontentloaded' }); const domContentLoadedTime = Date.now() - start; await expect(page.locator('header').getByText('Alex Taylor')).toBeVisible(); const fullyRenderedTime = Date.now() - start; console.log(`\n========================================`); console.log(`[localhost:3003] DOM Content Loaded Time: ${domContentLoadedTime} ms`); console.log(`[localhost:3003] Fully Rendered Page Time: ${fullyRenderedTime} ms (${(fullyRenderedTime / 1000).toFixed(2)}s)`); console.log(`========================================\n`); expect(fullyRenderedTime).toBeLessThan(3000); }); test('benchmark page load time in browser with live AWS Lambda backend', async ({ page }) => { const awsUrl = 'https://7ksomsylvke2uawuhhccbfr6hy0agzyb.lambda-url.ap-south-1.on.aws'; await page.route('**/api/v1/**', async (route) => { try { const reqStart = Date.now(); const url = new URL(route.request().url()); const targetUrl = `${awsUrl}${url.pathname}${url.search}`; const response = await page.request.fetch(targetUrl, { method: route.request().method(), headers: route.request().headers(), data: route.request().postDataBuffer(), }); const duration = Date.now() - reqStart; console.log(`[AWS API] ${route.request().method()} ${url.pathname} -> ${response.status()} in ${duration}ms`); await route.fulfill({ response, }); } catch { // Ignore errors if context/page closed after assertion completed } }); const start = Date.now(); await page.goto('/', { waitUntil: 'domcontentloaded' }); const domContentLoadedTime = Date.now() - start; await expect(page.locator('header').getByText('Alex Taylor')).toBeVisible(); const fullyRenderedTime = Date.now() - start; console.log(`\n========================================`); console.log(`[AWS Lambda Hosting] DOM Content Loaded Time: ${domContentLoadedTime} ms`); console.log(`[AWS Lambda Hosting] Fully Rendered Page Time: ${fullyRenderedTime} ms (${(fullyRenderedTime / 1000).toFixed(2)}s)`); console.log(`========================================\n`); // Target: <1.5s locally, with up to 7.5s allowed in CI to accommodate multi-hop cross-continental API routing const threshold = process.env.CI ? 7500 : 3000; expect(fullyRenderedTime).toBeLessThan(threshold); await page.unrouteAll({ behavior: 'ignoreErrors' }); });