// @ts-check import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; test.describe('@p1 Profile Editors — Career, Financial, and College', () => { test.setTimeout(90_000); test.beforeEach(async ({ page }) => { const u = loadTestUser(); // Premium gate that App.js / PremiumRoute actually uses await page.route( /\/api\/user-profile\?fields=.*(firstname|is_premium|is_pro_premium).*/i, async route => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ firstname: 'Tester', is_premium: 1, is_pro_premium: 0 }) }); } ); // Real sign-in (single session per test) await page.context().clearCookies(); await page.goto('/signin', { waitUntil: 'domcontentloaded' }); 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: 15_000 }); }); // -------- Career profile (edit) -------- test('CareerProfileList → edit first profile title and save', async ({ page }) => { // Ensure at least one await page.request.post('/api/premium/career-profile', { data: { career_name: 'QA Scenario', status: 'planned', start_date: '2025-09-01' } }); await page.goto('/profile/careers', { waitUntil: 'domcontentloaded' }); await expect(page.getByRole('heading', { name: 'Career Profiles' })).toBeVisible(); const editLinks = page.locator('a', { hasText: /^edit$/i }); await editLinks.first().click(); await expect(page.getByRole('heading', { name: /Edit Career Profile|New Career Profile/i })) .toBeVisible({ timeout: 15_000 }); const title = page.getByLabel(/Scenario Title/i); const prev = await title.inputValue().catch(() => 'Scenario'); await title.fill((prev || 'Scenario') + ' — test'); await page.getByRole('button', { name: /^Save$/ }).click(); await expect(page).toHaveURL(/\/career-roadmap\/[a-z0-9-]+$/i, { timeout: 20_000 }); }); // -------- Financial profile (save) -------- test('FinancialProfileForm saves and returns', async ({ page }) => { await page.goto('/profile/financial', { waitUntil: 'domcontentloaded' }); await expect(page.getByRole('heading', { name: /Financial Profile/i })).toBeVisible({ timeout: 10_000 }); await page.getByLabel(/Current.*Annual.*Salary/i).fill('55000'); await page.getByLabel(/Monthly.*Living.*Expenses/i).fill('1800'); await page.getByLabel(/Monthly.*Debt.*Payments/i).fill('200'); await page.getByLabel(/To.*Emergency.*\(%\)/i).fill('40'); // 60 to retirement auto-computed await page.getByRole('button', { name: /^Save$/ }).click(); await expect(page).not.toHaveURL(/\/profile\/financial$/i, { timeout: 15_000 }); }); // Helper: commit autosuggest that sometimes needs two selects async function commitAutosuggest(page, input, text) { await input.click(); await input.fill(text); await page.keyboard.press('ArrowDown').catch(() => {}); await page.keyboard.press('Enter').catch(() => {}); await input.blur(); const v1 = (await input.inputValue()).trim(); if (v1.toLowerCase() === text.toLowerCase()) { // Some nested lists require a second confirmation await input.click(); await page.keyboard.press('ArrowDown').catch(() => {}); await page.keyboard.press('Enter').catch(() => {}); await input.blur(); } } // ---- College helpers (put near the top of the file) ---- async function commitAutosuggest(page, input, text) { // Type and try first commit await input.click(); await input.fill(text); await page.keyboard.press('ArrowDown').catch(() => {}); await page.keyboard.press('Enter').catch(() => {}); await input.blur(); // If typed value still equals exactly what we wrote, some lists need a second confirm const v1 = (await input.inputValue()).trim(); if (v1.toLowerCase() === text.toLowerCase()) { await input.click(); await page.keyboard.press('ArrowDown').catch(() => {}); await page.keyboard.press('Enter').catch(() => {}); await input.blur(); } } async function pickDegree(page) { const select = page.getByLabel(/Degree Type/i); try { await select.selectOption({ label: "Bachelor's Degree" }); return; } catch {} const second = select.locator('option').nth(1); // skip placeholder await second.waitFor({ state: 'attached', timeout: 10_000 }); const val = await second.getAttribute('value'); if (val) await select.selectOption(val); } // Known-good school/program pair from your dataset const SCHOOL = 'Alabama A & M University'; const PROGRAM = 'Agriculture, General.'; // ---- CollegeProfileForm — create NEW plan (autosuggests must appear, then save) ---- test('CollegeProfileForm — create new plan (autosuggests + degree + save)', async ({ page, request }) => { // Fail the test if any unexpected alert shows page.on('dialog', d => { throw new Error(`Unexpected dialog: "${d.message()}"`); }); // Create a scenario to attach the college plan const scen = await request.post('/api/premium/career-profile', { data: { career_name: 'QA College Plan (new)', status: 'planned', start_date: '2025-09-01' } }); const { career_profile_id } = await scen.json(); await page.goto(`/profile/college/${career_profile_id}/new`, { waitUntil: 'domcontentloaded' }); await expect(page.getByRole('heading', { name: /College Plan|Edit College Plan|New College/i })) .toBeVisible({ timeout: 15_000 }); const SCHOOL = 'Alabama A & M University'; const PROGRAM = 'Agriculture, General.'; const schoolBox = page.getByLabel(/School Name/i); const programBox = page.getByLabel(/Major.*Program.*Name/i); // Type partial and assert autosuggest options exist (prove the dropdown is presented) await schoolBox.fill('Alabama A &'); await expect.poll(async () => { return await page.locator('#school-suggestions option').count(); }, { timeout: 5000 }).toBeGreaterThan(0); // Commit school programmatically with double-confirm helper await commitAutosuggest(page, schoolBox, SCHOOL); // Program autosuggest must be present too await programBox.fill('Agri'); await expect.poll(async () => { return await page.locator('#school-suggestions option').count(); }, { timeout: 5000 }).toBeGreaterThan(0); // Commit program await commitAutosuggest(page, programBox, PROGRAM); // Pick degree + set expected graduation await pickDegree(page); const grad = page.getByLabel(/Expected Graduation Date/i); if (await grad.isVisible().catch(() => false)) await grad.fill('2027-06-01'); // Save await page.getByRole('button', { name: /^Save$/i }).click(); // Should not remain stuck on /new (and no alerts were raised) await expect(page).not.toHaveURL(/\/new$/i, { timeout: 10_000 }); }); // ---- CollegeProfileForm — EDIT existing plan (autosuggests + degree + save) ---- test('CollegeProfileForm — edit existing plan (autosuggests + degree + save)', async ({ page, request }) => { // Fail the test if any unexpected alert shows page.on('dialog', d => { throw new Error(`Unexpected dialog: "${d.message()}"`); }); // Create a scenario and seed a minimal college plan const scen = await request.post('/api/premium/career-profile', { data: { career_name: 'QA College Plan (edit)', status: 'planned', start_date: '2025-09-01' } }); const { career_profile_id } = await scen.json(); const SCHOOL = 'Alabama A & M University'; const PROGRAM = 'Agriculture, General.'; await request.post('/api/premium/college-profile', { data: { career_profile_id, selected_school: SCHOOL, selected_program: PROGRAM, program_type: "Bachelor's Degree", expected_graduation: '2027-06-01', academic_calendar: 'semester', credit_hours_per_year: 30, interest_rate: 5.5, loan_term: 10 } }); await page.goto(`/profile/college/${career_profile_id}/edit`, { waitUntil: 'domcontentloaded' }); await expect(page.getByRole('heading', { name: /College Plan|Edit College Plan/i })) .toBeVisible({ timeout: 15_000 }); const schoolBox = page.getByLabel(/School Name/i); const programBox = page.getByLabel(/Major.*Program.*Name/i); // Assert autosuggest presents options on partial typing await schoolBox.fill('Alabama A &'); await expect.poll(async () => { return await page.locator('#school-suggestions option').count(); }, { timeout: 5000 }).toBeGreaterThan(0); // Recommit the same school/program (exercise autosuggest again) await commitAutosuggest(page, schoolBox, SCHOOL); await programBox.fill('Agri'); await expect.poll(async () => { return await page.locator('#school-suggestions option').count(); }, { timeout: 5000 }).toBeGreaterThan(0); await commitAutosuggest(page, programBox, PROGRAM); await pickDegree(page); const grad = page.getByLabel(/Expected Graduation Date/i); if (await grad.isVisible().catch(() => false)) await grad.fill('2028-05-01'); await page.getByRole('button', { name: /^Save$/i }).click(); // No error popup was allowed; we just assert we’re not showing the error text await expect(page.getByText(/Please pick a school from the list/i)) .toHaveCount(0, { timeout: 2000 }) .catch(() => {}); }); });