141 lines
5.0 KiB
JavaScript
141 lines
5.0 KiB
JavaScript
// @ts-nocheck
|
||
import { test, expect } from '@playwright/test';
|
||
import { loadTestUser } from '../utils/testUser.js';
|
||
|
||
test.describe('@p1 Educational Programs — distance filter (with geocode + schools stubs)', () => {
|
||
test.setTimeout(20000);
|
||
|
||
test('Distance (max) narrows results when ZIP is present', async ({ page }) => {
|
||
const u = loadTestUser();
|
||
|
||
// ---- Stubs ----
|
||
// 1) Profile ZIP/state so distance can be computed (match any query suffix)
|
||
await page.route('**/api/user-profile**', async route => {
|
||
await route.fulfill({
|
||
status: 200, contentType: 'application/json',
|
||
body: JSON.stringify({ zipcode: '30301', state: 'GA', area: 'Atlanta, GA' })
|
||
});
|
||
});
|
||
|
||
// 2) Geocode ZIP → lat/lng (actual endpoint used by clientGeocodeZip)
|
||
await page.route('https://maps.googleapis.com/maps/api/geocode/json**', async route => {
|
||
await route.fulfill({
|
||
status: 200,
|
||
contentType: 'application/json',
|
||
body: JSON.stringify({
|
||
status: 'OK',
|
||
results: [
|
||
{ geometry: { location: { lat: 33.7495, lng: -84.3883 } } }
|
||
]
|
||
})
|
||
});
|
||
});
|
||
|
||
// 3) Schools list for CIP codes (cover common paths)
|
||
const schools = [
|
||
// near Atlanta (~3–5 mi)
|
||
{
|
||
INSTNM: 'Atlanta Tech College',
|
||
CIPDESC: 'Data Analytics',
|
||
CREDDESC: 'Certificate',
|
||
'In_state cost': '5000',
|
||
'Out_state cost': '7000',
|
||
LATITUDE: '33.80',
|
||
LONGITUD: '-84.39',
|
||
Website: 'atl.tech.edu',
|
||
UNITID: '1001',
|
||
State: 'GA'
|
||
},
|
||
// far (Chicago, ~590 mi)
|
||
{
|
||
INSTNM: 'Chicago State',
|
||
CIPDESC: 'Data Analytics',
|
||
CREDDESC: 'Bachelor',
|
||
'In_state cost': '6000',
|
||
'Out_state cost': '8000',
|
||
LATITUDE: '41.8781',
|
||
LONGITUD: '-87.6298',
|
||
Website: 'chicago.state.edu',
|
||
UNITID: '2002',
|
||
State: 'IL'
|
||
}
|
||
];
|
||
const fulfillSchools = async (route) => {
|
||
await route.fulfill({
|
||
status: 200, contentType: 'application/json',
|
||
body: JSON.stringify(schools)
|
||
});
|
||
};
|
||
await page.route('**/api/**schools**', fulfillSchools);
|
||
await page.route('**/api/**program**', fulfillSchools);
|
||
|
||
// 4) Avoid premium KSA latency: return empty quickly
|
||
await page.route('**/api/premium/ksa/**', async route => {
|
||
await route.fulfill({
|
||
status: 200, contentType: 'application/json',
|
||
body: JSON.stringify({ data: { knowledge: [], skills: [], abilities: [] } })
|
||
});
|
||
});
|
||
|
||
// ---- Sign in ----
|
||
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 });
|
||
|
||
// Seed selectedCareer so Programs loads without Explorer handoff
|
||
await page.evaluate(() => {
|
||
localStorage.setItem('selectedCareer', JSON.stringify({
|
||
title: 'Data Analyst',
|
||
soc_code: '15-2051.00',
|
||
cip_code: ['11.0802', '04.0201']
|
||
}));
|
||
});
|
||
|
||
// ---- Go to Programs ----
|
||
await page.goto('/educational-programs', { waitUntil: 'networkidle' });
|
||
|
||
// Wait for cards to render
|
||
const cards = page.locator('div.rounded.border.p-3.text-sm');
|
||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||
|
||
// Confirm we have at least one card up front
|
||
const countBefore = await cards.count();
|
||
expect(countBefore).toBeGreaterThan(0);
|
||
|
||
// Set Distance (max) to a small number to keep only the ATL card
|
||
const distanceInput = page.getByLabel(/Distance \(max\)/i);
|
||
await expect(distanceInput).toBeVisible();
|
||
await distanceInput.fill('10');
|
||
// ensure onChange/onBlur handlers fire
|
||
await distanceInput.press('Enter').catch(() => {});
|
||
await distanceInput.blur().catch(() => {});
|
||
await page.waitForTimeout(200); // small debounce cushion
|
||
// Trigger change — many components require blur or Enter
|
||
await distanceInput.press('Enter').catch(() => {});
|
||
await distanceInput.blur().catch(() => {});
|
||
// After applying Distance(max)=10, the Chicago card should disappear
|
||
// (don’t rely on count; assert by card names)
|
||
await expect
|
||
.poll(async () => {
|
||
const names = await page
|
||
.locator('div.rounded.border.p-3.text-sm strong')
|
||
.allInnerTexts()
|
||
.catch(() => []);
|
||
const anyVisible = names.length > 0;
|
||
const hasChicago = names.some(n => /chicago/i.test(n));
|
||
return anyVisible && !hasChicago;
|
||
}, { timeout: 20000 })
|
||
.toBeTruthy();
|
||
|
||
// And at least one visible card should be the ATL school
|
||
const namesAfter = await page
|
||
.locator('div.rounded.border.p-3.text-sm strong')
|
||
.allInnerTexts()
|
||
.catch(() => []);
|
||
expect(namesAfter.some(n => /atlanta/i.test(n))).toBeTruthy();
|
||
});
|
||
});
|