263 lines
11 KiB
JavaScript
263 lines
11 KiB
JavaScript
// @ts-nocheck
|
|
import { test, expect } from '@playwright/test';
|
|
import { loadTestUser } from '../utils/testUser.js';
|
|
|
|
const SCHOOL = 'Alabama A & M University';
|
|
const PROGRAM = 'Agriculture, General.';
|
|
const DEGREE = "Bachelor's Degree";
|
|
|
|
async function fillDateField(ctrl, iso = '2027-06-01', us = '06/01/2027') {
|
|
const type = (await ctrl.getAttribute('type')) || '';
|
|
if (type.toLowerCase() === 'date') {
|
|
await ctrl.fill(iso);
|
|
} else {
|
|
await ctrl.scrollIntoViewIfNeeded();
|
|
await ctrl.click({ force: true });
|
|
await ctrl.fill('');
|
|
await ctrl.type(us, { delay: 15 });
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
test.describe('@p1 College-Profile (45c)', () => {
|
|
test.setTimeout(20000);
|
|
|
|
test('Create new college plan from list (with link-to-career prompt) → save', async ({ page, request }) => {
|
|
const u = loadTestUser();
|
|
|
|
// Premium gate
|
|
await page.route(
|
|
/\/api\/user-profile\?fields=.*(firstname|is_premium|is_pro_premium).*/i,
|
|
r => r.fulfill({ status: 200, contentType: 'application/json',
|
|
body: JSON.stringify({ firstname: 'Tester', is_premium: 1, is_pro_premium: 0 }) })
|
|
);
|
|
|
|
// Seed a minimal Career Profile (needed for the prompt dropdown)
|
|
const scen = await request.post('/api/premium/career-profile', {
|
|
data: { career_name: 'Teaching Assistants, Postsecondary', status: 'planned', start_date: '2025-09-01' }
|
|
});
|
|
const { career_profile_id } = await scen.json();
|
|
|
|
// Deterministic autosuggest + degree + tuition
|
|
await page.route(/\/api\/schools\/suggest\?*/i, async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json',
|
|
body: JSON.stringify([{ name: 'Alabama A & M University', unitId: 100654 }]) });
|
|
});
|
|
await page.route(/\/api\/programs\/suggest\?*/i, async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json',
|
|
body: JSON.stringify([{ program: 'Agriculture, General.' }]) });
|
|
});
|
|
await page.route(/\/api\/programs\/types\?*/i, async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json',
|
|
body: JSON.stringify({ types: ["Bachelor's Degree"] }) });
|
|
});
|
|
await page.route(/\/api\/tuition\/estimate\?*/i, async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json',
|
|
body: JSON.stringify({ estimate: 17220 }) });
|
|
});
|
|
|
|
// Accept POST save
|
|
await page.route('**/api/premium/college-profile', async route => {
|
|
if (route.request().method() === 'POST') {
|
|
await route.fulfill({ status: 200, body: JSON.stringify({ ok: true }) });
|
|
} else {
|
|
await route.fallback();
|
|
}
|
|
});
|
|
|
|
// Sign in
|
|
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: 15000 });
|
|
|
|
// List → + New College Plan (expect link-to-career prompt)
|
|
await page.goto('/profile/college', { waitUntil: 'domcontentloaded' });
|
|
await page.getByRole('button', { name: '+ New College Plan' }).click();
|
|
// The prompt is a labeled box; target the <select> inside that label container.
|
|
const promptBox = page.locator('text=Select the career this college plan belongs to:').first();
|
|
await expect(promptBox).toBeVisible({ timeout: 5000 });
|
|
const promptSelect = promptBox.locator('..').locator('select').first();
|
|
await expect(promptSelect).toBeVisible({ timeout: 5000 });
|
|
await promptSelect.selectOption(String(career_profile_id));
|
|
// Selecting navigates to new editor with query params (?career=…)
|
|
await expect(page).toHaveURL(/\/profile\/college\/new\?career=.*$/i, { timeout: 10000 });
|
|
await expect(page.getByRole('heading', { name: /College Plan|New College Plan/i }))
|
|
.toBeVisible({ timeout: 10000 });
|
|
|
|
// Fill required fields on editor
|
|
const school = page.locator('input[name="selected_school"]').first();
|
|
await school.fill('Alabama');
|
|
await page.keyboard.press('ArrowDown').catch(() => {});
|
|
await page.keyboard.press('Enter').catch(() => {});
|
|
|
|
const program = page.locator('input[name="selected_program"]').first();
|
|
await program.fill('Agri');
|
|
await page.keyboard.press('ArrowDown').catch(() => {});
|
|
await page.keyboard.press('Enter').catch(() => {});
|
|
|
|
await page.locator('select[name="program_type"]').first().selectOption({ label: "Bachelor's Degree" }).catch(() => {});
|
|
const grad = page.locator('input[name="expected_graduation"]').first();
|
|
const t = (await grad.getAttribute('type')) || '';
|
|
if (t.toLowerCase() === 'date') await grad.fill('2028-05-01');
|
|
else { await grad.fill(''); await grad.type('05/01/2028', { delay: 15 }); }
|
|
|
|
page.once('dialog', d => d.accept().catch(() => {}));
|
|
await page.getByRole('button', { name: /^Save$/ }).click();
|
|
await expect(page).not.toHaveURL(/\/edit$/i, { timeout: 10000 });
|
|
});
|
|
|
|
test('Edit existing plan: autosuggest + degree + save', async ({ page, request }) => {
|
|
const u = loadTestUser();
|
|
|
|
// Premium gate
|
|
await page.route(
|
|
/\/api\/user-profile\?fields=.*(firstname|is_premium|is_pro_premium).*/i,
|
|
r => r.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ firstname: 'Tester', is_premium: 1, is_pro_premium: 0 })
|
|
})
|
|
);
|
|
|
|
// Deterministic autosuggests/types/tuition
|
|
await page.route(/\/api\/schools\/suggest\?*/i, async route => {
|
|
const url = new URL(route.request().url());
|
|
const q = (url.searchParams.get('query') || '').toLowerCase();
|
|
const list = q.includes('alabama') ? [{ name: SCHOOL, unitId: 100654 }] : [];
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(list) });
|
|
});
|
|
|
|
await page.route(/\/api\/programs\/suggest\?*/i, async route => {
|
|
const url = new URL(route.request().url());
|
|
const school = (url.searchParams.get('school') || '').toLowerCase();
|
|
const q = (url.searchParams.get('query') || '').toLowerCase();
|
|
const list = school.includes('alabama a & m') && (q.includes('agri') || q === '')
|
|
? [{ program: PROGRAM }]
|
|
: [];
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(list) });
|
|
});
|
|
|
|
await page.route(/\/api\/programs\/types\?*/i, async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ types: [DEGREE, "Associate's Degree", "Master's Degree"] })
|
|
});
|
|
});
|
|
|
|
await page.route(/\/api\/tuition\/estimate\?*/i, async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ estimate: 17220 }) });
|
|
});
|
|
|
|
// Initial GET for edit page
|
|
await page.route(/\/api\/premium\/college-profile\?careerProfileId=.*/i, async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
selected_school: SCHOOL,
|
|
selected_program: PROGRAM,
|
|
program_type: DEGREE,
|
|
expected_graduation: '2027-06-01',
|
|
academic_calendar: 'semester',
|
|
credit_hours_per_year: 27,
|
|
interest_rate: 5.5,
|
|
loan_term: 10,
|
|
tuition: 17220,
|
|
unit_id: 100654,
|
|
loan_deferral_until_graduation: 1
|
|
})
|
|
});
|
|
});
|
|
|
|
// Accept POST save
|
|
await page.route('**/api/premium/college-profile', async route => {
|
|
if (route.request().method() === 'POST') {
|
|
await route.fulfill({ status: 200, body: '{}' });
|
|
} else {
|
|
await route.fallback();
|
|
}
|
|
});
|
|
|
|
// Sign in
|
|
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: 15000 });
|
|
|
|
// Create scenario + minimal plan server-side
|
|
const scen = await request.post('/api/premium/career-profile', {
|
|
data: { career_name: 'QA College Plan', status: 'planned', start_date: '2025-09-01' }
|
|
});
|
|
const { career_profile_id } = await scen.json();
|
|
|
|
await request.post('/api/premium/college-profile', {
|
|
data: {
|
|
career_profile_id,
|
|
selected_school: SCHOOL,
|
|
selected_program: PROGRAM,
|
|
program_type: DEGREE,
|
|
expected_graduation: '2027-06-01',
|
|
academic_calendar: 'semester',
|
|
credit_hours_per_year: 27,
|
|
interest_rate: 5.5,
|
|
loan_term: 10
|
|
}
|
|
});
|
|
|
|
// Go to edit
|
|
await page.goto(`/profile/college/${career_profile_id}/edit`, { waitUntil: 'domcontentloaded' });
|
|
await expect(page.getByRole('heading', { name: /Edit College Plan|College Plan/i })).toBeVisible({ timeout: 20000 });
|
|
|
|
// School (partial -> suggestions -> commit exact)
|
|
const schoolBox = page.locator('input[name="selected_school"]').first();
|
|
await schoolBox.fill('Alabama A &');
|
|
await expect.poll(async () => await page.locator('#school-suggestions option').count(), { timeout: 5000 })
|
|
.toBeGreaterThan(0);
|
|
await commitAutosuggest(page, schoolBox, SCHOOL);
|
|
|
|
// Program (partial -> suggestions -> commit exact)
|
|
const programBox = page.locator('input[name="selected_program"]').first();
|
|
await programBox.fill('Agri');
|
|
await expect.poll(async () => await page.locator('#program-suggestions option').count(), { timeout: 5000 })
|
|
.toBeGreaterThan(0);
|
|
await commitAutosuggest(page, programBox, PROGRAM);
|
|
|
|
// Degree
|
|
const degreeSelect = page.locator('select[name="program_type"]').first();
|
|
await expect.poll(async () => await degreeSelect.locator('option').count(), { timeout: 15000 }).toBeGreaterThan(1);
|
|
try {
|
|
await degreeSelect.selectOption({ label: DEGREE });
|
|
} catch {
|
|
const firstReal = degreeSelect.locator('option').nth(1);
|
|
const val = await firstReal.getAttribute('value');
|
|
if (val) await degreeSelect.selectOption(val);
|
|
}
|
|
|
|
// Expected Graduation Date
|
|
const grad = page.locator('input[name="expected_graduation"]').first();
|
|
await fillDateField(grad, '2028-05-01', '05/01/2028');
|
|
|
|
// Save (accept alert) and ensure we left /edit
|
|
page.once('dialog', d => d.accept().catch(() => {}));
|
|
await page.getByRole('button', { name: /^Save$/i }).click();
|
|
await expect(page).not.toHaveURL(/\/edit$/i, { timeout: 10000 });
|
|
|
|
// Sanity: no inline validation error text rendered
|
|
await expect(page.getByText(/Please pick a (school|program) from the list/i)).toHaveCount(0, { timeout: 2000 })
|
|
.catch(() => {});
|
|
});
|
|
});
|