import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; test.describe('@p1 Career Explorer — CareerSearch datalist', () => { test.setTimeout(30000); test('datalist commit opens modal; Change resets input', async ({ page }) => { const user = loadTestUser(); // Helpers async function closeAnyOverlay() { const overlay = page.locator('div.fixed.inset-0'); if (!(await overlay.isVisible({ timeout: 500 }).catch(() => false))) return; const dlg = overlay.locator('div[role="dialog"], div.bg-white').first(); // If modal asks for ratings, pick neutral values and Save/Continue so it goes away. const selects = dlg.locator('select'); const sc = await selects.count().catch(() => 0); for (let i = 0; i < sc; i++) { const sel = selects.nth(i); if (await sel.isVisible().catch(() => false)) { const has3 = await sel.locator('option[value="3"]').count().catch(() => 0); if (has3) await sel.selectOption('3'); else { const opts = sel.locator('option'); const n = await opts.count().catch(() => 0); for (let j = 0; j < n; j++) { const v = await opts.nth(j).getAttribute('value'); if (v) { await sel.selectOption(v); break; } } } } } const tb = dlg.locator('input, textarea, [role="textbox"]').first(); if (await tb.isVisible().catch(() => false)) await tb.fill('3'); const save = dlg.getByRole('button', { name: /(Save|Continue|Done|OK)/i }); const cancel = dlg.getByRole('button', { name: /(Cancel|Close)/i }); if (await save.isVisible({ timeout: 500 }).catch(() => false)) await save.click(); else if (await cancel.isVisible({ timeout: 500 }).catch(() => false)) await cancel.click(); else await page.keyboard.press('Escape'); await overlay.waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {}); } // Sign in await page.context().clearCookies(); await page.goto('/signin', { waitUntil: 'networkidle' }); await page.getByPlaceholder('Username', { exact: true }).fill(user.username); await page.getByPlaceholder('Password', { exact: true }).fill(user.password); await page.getByRole('button', { name: /^Sign In$/ }).click(); await page.waitForURL('**/signin-landing**', { timeout: 15000 }); // Go to Career Explorer await page.goto('/career-explorer', { waitUntil: 'networkidle' }); await expect(page.getByRole('heading', { name: /Explore Careers - use these tools/i })).toBeVisible(); await closeAnyOverlay(); const input = page.getByPlaceholder('Start typing a career...'); // If previously selected, the input is disabled; click Change to reset. if (await input.isDisabled()) { const changeLink = page.getByRole('button', { name: /^Change$/i }).or(page.getByText(/^Change$/)); await expect(changeLink).toBeVisible({ timeout: 5000 }); await changeLink.click(); await expect(input).toBeEnabled({ timeout: 2000 }); await expect(input).toHaveValue(''); } // Type a partial and wait for datalist options to populate await input.fill('block'); const options = page.locator('datalist#career-titles option'); await expect .poll(async () => await options.count(), { timeout: 7000, message: 'no datalist options' }) .toBeGreaterThan(0); // Take the first suggestion's exact value (e.g., "Blockchain Engineers") const firstValue = await options.first().evaluate(el => el.value); // Commit by setting exact value + blur (component commits on exact + blur) await input.fill(firstValue); await input.blur(); // Loading overlay may show; wait for it to appear (optional) then hide const loading = page.getByText(/Loading Career/i).first(); // matches “Loading Career Suggestions…” await loading.isVisible({ timeout: 2000 }).catch(() => {}); await loading.waitFor({ state: 'hidden', timeout: 60000 }).catch(() => {}); // guard slow cold path // CareerModal should open (Add to Comparison button present) await expect(page.getByRole('button', { name: /Add to Comparison/i })).toBeVisible({ timeout: 15000 }); // Close the modal (don’t add in this test) const closeBtn = page.getByRole('button', { name: /^Close$/i }); if (await closeBtn.isVisible().catch(() => false)) { await closeBtn.click(); } else { await page.keyboard.press('Escape'); } // Input becomes disabled after selection; click Change to reset await expect(input).toBeDisabled(); const changeLink = page.getByRole('button', { name: /^Change$/i }).or(page.getByText(/^Change$/)); await expect(changeLink).toBeVisible({ timeout: 5000 }); await changeLink.click(); // Now the input should be enabled and cleared await expect(input).toBeEnabled(); await expect(input).toHaveValue(''); }); });