import test from 'node:test'; import assert from 'node:assert/strict'; import { createServer } from 'node:http'; import { existsSync } from 'node:fs'; import { chromium } from 'playwright'; import { compile } from 'sass'; import { loadConfig } from '../server/config.mjs'; import { createBrowserChecks } from '../server/browser-checks.mjs'; const available = existsSync('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome') || existsSync(chromium.executablePath()); test('real browser journey blocks writes, applies reduced motion and handles night-time empty data', { skip: !available }, async () => { let writes = 0, observedMotion = null; const css = compile('src/styles.scss').css; const fixture = createServer((req, res) => { const url = new URL(req.url, 'http://localhost'); if (req.method !== 'GET') { writes++; res.end('write'); return; } if (url.pathname === '/api/board') { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ departures: [] })); return; } if (url.pathname === '/motion-report') { observedMotion = url.searchParams.get('motion'); res.end('ok'); return; } res.setHeader('Content-Type', 'text/html'); res.end(`

Test stop

Test
`); }); await new Promise((resolve, reject) => { fixture.once('error', reject); fixture.listen(0, '127.0.0.1', resolve); }); const config = loadConfig({ STATUS_SCENARIO_TIMEOUT_MS: '2000' }); const browser = createBrowserChecks(config); try { const result = await browser.run({ type: 'board', baseUrl: `http://127.0.0.1:${fixture.address().port}`, cookie: null }, { cityId: 1, stopId: 1 }); assert.equal(result.ok, true); assert.equal(writes, 0); assert.equal(observedMotion, 'none'); } finally { await browser.close(); fixture.closeIdleConnections(); await new Promise(resolve => fixture.close(resolve)); } }); test('paired board browser uses real cookies while writes and requests to another origin are blocked', { skip: !available }, async () => { const cookie = 'ridebus_board_device=test-session-value'; let authenticatedReads = 0, unauthenticatedReads = 0, writes = 0, otherOriginRequests = 0; const otherOrigin = createServer((_req, res) => { otherOriginRequests++; res.end('unexpected'); }); await new Promise(resolve => otherOrigin.listen(0, '127.0.0.1', resolve)); const fixture = createServer((req, res) => { if (req.method !== 'GET') { writes++; res.end('write'); return; } if (req.url.startsWith('/api/')) { if (req.headers.cookie !== cookie) { unauthenticatedReads++; res.writeHead(401); res.end('{}'); return; } authenticatedReads++; res.setHeader('Content-Type', 'application/json'); res.end('{}'); return; } res.setHeader('Content-Type', 'text/html'); res.end(`
Connecting
`); }); await new Promise(resolve => fixture.listen(0, '127.0.0.1', resolve)); const browser = createBrowserChecks(loadConfig({ STATUS_SCENARIO_TIMEOUT_MS: '3000' })); try { const result = await browser.run({ type: 'board', baseUrl: `http://127.0.0.1:${fixture.address().port}`, cookie }, { cityId: 1, stopId: 28 }); assert.equal(result.ok, true); assert.equal(authenticatedReads, 2); assert.equal(unauthenticatedReads, 0); assert.equal(writes, 0); assert.equal(otherOriginRequests, 0); } finally { await browser.close(); fixture.closeAllConnections(); otherOrigin.closeAllConnections(); await Promise.all([new Promise(resolve => fixture.close(resolve)), new Promise(resolve => otherOrigin.close(resolve))]); } });