mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
217 lines
8.1 KiB
JavaScript
217 lines
8.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import puppeteer from 'puppeteer';
|
|
import { blockPaidQaMaps } from './qa-map-policy.mjs';
|
|
|
|
const url = new URL(process.argv[2]);
|
|
if (
|
|
!['localhost', '127.0.0.1'].includes(url.hostname) ||
|
|
['', '4173', '4185', '4186', '4187', '4188', '4189', '4194'].includes(
|
|
url.port,
|
|
)
|
|
)
|
|
throw new Error('Supply an unreserved local keyless preview URL');
|
|
const military = process.argv.includes('--military');
|
|
const layerId = military ? 'military' : 'flights';
|
|
const aircraftId = military ? 'aaa052' : '71be26';
|
|
url.search = '?engine=navara&welcome=0';
|
|
url.hash =
|
|
'v=2&lat=40.2539&lon=-125.5779&alt=21130&heading=360&pitch=-35&map=sentinel2' +
|
|
(military ? '&l=m&lo=f.e.1_f.u.aaa052' : '&l=f&lo=f.e.1_f.t.71be26');
|
|
const browser = await puppeteer.launch({
|
|
headless: true,
|
|
args: ['--use-angle=metal', '--enable-gpu'],
|
|
});
|
|
try {
|
|
const page = await browser.newPage();
|
|
await blockPaidQaMaps(page);
|
|
const errors = [];
|
|
page.on('pageerror', (e) => errors.push(e.message));
|
|
await page.setViewport({ width: 1280, height: 720 });
|
|
await page.evaluateOnNewDocument((layerId, aircraftId) => {
|
|
window.__qaAircraft = {layerId, aircraftId};
|
|
const fetch = window.fetch.bind(window);
|
|
window.__flightPolls = 0;
|
|
const interval = window.setInterval.bind(window);
|
|
window.setInterval = function (callback, delay, ...args) {
|
|
if (typeof callback !== 'function') return interval(callback, delay, ...args);
|
|
const id = interval(function (...values) {
|
|
if (window.__handoff?.timer === id) window.__handoff.ticks++;
|
|
return callback.apply(this, values);
|
|
}, delay, ...args);
|
|
return id;
|
|
};
|
|
window.fetch = (input, options) => {
|
|
const path = new URL(input.url ?? input, document.baseURI).pathname;
|
|
const now = Math.floor(Date.now() / 1000);
|
|
if (path === '/api/flights') {
|
|
if (layerId === 'flights') window.__flightPolls++;
|
|
return Promise.resolve(
|
|
Response.json({
|
|
time: now,
|
|
states: [
|
|
[
|
|
'71be26',
|
|
'GEV123',
|
|
'QA',
|
|
now,
|
|
now,
|
|
-125.5779,
|
|
40.2539,
|
|
9700,
|
|
false,
|
|
200,
|
|
45,
|
|
0,
|
|
null,
|
|
9700,
|
|
null,
|
|
false,
|
|
0,
|
|
],
|
|
],
|
|
}),
|
|
);
|
|
}
|
|
if (path === '/api/military') {
|
|
if (layerId === 'military') window.__flightPolls++;
|
|
return Promise.resolve(Response.json({now: Date.now(), ac: [{
|
|
hex: 'aaa052', flight: 'GEVMIL', lon: -125.5779, lat: 40.2539,
|
|
alt_geom: 31825, alt_baro: 31825, gs: 389, track: 45,
|
|
seen: 0, seen_pos: 0, dbFlags: 1, type: 'adsb_icao',
|
|
}]}));
|
|
}
|
|
if (path === '/api/flights/track')
|
|
return Promise.resolve(Response.json({ path: [] }));
|
|
if (path.startsWith('/api/flights/') || path.startsWith('/api/openai/'))
|
|
return Promise.resolve(Response.json({}));
|
|
return fetch(input, options);
|
|
};
|
|
}, layerId, aircraftId);
|
|
await page.goto(url.href, { waitUntil: 'domcontentloaded' });
|
|
const ready = (kind) =>
|
|
page.waitForFunction(
|
|
(engine) =>
|
|
window.__godsEyeView?.engine.kind === engine &&
|
|
!document.querySelector('#globe-engine')?.disabled &&
|
|
document.querySelector('#loading-screen.hidden') &&
|
|
!document.querySelector('.engine-switch-frame'),
|
|
{ timeout: 90000 },
|
|
kind,
|
|
);
|
|
await ready('navara');
|
|
await page.evaluate(
|
|
() => window.__godsEyeView.styleManager.initialRestorePromise,
|
|
);
|
|
await page.waitForSelector('#cockpit-entry', { visible: true });
|
|
await page.click('#cockpit-entry');
|
|
await page.waitForFunction(
|
|
() => window.__godsEyeView.styleManager.getCockpitState().active,
|
|
);
|
|
await page.evaluate(() => {
|
|
const { dataManager, styleManager, tileset } = window.__godsEyeView;
|
|
if (window.__GOOGLE_MAPS_API_KEY__ || tileset)
|
|
throw Error('Keyless preview required');
|
|
styleManager.cockpitView.setVisionMode('thermal');
|
|
const entry = dataManager.layers.get(window.__qaAircraft.layerId);
|
|
window.__handoff = {
|
|
dataManager,
|
|
entry,
|
|
row: document.querySelector(`[data-layer-id="${window.__qaAircraft.layerId}"] .data-toggle-btn`),
|
|
timer: entry.intervalId,
|
|
ticks: 0,
|
|
model: entry.module,
|
|
pollCount: window.__flightPolls,
|
|
timestamp: entry.module.getStats().lastUpdate,
|
|
};
|
|
});
|
|
// Refuse the first Cesium canvas. The application must roll back with the
|
|
// original aircraft still in the cockpit, then allow an ordinary retry.
|
|
await page.evaluate(() => {
|
|
const original = HTMLCanvasElement.prototype.getContext;
|
|
HTMLCanvasElement.prototype.getContext = function (type, ...args) {
|
|
if (String(type).includes('webgl')) {
|
|
window.__refusedContext = true;
|
|
throw new Error('QA renderer startup failure');
|
|
}
|
|
return original.call(this, type, ...args);
|
|
};
|
|
window.__restoreContext = () => {
|
|
HTMLCanvasElement.prototype.getContext = original;
|
|
};
|
|
});
|
|
await page.select('#globe-engine', 'cesium');
|
|
await page.waitForFunction(() => window.__refusedContext === true);
|
|
await ready('navara');
|
|
assert.ok(await page.evaluate(() => {
|
|
window.__restoreContext();
|
|
const {dataManager, styleManager} = window.__godsEyeView;
|
|
return new URL(location.href).searchParams.get('engine') === 'navara' &&
|
|
dataManager === window.__handoff.dataManager &&
|
|
dataManager.layers.get(window.__qaAircraft.layerId) === window.__handoff.entry &&
|
|
styleManager.getCockpitState().active &&
|
|
styleManager.getAircraftTrackingTarget()?.id === window.__qaAircraft.aircraftId;
|
|
}), 'a failed scene must leave the live session usable');
|
|
console.log('PASS failed renderer rolled back to the same flight and cockpit');
|
|
|
|
for (const kind of ['cesium', 'navara']) {
|
|
await page.select('#globe-engine', kind);
|
|
await ready(kind);
|
|
const result = await page.evaluate(() => {
|
|
const { dataManager, engine, styleManager } = window.__godsEyeView;
|
|
const before = window.__handoff;
|
|
const entry = dataManager.layers.get(window.__qaAircraft.layerId);
|
|
const cockpit = styleManager.getCockpitState();
|
|
return {
|
|
sameOwner:
|
|
before.dataManager === dataManager &&
|
|
before.entry === entry &&
|
|
before.model === entry.module,
|
|
sameRow: Boolean(before.row) &&
|
|
before.row === document.querySelector(`[data-layer-id="${window.__qaAircraft.layerId}"] .data-toggle-btn`),
|
|
sameTimer:
|
|
before.timer === entry.intervalId && entry.intervalId != null,
|
|
sourcePolls: window.__flightPolls - before.pollCount,
|
|
timerTicks: before.ticks,
|
|
stamp: entry.module.getStats().lastUpdate,
|
|
initialStamp: before.timestamp,
|
|
id: cockpit.subject?.id,
|
|
active: cockpit.active,
|
|
mode: cockpit.visionMode,
|
|
hud: !document.querySelector('#cockpit-hud').hidden,
|
|
drawn: entry.module.qaDrawn().some((row) => row.id === window.__qaAircraft.aircraftId),
|
|
height: engine.camera.height(),
|
|
};
|
|
});
|
|
assert.ok(
|
|
result.sameOwner &&
|
|
result.sameTimer &&
|
|
result.sameRow &&
|
|
result.active &&
|
|
result.hud &&
|
|
result.drawn,
|
|
JSON.stringify(result),
|
|
);
|
|
assert.equal(result.id, aircraftId);
|
|
assert.equal(result.mode, 'thermal');
|
|
assert.ok(result.sourcePolls <= result.timerTicks, 'switch must not add a source request');
|
|
if (result.timerTicks === 0) {
|
|
assert.equal(result.stamp, result.initialStamp);
|
|
}
|
|
await page.waitForFunction(
|
|
() => Math.abs(window.__godsEyeView.engine.camera.height() - 9700) < 1000,
|
|
);
|
|
console.log(
|
|
`PASS ${kind} cockpit, aircraft, HUD, manager and timer (${result.sourcePolls} polls since entry)`,
|
|
);
|
|
}
|
|
await page.evaluate(() =>
|
|
window.__godsEyeView.styleManager.controlCockpit('exit'),
|
|
);
|
|
await page.waitForFunction(
|
|
() => !window.__godsEyeView.styleManager.getCockpitState().active,
|
|
);
|
|
assert.deepEqual(errors, []);
|
|
} finally {
|
|
await browser.close();
|
|
}
|