Files
gods-eye-view/scripts/qa-traffic-navigation.mjs

126 lines
4.4 KiB
JavaScript

#!/usr/bin/env node
// Deterministic city-navigation exercise; road/flow responses are fixtures.
import assert from 'node:assert/strict';
import puppeteer from 'puppeteer';
import { trafficFixtureResponse } from './traffic-fixtures.mjs';
const args = process.argv.slice(2);
const url = args[args.indexOf('--url') + 1] || 'http://localhost:4173';
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const browser = await puppeteer.launch({
headless: true,
protocolTimeout: 120000,
args: [
'--no-sandbox',
'--disable-dev-shm-usage',
'--use-gl=angle',
'--use-angle=swiftshader',
'--disable-background-timer-throttling',
],
});
try {
for (const cctv of [false, true]) {
const page = await browser.newPage();
const errors = [];
let londonRequests = 0;
page.on('pageerror', (error) => errors.push(error.message));
page.on('console', (message) => {
if (message.text().includes('[Data:Traffic]'))
console.log(message.text());
});
await page.setViewport({ width: 1280, height: 800 });
await page.setRequestInterception(true);
page.on('request', (request) => {
let response = trafficFixtureResponse(request);
const query = new URLSearchParams(request.postData()).get('data') || '';
if (query.includes('highway') && query.includes('(51.')) {
londonRequests++;
if (londonRequests === 1)
response = { status: 504, body: 'Temporary road source timeout' };
}
return response ? request.respond(response) : request.continue();
});
await page.goto(`${url}/?welcome=0`, { waitUntil: 'domcontentloaded' });
await page.waitForFunction(() => window.__godsEyeView?.dataManager, {
timeout: 60000,
});
await sleep(5000);
await page.keyboard.press('Escape');
await page.evaluate(async (withCctv) => {
const { viewer, dataManager } = window.__godsEyeView;
const C = await import('/node_modules/.vite/deps/cesium.js');
for (const id of ['satellites', 'flights', 'military'])
await dataManager.setEnabled(id, false);
viewer.camera.cancelFlight();
viewer.camera.setView({
destination: C.Cartesian3.fromDegrees(-97.744, 30.267, 3200),
orientation: { heading: 0, pitch: -Math.PI / 2, roll: 0 },
});
await dataManager.setEnabled('traffic', true);
if (withCctv) await dataManager.setEnabled('cctv', true);
}, cctv);
const ready = () => {
const stats = window.__godsEyeView.dataManager.layers
.get('traffic')
.module.getStats();
return stats.count > 0 && !stats.loading;
};
try {
await page.waitForFunction(ready, { timeout: 45000 });
} catch (error) {
console.log(
'Traffic timeout state',
await page.evaluate(() => {
const { viewer, dataManager } = window.__godsEyeView;
return {
stats: dataManager.layers.get('traffic').module.getStats(),
camera: viewer.camera.positionCartographic,
};
}),
);
throw error;
}
await sleep(2500);
await page.evaluate(async () => {
const { viewer } = window.__godsEyeView;
const C = await import('/node_modules/.vite/deps/cesium.js');
viewer.camera.flyTo({
destination: C.Cartesian3.fromDegrees(-0.1276, 51.5072, 3200),
orientation: { heading: 0, pitch: -Math.PI / 2, roll: 0 },
duration: 4,
});
});
const deadline = Date.now() + 45000;
while (londonRequests < 2 && Date.now() < deadline) await sleep(500);
assert.ok(
londonRequests >= 2,
'London must recover its failed request without a toggle',
);
await page.waitForFunction(ready, { timeout: 45000 });
const stats = await page.evaluate(() =>
window.__godsEyeView.dataManager.layers.get('traffic').module.getStats(),
);
assert.equal(stats.error, null);
assert.deepEqual(errors, []);
console.log(
'PASS: Austin → London, first destination request fails then recovers',
{ cctv, londonRequests, count: stats.count },
);
await page.evaluate(() =>
window.__godsEyeView.dataManager.setEnabled('traffic', false),
);
assert.equal(
await page.evaluate(
() =>
window.__godsEyeView.dataManager.layers
.get('traffic')
.module.getStats().loading,
),
false,
);
await page.close();
}
} finally {
await browser.close();
}