// @ts-check import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; const j = (o) => JSON.stringify(o); test.describe('@p1 ScenarioEditModal — save + retirement milestone (51)', () => { test.setTimeout(20000); test('Open modal, set retirement fields, save → creates Retirement milestone', async ({ page, request }) => { const u = loadTestUser(); // ── Premium gate await page.route( /\/api\/user-profile\?fields=.*(firstname|is_premium|is_pro_premium|area|state).*/i, r => r.fulfill({ status: 200, contentType: 'application/json', body: j({ firstname: 'Tester', is_premium: 1, is_pro_premium: 0, area: 'U.S.', state: 'GA' }) }) ); // ── Seed a scenario const seed = await request.post('/api/premium/career-profile', { data: { career_name: 'Software Developers', status: 'planned', start_date: '2025-01-01' } }); const { career_profile_id } = await seed.json(); // ── CareerRoadmap deps (minimal) await page.route(new RegExp(`/api/premium/career-profile/${career_profile_id}$`, 'i'), r => r.fulfill({ status: 200, contentType: 'application/json', body: j({ id: career_profile_id, scenario_title: 'SWE Plan', career_name: 'Software Developers', status: 'planned', start_date: '2025-01-01', college_enrollment_status: 'not_enrolled' }) }) ); await page.route(/\/api\/premium\/financial-profile$/i, r => r.fulfill({ status: 200, contentType: 'application/json', body: j({ current_salary: 90000, additional_income: 0, monthly_expenses: 2500, monthly_debt_payments: 300, retirement_savings: 10000, emergency_fund: 3000, retirement_contribution: 300, emergency_contribution: 200, extra_cash_emergency_pct: 50, extra_cash_retirement_pct: 50 }) })); await page.route(new RegExp(`/api/premium/college-profile\\?careerProfileId=${career_profile_id}$`, 'i'), r => r.fulfill({ status: 200, contentType: 'application/json', body: j({}) }) ); // Salary/Projections to keep UI calm await page.route(/\/api\/salary\?*/i, r => r.fulfill({ status: 200, contentType: 'application/json', body: j({}) })); await page.route(/\/api\/projections\/15-1252\?state=.*/i, r => r.fulfill({ status: 200, contentType: 'application/json', body: j({}) })); // Milestones list for CareerRoadmap panel (empty) await page.route(new RegExp(`/api/premium/milestones\\?careerProfileId=${career_profile_id}$`, 'i'), r => r.fulfill({ status: 200, contentType: 'application/json', body: j({ milestones: [] }) }) ); // POST /career-profile (upsert on save) await page.route(/\/api\/premium\/career-profile$/i, async r => { if (r.request().method() === 'POST') { return r.fulfill({ status: 200, contentType: 'application/json', body: j({ career_profile_id }) }); } return r.fallback(); }); // GET milestones?careerProfileId=.. (check Retirement exists) → none await page.route(/\/api\/premium\/milestones\?careerProfileId=\d+$/i, r => { return r.fulfill({ status: 200, contentType: 'application/json', body: j({ milestones: [] }) // no Retirement yet → should POST }); }); // POST /milestone (create Retirement) await page.route(/\/api\/premium\/milestone$/i, async r => { if (r.request().method() === 'POST') { return r.fulfill({ status: 200, contentType: 'application/json', body: j({ id: 70001 }) }); } return r.fallback(); }); // PUT /milestones/:id (would be used if it already existed) await page.route(/\/api\/premium\/milestones\/\d+$/i, async r => { if (r.request().method() === 'PUT') { return r.fulfill({ status: 200, body: '{}' }); } return r.fallback(); }); // ── Navigate to roadmap await page.goto(`/career-roadmap/${career_profile_id}`, { waitUntil: 'domcontentloaded' }); // Open the ScenarioEditModal const editBtn = page.getByRole('button', { name: /^Edit Simulation Inputs$/i }); await expect(editBtn).toBeVisible({ timeout: 6000 }); await editBtn.click(); // Modal visible const modalHeading = page.getByRole('heading', { name: /^Edit Scenario:/i }).first(); await expect(modalHeading).toBeVisible({ timeout: 6000 }); // Set retirement date and desired monthly income (robust selectors) const retireField = page.locator('input[name="retirement_start_date"]').first(); const dtype = (await retireField.getAttribute('type')) || ''; if (dtype.toLowerCase() === 'date') { await retireField.fill('2035-06-01'); } else { await retireField.fill(''); await retireField.type('06/01/2035', { delay: 10 }); } const incomeField = page.locator('input[name="desired_retirement_income_monthly"]').first(); await incomeField.fill('5500'); // Prepare network waits before clicking Save const waitUpsert = page.waitForRequest(req => /\/api\/premium\/career-profile$/i.test(req.url()) && req.method() === 'POST' ); const waitMilestonesCheck = page.waitForRequest(req => new RegExp(`/api/premium/milestones\\?careerProfileId=${career_profile_id}$`, 'i').test(req.url()) ); const waitRetirementCreateOrPut = page.waitForRequest(req => /\/api\/premium\/milestone($|\/\d+$)/i.test(req.url()) && /^(POST|PUT)$/.test(req.method()) ); // Save await page.getByRole('button', { name: /^Save$/i }).click(); // Modal closes await expect(modalHeading).toHaveCount(0, { timeout: 6000 }); // Verify requests fired await Promise.all([ waitUpsert, waitMilestonesCheck, waitRetirementCreateOrPut ]); }); });