mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 15:52:21 +00:00
The probe exposes settled() and the first-frame outcome; scripts/qa/ready.mjs waits for drawn frames with the camera at rest and for a pick at the click position, with a deadline and its reason in the error. The strict scenarios use these instead of fixed pauses and loading-screen polling, and the hidden-switch scenario checks how the loading screen was lifted instead of how long it took. Each switch scenario now records a draw ledger per engine and runs a contract monitor; both write to the scenario's evidence file only, with an empty allowlist until browser runs show what differs on purpose.
132 lines
4.3 KiB
JavaScript
132 lines
4.3 KiB
JavaScript
import { whenSettled } from './qa/ready.mjs';
|
|
import { fromDegrees } from '../src/geo/cartesian3.js';
|
|
import sharp from 'sharp';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
createStrict,
|
|
localPreview,
|
|
openPage,
|
|
waitForEngine,
|
|
} from './qa-strict-harness.mjs';
|
|
|
|
const base = localPreview(process.argv[2]);
|
|
base.search = '?engine=navara&welcome=0&look=cinematic';
|
|
base.hash =
|
|
'v=2&lat=28.3326&lon=85.4848&alt=18000&heading=0&pitch=-90&roll=0&map=sentinel2&l=';
|
|
const strict = createStrict({
|
|
origin: base.origin,
|
|
layers: ['bhote-koshi-locator'],
|
|
});
|
|
await strict.run({}, async (b) => {
|
|
const { page: p, errors } = await openPage(b, { shaderErrors: true });
|
|
await p.goto(base.href);
|
|
await waitForEngine(p, 'navara');
|
|
await p.evaluate(async () => {
|
|
const { dataManager } = window.__godsEyeView;
|
|
|
|
window.qaLocator = dataManager.layers.get('bhote-koshi-locator').module;
|
|
window.qaLocator.setParams({ presentation: 'bhote-koshi-path-overview' });
|
|
await dataManager.setEnabled('bhote-koshi-locator', true, {
|
|
origin: 'user',
|
|
});
|
|
});
|
|
for (const kind of ['navara', 'cesium', 'navara']) {
|
|
if ((await p.evaluate(() => window.__godsEyeView.engine.kind)) !== kind) {
|
|
await strict.switchTo(p, kind);
|
|
}
|
|
const { same, stats, params, at } = await p.evaluate(
|
|
(world) => {
|
|
const { engine, dataManager } = window.__godsEyeView,
|
|
mod = dataManager.layers.get('bhote-koshi-locator').module;
|
|
const pos = engine.projector.worldToWindow(world, {}),
|
|
box = engine.host.canvas.getBoundingClientRect();
|
|
return {
|
|
same: mod === window.qaLocator,
|
|
stats: mod.getStats(),
|
|
params: mod.getParams(),
|
|
at: { x: pos.x + box.left, y: pos.y + box.top },
|
|
};
|
|
},
|
|
fromDegrees(85.47741, 28.33299, 1600),
|
|
);
|
|
assert.equal(same, true);
|
|
assert.equal(stats.count, 1);
|
|
assert.equal(params.presentation, 'bhote-koshi-path-overview');
|
|
// Look for the cyan river in a scene crop away from the UI rails.
|
|
await whenSettled(p);
|
|
const crop = async () =>
|
|
sharp(await p.screenshot())
|
|
.extract({ left: 400, top: 320, width: 230, height: 180 })
|
|
.removeAlpha()
|
|
.raw()
|
|
.toBuffer();
|
|
const rendered = await crop();
|
|
await p.evaluate(() =>
|
|
window.qaLocator.setParams({ presentation: 'nepal-context' }),
|
|
);
|
|
await whenSettled(p);
|
|
const baseline = await crop();
|
|
let added = 0;
|
|
for (let i = 0; i < rendered.length; i += 3) {
|
|
const contrast = rendered[i + 1] - rendered[i],
|
|
previous = baseline[i + 1] - baseline[i];
|
|
if (
|
|
rendered[i + 1] > 140 &&
|
|
rendered[i + 2] > 140 &&
|
|
contrast > 35 &&
|
|
contrast - previous > 18
|
|
)
|
|
added++;
|
|
}
|
|
console.log(
|
|
kind,
|
|
stats.coverage,
|
|
'cyan pixels added by the path',
|
|
added,
|
|
at,
|
|
);
|
|
await strict.check(
|
|
p,
|
|
'bhote-koshi-locator',
|
|
'same model; the flood path adds more than 50 cyan pixels to the same scene without it',
|
|
added > 50,
|
|
{ added },
|
|
);
|
|
await p.evaluate(() =>
|
|
window.qaLocator.setParams({ presentation: 'bhote-koshi-path-overview' }),
|
|
);
|
|
}
|
|
await p.evaluate(() => {
|
|
window.qaLocator.setParams({ presentation: 'bhote-koshi-incident-places' });
|
|
window.qaLocator.setParams({ presentation: 'bhote-koshi-city-context' });
|
|
window.qaLocator.setParams({
|
|
presentation: 'bhote-koshi-trigger-record',
|
|
preview: true,
|
|
});
|
|
});
|
|
await whenSettled(p);
|
|
// The last of three quick presentation changes is the one that stays.
|
|
const last = await p.evaluate(() => ({
|
|
params: window.qaLocator.getParams(),
|
|
stats: window.qaLocator.getStats(),
|
|
}));
|
|
await strict.check(
|
|
p,
|
|
'bhote-koshi-locator',
|
|
'the last of three quick presentation changes is the one applied',
|
|
last.params.presentation === 'bhote-koshi-trigger-record' &&
|
|
last.stats.count === 1 &&
|
|
!last.stats.error,
|
|
{ presentation: last.params.presentation, count: last.stats.count },
|
|
);
|
|
await p.evaluate(() =>
|
|
window.__godsEyeView.dataManager.setEnabled('bhote-koshi-locator', false, {
|
|
origin: 'user',
|
|
}),
|
|
);
|
|
assert.deepEqual(errors, []);
|
|
console.log(
|
|
'PASS Nepal locator flood path and presentation retained, trigger and places update; both engines',
|
|
);
|
|
});
|