/** * Guarded consultation-only Form A browser regression. * Run after an explicitly gated isolated-test build. Every Jotform request is * fulfilled or aborted locally; no Jotform request is transmitted. */ import { randomBytes } from 'node:crypto'; import { encryptPortalStream, portalAlgorithm } from '../src/utils/portal-crypto.mjs'; import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import http from 'node:http'; import net from 'node:net'; import path from 'node:path'; import { spawn } from 'node:child_process'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { setTimeout as delay } from 'node:timers/promises'; const root = fileURLToPath(new URL('../', import.meta.url)); const moduleName = process.env.PLAYWRIGHT_MODULE ? pathToFileURL(path.resolve(process.env.PLAYWRIGHT_MODULE)).href : 'playwright'; const output = await fs.mkdtemp('/tmp/aia-service-portal-'); const routes = [ { route: '/client-consultation', locale: 'en', drawer: false, screenshot: 'client-consultation' }, { route: '/es/client-consultation', locale: 'es', drawer: false, screenshot: 'es-client-consultation' }, { route: '/schedule-consultation', locale: 'en', drawer: false, screenshot: 'schedule-consultation' }, { route: '/aba-therapy', locale: 'en', drawer: true, screenshot: 'aba-therapy' }, { route: '/autism-evaluations', locale: 'en', drawer: true, screenshot: 'autism-evaluations' }, { route: '/learner-social-club', locale: 'en', drawer: true, screenshot: 'learner-social-club' }, { route: '/es/aba-therapy', locale: 'es', drawer: true, screenshot: 'es-aba-therapy' }, { route: '/es/autism-evaluations', locale: 'es', drawer: true, screenshot: 'es-autism-evaluations' }, { route: '/es/learner-social-club', locale: 'es', drawer: true, screenshot: 'es-learner-social-club' }, ]; const widths = [320, 390, 768, 1440]; const evidence = { routes, widths, checks: 0, blocked: [], jotformAttempts: [], screenshots: [], fallbackChecks: [], status: 'failed' }; const reserve = net.createServer(); await new Promise((resolve, reject) => { reserve.once('error', reject); reserve.listen(0, '127.0.0.1', resolve); }); const port = reserve.address().port; await new Promise((resolve) => reserve.close(resolve)); const origin = 'http://127.0.0.1:' + port; let browser; let preview; function expectedUrl(locale) { return 'https://form.jotform.com/262946078314059?formContext=consultation&language=' + locale; } try { const { chromium } = await import(moduleName); browser = await chromium.launch(process.env.CHROMIUM_EXECUTABLE ? { headless: true, executablePath: process.env.CHROMIUM_EXECUTABLE } : { headless: true }); preview = spawn(process.execPath, ['node_modules/astro/bin/astro.mjs', 'preview', '--host', '127.0.0.1', '--port', String(port)], { cwd: root, env: { ...process.env, ASTRO_TELEMETRY_DISABLED: '1' }, stdio: 'ignore', }); const reachable = () => new Promise((resolve) => { const request = http.get(origin + '/', (response) => { response.resume(); resolve(response.statusCode === 200); }); request.setTimeout(500, () => request.destroy()); request.on('error', () => resolve(false)); }); for (let i = 0; i < 60 && !(await reachable()); i++) await delay(250); assert.equal(await reachable(), true, 'Loopback preview did not become reachable'); const key = 'aia:service-inquiry:auto-suppressed-until'; const duration = 30 * 86400000; const staffCode = randomBytes(24).toString('hex'); const managementCode = randomBytes(24).toString('hex'); const payload = { alg: portalAlgorithm, streams: [ await encryptPortalStream('fixture-staff', '

Synthetic Staff

Staff fixture only

Synthetic resource', staffCode), await encryptPortalStream('fixture-management', '

Synthetic Management

Management fixture only

', managementCode), ] }; const guard = async (context, inject = false) => { await context.routeWebSocket('**/*', (socket) => { evidence.blocked.push({ method: 'WEBSOCKET' }); socket.close(); }); await context.route('**/*', async (route) => { const req = route.request(), url = new URL(req.url()); if (url.origin === origin && ['GET', 'HEAD'].includes(req.method())) { if (inject && url.pathname === '/employee-portal') { const response = await route.fetch(); const html = (await response.text()).replace(/(]*data-portal-payload[^>]*>)[\s\S]*?(<\/script>)/, '$1' + JSON.stringify(payload) + '$2'); return route.fulfill({ response, body: html }); } return route.continue(); } evidence.blocked.push({ method: req.method(), origin: url.origin, path: url.pathname }); if (url.origin === 'https://form.jotform.com') { evidence.jotformAttempts.push({ method: req.method(), url: url.href }); return route.fulfill({ contentType: 'text/html', body: 'Local fixture' }); } return route.abort(); }); }; if (!process.argv.includes('--portal-only')) { for (const width of widths) { for (const target of routes.filter((r) => r.drawer)) { const context = await browser.newContext({ viewport: { width, height: 844 }, serviceWorkers: 'block', reducedMotion: 'reduce' }); await guard(context); const page = await context.newPage(); await page.clock.install({ time: new Date('2026-10-29T12:00:00Z') }); await page.clock.pauseAt(new Date('2026-10-29T12:00:01Z')); await page.goto(origin + target.route, { waitUntil: 'domcontentloaded' }); const dialog = page.locator('[data-service-inquiry-drawer]'); const frame = dialog.locator('iframe'); const before = evidence.jotformAttempts.length; assert.equal(await frame.getAttribute('src'), null); await page.clock.runFor(3999); assert.equal(await dialog.evaluate((d) => d.open), false); await page.clock.runFor(100); assert.equal(await dialog.evaluate((d) => d.open), true); assert.equal(await frame.getAttribute('src'), expectedUrl(target.locale)); await page.waitForFunction(() => document.querySelector('iframe[data-jotform-iframe-frame]')?.src.includes('consultation')); assert.equal(await page.locator('[data-service-inquiry-trigger]').count(), 1); const heading = await dialog.locator('h2').textContent(); assert.ok(target.locale === 'es' ? /Conozca|preguntas/.test(heading) : /Explore|Questions/.test(heading)); assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1)); await page.screenshot({ path: path.join(output, target.screenshot + '-' + width + '.png'), fullPage: true }); evidence.screenshots.push(target.screenshot + '-' + width + '.png'); await page.keyboard.press('Escape'); await page.clock.runFor(100); assert.equal(await dialog.evaluate((d) => d.open), false); const expiry = await page.evaluate((k) => Number(localStorage.getItem(k)), key); const now = await page.evaluate(() => Date.now()); assert.ok(expiry > now && expiry <= now + duration); await page.clock.runFor(10000); await page.locator('[data-service-inquiry-trigger]').focus(); await page.keyboard.press('Enter'); await page.clock.runFor(100); assert.equal(await dialog.evaluate((d) => d.open), true); assert.equal(await frame.count(), 1); await page.locator('[data-service-inquiry-close]').click(); await page.clock.runFor(100); assert.equal(await page.evaluate(() => document.activeElement?.hasAttribute('data-service-inquiry-trigger')), true); const renewed = await page.evaluate((k) => Number(localStorage.getItem(k)), key); assert.ok(renewed > expiry); assert.ok(evidence.jotformAttempts.length <= before + 1); evidence.checks++; await context.close(); } } // Scroll wins, suppression crosses locale/service navigation, manual opening bypasses it. const context = await browser.newContext({ serviceWorkers: 'block', reducedMotion: 'reduce' }); await guard(context); const page = await context.newPage(); await page.clock.install({ time: new Date('2026-10-29T12:00:00Z') }); await page.clock.pauseAt(new Date('2026-10-29T12:00:01Z')); await page.goto(origin + '/aba-therapy', { waitUntil: 'domcontentloaded' }); await page.evaluate(() => scrollTo({ top: (document.documentElement.scrollHeight - innerHeight) * .6, behavior: 'instant' })); await page.clock.runFor(100); assert.equal(await page.locator('dialog').evaluate((d) => d.open), true); await page.keyboard.press('Escape'); await page.clock.runFor(100); await page.goto(origin + '/es/learner-social-club', { waitUntil: 'domcontentloaded' }); await page.clock.runFor(5000); await page.evaluate(() => scrollTo({ top: document.documentElement.scrollHeight, behavior: 'instant' })); await page.clock.runFor(100); assert.equal(await page.locator('dialog').evaluate((d) => d.open), false); assert.equal(await page.locator('dialog iframe').getAttribute('src'), null); await page.locator('[data-service-inquiry-trigger]').click(); await page.clock.runFor(100); assert.equal(await page.locator('dialog').evaluate((d) => d.open), true); await page.keyboard.press('Escape'); await page.clock.runFor(100); // A second page-load initialization disposes previous listeners without duplicating activation. await page.evaluate(() => document.dispatchEvent(new Event('astro:page-load'))); await page.locator('[data-service-inquiry-trigger]').click(); await page.clock.runFor(100); assert.equal(await page.locator('dialog iframe').count(), 1); evidence.checks += 2; await context.close(); for (const preference of ['expired', 'invalid', 'denied', 'editing', 'short', 'other-modal']) { const ctx = await browser.newContext({ serviceWorkers: 'block', reducedMotion: 'reduce' }); await guard(ctx); await ctx.addInitScript(({ preference, key }) => { if (preference === 'expired') localStorage.setItem(key, '1'); if (preference === 'invalid') localStorage.setItem(key, 'broken'); if (preference === 'denied') Object.defineProperty(window, 'localStorage', { get() { throw new Error('Denied'); } }); }, { preference, key }); const p = await ctx.newPage(); await p.clock.install({ time: new Date('2026-10-29T12:00:00Z') }); await p.clock.pauseAt(new Date('2026-10-29T12:00:01Z')); await p.goto(origin + '/aba-therapy', { waitUntil: 'domcontentloaded' }); if (preference === 'editing') await p.evaluate(() => { const field = document.createElement('input'); document.body.prepend(field); field.focus(); }); if (preference === 'other-modal') await p.evaluate(() => { const d = document.createElement('dialog'); document.body.append(d); d.showModal(); }); if (preference === 'short') { await p.evaluate(() => { document.querySelectorAll('main > :not([data-service-inquiry-drawer]), header, footer').forEach((e) => e instanceof HTMLElement && (e.style.display = 'none')); }); await p.clock.runFor(100); assert.equal(await p.locator('[data-service-inquiry-drawer]').evaluate((d) => d.open), false); } await p.clock.runFor(4100); assert.equal(await p.locator('[data-service-inquiry-drawer]').evaluate((d) => d.open), !['editing', 'other-modal'].includes(preference), preference); evidence.checks++; await ctx.close(); } const backContext = await browser.newContext({ serviceWorkers: 'block', reducedMotion: 'reduce' }); await guard(backContext); const backPage = await backContext.newPage(); await backPage.goto(origin + '/aba-therapy', { waitUntil: 'domcontentloaded' }); await backPage.evaluate(() => { window.dispatchEvent(new PageTransitionEvent('pagehide', { persisted: true })); window.dispatchEvent(new PageTransitionEvent('pageshow', { persisted: true })); }); assert.equal(await backPage.evaluate((storageKey) => localStorage.getItem(storageKey), key), null); await backPage.locator('[data-service-inquiry-trigger]').click(); assert.equal(await backPage.locator('dialog iframe').getAttribute('src'), expectedUrl('en')); evidence.checks++; await backContext.close(); } // Actual portal UI with synthetic encrypted response fixtures, never real private source. for (const width of widths) { const ctx = await browser.newContext({ viewport: { width, height: 844 }, serviceWorkers: 'block' }); await guard(ctx, true); const p = await ctx.newPage(); await p.goto(origin + '/employee-portal'); assert.equal(await p.locator('meta[name="robots"]').getAttribute('content'), 'noindex,nofollow'); assert.equal(await p.locator('[data-portal-content]').isVisible(), false); const input = p.locator('[data-portal-code]'); await input.fill('synthetic-incorrect'); await input.press('Enter'); await p.waitForFunction(() => document.querySelector('[data-portal-feedback]')?.textContent === 'Invalid Code'); assert.equal(await p.locator('[data-portal-content]').textContent(), ''); await input.fill(staffCode); await input.press('Enter'); await p.locator('[data-portal-content]').waitFor({ state: 'visible' }); assert.match(await p.locator('[data-portal-content]').textContent(), /Synthetic Staff/); assert.doesNotMatch(await p.locator('[data-portal-content]').textContent(), /Management/); assert.equal(await p.evaluate(() => window.portalUnsafe), undefined); assert.equal(await p.locator('[data-portal-content] img, [data-portal-content] script').count(), 0); assert.equal(await p.evaluate(() => document.activeElement?.hasAttribute('data-portal-content')), true); assert.equal(await input.inputValue(), ''); assert.ok(await p.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1)); await p.screenshot({ path: path.join(output, 'portal-synthetic-' + width + '.png'), fullPage: true }); evidence.screenshots.push('portal-synthetic-' + width + '.png'); await p.reload(); assert.equal(await p.locator('[data-portal-content]').isVisible(), false); await input.fill(managementCode); await input.press('Enter'); await p.locator('[data-portal-content]').waitFor({ state: 'visible' }); assert.match(await p.locator('[data-portal-content]').textContent(), /Synthetic Management/); assert.doesNotMatch(await p.locator('[data-portal-content]').textContent(), /Staff fixture/); evidence.checks++; await ctx.close(); } for (const js of [false, true]) { const ctx = await browser.newContext({ javaScriptEnabled: js, serviceWorkers: 'block' }); await guard(ctx); const p = await ctx.newPage(); await p.goto(origin + '/employee-portal'); assert.equal(await p.locator('[data-portal-code]').isDisabled(), true); assert.equal(await p.locator('[data-portal-content]').isVisible(), false); if (!js) assert.ok(await p.locator('noscript').last().isVisible()); evidence.checks++; await ctx.close(); } assert.equal(evidence.blocked.filter((r) => !['GET','HEAD'].includes(r.method)).length, 0); evidence.status = 'passed'; } catch (error) { evidence.error = error instanceof Error ? error.message : String(error); throw error; } finally { await fs.writeFile(path.join(output, 'evidence.json'), JSON.stringify(evidence, null, 2)); if (preview && preview.exitCode === null) { preview.kill('SIGTERM'); await Promise.race([new Promise((resolve) => preview.once('exit', resolve)), delay(3000)]); if (preview.exitCode === null) preview.kill('SIGKILL'); } await browser?.close(); console.log(JSON.stringify({ ...evidence, artifactDirectory: output }, null, 2)); }