89 lines
3.6 KiB
JavaScript
89 lines
3.6 KiB
JavaScript
// @ts-check
|
|
import { test, expect } from '@playwright/test';
|
|
import { loadTestUser } from '../utils/testUser.js';
|
|
|
|
test.describe('@p1 Educational Programs — sorting (tuition vs distance)', () => {
|
|
test.setTimeout(120000);
|
|
|
|
test('sort toggles change ordering; list remains populated', async ({ page }) => {
|
|
const u = loadTestUser();
|
|
|
|
// 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 for programs fetch (UI does not render SOC/CIP)
|
|
await page.evaluate(() => {
|
|
localStorage.setItem('selectedCareer', JSON.stringify({
|
|
title: 'Data Analyst',
|
|
soc_code: '15-2051.00',
|
|
cip_code: ['11.0802', '04.0201']
|
|
}));
|
|
});
|
|
|
|
await page.goto('/educational-programs', { waitUntil: 'networkidle' });
|
|
|
|
// Wait for at least one card to render (match the card structure used in the component)
|
|
const card = page.locator('div.rounded.border.p-3.text-sm').first();
|
|
await expect(card).toBeVisible({ timeout: 30000 });
|
|
|
|
// Helper to read numbers from card list
|
|
async function readTuitionList() {
|
|
return await page.locator('div.rounded.border.p-3.text-sm').evaluateAll(nodes =>
|
|
nodes.map(n => {
|
|
const line = [...n.querySelectorAll('p')]
|
|
.map(p => p.textContent || '')
|
|
.find(t => /^In-State Tuition:\s*\$/.test(t));
|
|
if (!line) return NaN;
|
|
const match = line.replace(/,/g, '').match(/In-State Tuition:\s*\$(\d+(?:\.\d+)?)/i);
|
|
return match ? parseFloat(match[1]) : NaN;
|
|
}).filter(x => Number.isFinite(x))
|
|
);
|
|
}
|
|
|
|
async function readDistanceList() {
|
|
return await page.locator('div.rounded.border.p-3.text-sm').evaluateAll(nodes =>
|
|
nodes.map(n => {
|
|
const line = [...n.querySelectorAll('p')]
|
|
.map(p => p.textContent || '')
|
|
.find(t => /^Distance:\s*/i.test(t));
|
|
if (!line) return NaN;
|
|
const match = line.match(/Distance:\s*(\d+(?:\.\d+)?)\s*mi/i);
|
|
return match ? parseFloat(match[1]) : NaN; // NaN if "N/A"
|
|
}).filter(x => Number.isFinite(x))
|
|
);
|
|
}
|
|
|
|
const isNonDecreasing = (arr) => arr.every((v, i) => i === 0 || arr[i - 1] <= v);
|
|
|
|
// --- Default sort = Tuition ---
|
|
const tuitionBefore = await readTuitionList();
|
|
if (tuitionBefore.length >= 2) {
|
|
expect(isNonDecreasing(tuitionBefore)).toBeTruthy();
|
|
} else {
|
|
// At least the list is populated with cards
|
|
const cardCount = await page.locator('div.rounded.border.p-3.text-sm').count();
|
|
expect(cardCount).toBeGreaterThan(0);
|
|
}
|
|
|
|
// Switch Sort to Distance (the select is inside its label)
|
|
const sortSelect = page.locator('label:has-text("Sort")').locator('select');
|
|
await expect(sortSelect).toBeVisible();
|
|
await sortSelect.selectOption('distance');
|
|
|
|
// Wait for re-render by observing that either distances appear or first card block text changes
|
|
const distances = await readDistanceList();
|
|
if (distances.length >= 2) {
|
|
expect(isNonDecreasing(distances)).toBeTruthy();
|
|
} else {
|
|
// If distances are N/A (no ZIP), at least ensure the list remains populated
|
|
const cardCount = await page.locator('div.rounded.border.p-3.text-sm').count();
|
|
expect(cardCount).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
});
|