Ask a parked Navara globe for no frames and guard parked engines in the switch gate

The Navara look stopped requesting frames once its globe is parked. scripts/qa-app-once.mjs now fails if anything moves a parked engine's camera or asks it to draw (its own resume aside).
This commit is contained in:
German Khokhlov committed 2026-11-03 19:54:45 +04:00
1 parent 40a81c58e6
commit f2117a98f2
2 files changed
+59 -3

No files matched your search

+48
View File
@@ -166,9 +166,51 @@ try {
report.uiBefore = uiBefore;
const sequence = ['navara', 'cesium', 'navara', 'cesium', 'navara', 'cesium'];
// Dev guard: once an engine is parked, nothing may move its camera or
// ask it to draw until it is attached again (its own resume aside).
await page.evaluate(() => {
window.__qaParkedCalls = [];
window.__qaWatchParked = (engine) => {
if (!engine || engine.__qaWatched) return;
engine.__qaWatched = true;
const watch = (owner, names, label) => {
for (const name of names) {
const original = owner[name];
if (typeof original !== 'function') continue;
owner[name] = function (...args) {
const parked = window.__godsEyeView?.engine !== engine;
const resume = name === 'request' && args[0] === 'engine-resume';
if (parked && !resume && !window.__qaSwitching)
window.__qaParkedCalls.push({
call: `${engine.kind}.${label}.${name}`,
reason: typeof args[0] === 'string' ? args[0] : null,
stack: new Error().stack.split('\n').slice(2, 6).join(' | '),
});
return original.apply(this, args);
};
}
};
watch(
engine.camera,
['setView', 'flyTo', 'lookAt', 'flyToBoundingSphere', 'release'],
'camera',
);
watch(engine.render, ['request', 'setContinuous'], 'render');
};
window.__qaWatchParked(window.__godsEyeView.engine);
});
for (const kind of sequence) {
const started = Date.now();
// The switch itself parks and resumes engines; only the time an engine
// sits parked is watched.
await page.evaluate(() => {
window.__qaSwitching = true;
});
await switchEngine(page, kind);
await page.evaluate(() => {
window.__qaSwitching = false;
window.__qaWatchParked(window.__godsEyeView.engine);
});
const state = await readSession(page);
const ui = await readUi(page);
if (kind === 'navara')
@@ -251,6 +293,12 @@ try {
'each switch detaches once and attaches once',
after.counters,
);
report.parkedEngineCalls = await page.evaluate(() => window.__qaParkedCalls);
check(
report.parkedEngineCalls.length === 0,
'a parked engine had its camera moved or a frame requested',
report.parkedEngineCalls,
);
check(
after.counters?.applications === 1,
'the application must be created once',
+11 -3
View File
@@ -114,6 +114,8 @@ export async function createNavaraGlobe({
let look;
let removeLook = null;
let removePostSampling = null;
// Parked for a switch back: its render loop is off (setRenderLoop).
let parked = false;
try {
view = new ThreeView(navaraViewOptions({ container, canvas, pixelRatio }));
const plugin = new DefaultPlugin();
@@ -165,7 +167,9 @@ export async function createNavaraGlobe({
camera.moveEnd.addEventListener(() => {
moving = false;
readGround();
engine.render.request('navara-look');
// A parked globe (setRenderLoop(false)) draws nothing: its camera
// settling asks for no frame.
if (!parked) engine.render.request('navara-look');
}),
// After the engine's camera sync: before the first frame the camera
// has no position yet (camera.height() throws).
@@ -188,7 +192,8 @@ export async function createNavaraGlobe({
ground,
placed ? lookPlace : null,
landscape,
)
) &&
!parked
)
engine.render.request('navara-look');
}),
@@ -219,7 +224,10 @@ export async function createNavaraGlobe({
look.resetDaylight();
engine.render.request('restored-daylight');
},
setRenderLoop: (enabled) => setRenderLoopEnabled(view, enabled),
setRenderLoop: (enabled) => {
parked = !enabled;
setRenderLoopEnabled(view, enabled);
},
destroy() {
if (destroyed) return;
destroyed = true;