// @ts-check import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; const ENFORCE = process.env.APTIVA_ENFORCE_BUDGETS === '1'; // Budgets (ms) — adjust here when needed const B = { signup_areas: 15000, // state change -> areas select enabled & options>1 (dev may be slow) reload_cold: 60000, // click Reload -> careerSuggestionsCache length > 0 modal_cold: 3000, // click tile -> Add to Comparison visible }; function log(name, ms, budget) { console.log(`${name}: ${Math.round(ms)} ms${budget ? ` (budget ≤ ${budget})` : ''}`); if (ENFORCE && budget) expect(ms).toBeLessThanOrEqual(budget); } test.describe('@perf Focused Budgets', () => { test.setTimeout(30000); test('SignUp: Areas population time', async ({ page }) => { await page.context().clearCookies(); await page.goto('/signup', { waitUntil: 'networkidle' }); // Select State (dropdown with "Select State" placeholder) const stateSelect = page.locator('select').filter({ has: page.locator('option', { hasText: 'Select State' }), }); await expect(stateSelect).toBeVisible(); const areaSelect = page.locator('select#area'); await expect(areaSelect).toBeVisible(); const STATE = 'GA'; // Georgia (populates areas) const stateParam = encodeURIComponent(STATE); const t0 = Date.now(); await stateSelect.selectOption(STATE); // Wait for the API call and the UI to be interactable await page.waitForResponse( r => r.url().includes(`/api/areas?state=${stateParam}`) && r.request().method() === 'GET', { timeout: 20000 } ); await expect(areaSelect).toBeEnabled({ timeout: 10000 }); await expect(async () => { const count = await areaSelect.locator('option').count(); expect(count).toBeGreaterThan(1); }).toPass({ timeout: 10000 }); log('signup_areas', Date.now() - t0, B.signup_areas); }); test('Career Explorer: Reload Career Suggestions (cold)', async ({ page }) => { const u = loadTestUser(); await page.context().clearCookies(); await page.goto('/signin', { waitUntil: 'networkidle' }); await page.getByPlaceholder('Username', { exact: true }).fill(u.username); await page.getByPlaceholder('Password', { exact: true }).fill(u.password); await page.getByRole('button', { name: /^Sign In$/ }).click(); await page.waitForURL('**/signin-landing**', { timeout: 15000 }); await page.goto('/career-explorer', { waitUntil: 'networkidle' }); // Force cold by clearing cache await page.evaluate(() => localStorage.removeItem('careerSuggestionsCache')); const reloadBtn = page.getByRole('button', { name: /Reload Career Suggestions/i }); await expect(reloadBtn).toBeVisible(); const t0 = Date.now(); await reloadBtn.click(); // Wait for overlay to appear (if it does), then for it to effectively finish and hide. const overlayText = page.getByText(/Loading Career Suggestions/i).first(); const appeared = await overlayText.isVisible({ timeout: 2000 }).catch(() => false); if (appeared) { // Treat overlay hidden as 100%; otherwise poll the % and accept ≥95 as done. await expect .poll(async () => { const stillVisible = await overlayText.isVisible().catch(() => false); if (!stillVisible) return 100; const t = (await overlayText.textContent()) || ''; const m = t.match(/(\d+)%/); return m ? parseInt(m[1], 10) : 0; }, { timeout: B.reload_cold, message: 'reload overlay did not complete' }) .toBeGreaterThanOrEqual(95); await overlayText.waitFor({ state: 'hidden', timeout: B.reload_cold }).catch(() => {}); } // Source of truth: cache populated after overlay completes await expect .poll(async () => { return await page.evaluate(() => { try { const s = localStorage.getItem('careerSuggestionsCache'); const arr = s ? JSON.parse(s) : []; return Array.isArray(arr) ? arr.length : 0; } catch { return 0; } }); }, { timeout: B.reload_cold, message: 'careerSuggestionsCache not populated' }) .toBeGreaterThan(0); log('explorer_reload_cold', Date.now() - t0, B.reload_cold); }); test('Career Explorer: CareerModal open (cold)', async ({ page }) => { const u = loadTestUser(); await page.context().clearCookies(); await page.goto('/signin', { waitUntil: 'networkidle' }); await page.getByPlaceholder('Username', { exact: true }).fill(u.username); await page.getByPlaceholder('Password', { exact: true }).fill(u.password); await page.getByRole('button', { name: /^Sign In$/ }).click(); await page.waitForURL('**/signin-landing**', { timeout: 15000 }); await page.goto('/career-explorer', { waitUntil: 'networkidle' }); // Ensure at least one tile exists; if not, perform a quick reload const tile = page.locator('div.grid button').first(); if (!(await tile.isVisible({ timeout: 1500 }).catch(() => false))) { const reloadBtn = page.getByRole('button', { name: /Reload Career Suggestions/i }); await reloadBtn.click(); await expect .poll(async () => { return await page.evaluate(() => { try { const s = localStorage.getItem('careerSuggestionsCache'); const arr = s ? JSON.parse(s) : []; return Array.isArray(arr) ? arr.length : 0; } catch { return 0; } }); }, { timeout: 60000 }) .toBeGreaterThan(0); await expect(tile).toBeVisible({ timeout: 8000 }); } const t0 = Date.now(); await tile.click(); await page.getByRole('button', { name: /Add to Comparison/i }).waitFor({ timeout: 15000 }); log('careermodal_open_cold', Date.now() - t0, B.modal_cold); }); });