Files
gods-eye-view/src/voice/pointerCrop.test.mjs
T
manjunath22466 0343b4495e fix the remaining voice review gaps
keep analyst counts, speech, cards, cancellation, pointer capture, tool schema boundaries, and session lifetime consistent
add the exact Alps fallback and focused regression coverage
2026-10-05 04:37:28 +05:30

350 lines
9.1 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
RealtimeViewport,
pointerCropRect,
renderFreshPointerFrame,
} from './realtimeViewport.js';
test('crop: a square around the pointer, clamped inside the canvas, in buffer pixels', () => {
assert.deepEqual(
pointerCropRect({
x: 750,
y: 475,
cssWidth: 1500,
cssHeight: 950,
pixelWidth: 3000,
pixelHeight: 1900,
}),
{
sx: 988,
sy: 438,
sw: 1024,
sh: 1024,
output: 512,
pointX: 256,
pointY: 256,
},
);
const corner = pointerCropRect({
x: 20,
y: 20,
cssWidth: 1500,
cssHeight: 950,
pixelWidth: 1500,
pixelHeight: 950,
});
assert.equal(corner.sx, 0);
assert.equal(corner.sy, 0);
assert.equal(
corner.pointX,
20,
'the ring still marks the real spot near an edge',
);
assert.equal(
pointerCropRect({
x: 1,
y: 1,
cssWidth: 0,
cssHeight: 0,
pixelWidth: 0,
pixelHeight: 0,
}),
null,
);
assert.equal(
pointerCropRect({
x: Number.NaN,
y: 1,
cssWidth: 100,
cssHeight: 100,
pixelWidth: 100,
pixelHeight: 100,
}),
null,
'non-finite pointer geometry fails closed',
);
assert.equal(
pointerCropRect({
x: 101,
y: 1,
cssWidth: 100,
cssHeight: 100,
pixelWidth: 100,
pixelHeight: 100,
}),
null,
'out-of-canvas pointer geometry fails closed',
);
assert.equal(
pointerCropRect({
x: 120,
y: 100,
cssWidth: 320,
cssHeight: 240,
pixelWidth: 320,
pixelHeight: 240,
}).output,
512,
'the provider image stays 512 px even when the source crop is smaller',
);
});
test('crop: a slow render gets one bounded fresh-frame recovery request', async () => {
const originalDocument = globalThis.document;
let requests = 0;
let listener = null;
try {
globalThis.document = { hidden: false };
const scene = {
postRender: {
addEventListener(next) {
listener = next;
return () => {
if (listener === next) listener = null;
};
},
},
requestRender() {
requests += 1;
if (requests === 2) queueMicrotask(() => listener?.());
},
};
assert.equal(await renderFreshPointerFrame({ scene }), true);
assert.equal(requests, 2, 'only the pointer path retries once');
assert.equal(listener, null, 'the successful listener is removed');
} finally {
globalThis.document = originalDocument;
}
});
test('crop: a hidden document never starts the recovery request', async () => {
const originalDocument = globalThis.document;
let requests = 0;
try {
globalThis.document = { hidden: true };
const scene = {
postRender: { addEventListener: () => () => {} },
requestRender() {
requests += 1;
},
};
assert.equal(await renderFreshPointerFrame({ scene }), false);
assert.equal(requests, 0);
} finally {
globalThis.document = originalDocument;
}
});
function viewportFixture({ capturePointer, capture } = {}) {
const sent = [];
const captures = [];
const state = { clock: 10_000, pointer: null, camera: 'pose-A' };
const channel = { readyState: 'open' };
const viewport = new RealtimeViewport({
readChannel: () => channel,
readPointer: () => state.pointer,
readCameraKey: () => state.camera,
capture: capture || (async () => 'data:image/jpeg;base64,FULL'),
capturePointer:
capturePointer ||
(async (px) => {
captures.push(px);
return {
dataUrl: 'data:image/jpeg;base64,CROP',
rect: { x: 0.25, y: 0.2, w: 0.3, h: 0.5 },
};
}),
now: () => state.clock,
operations: {
sendRealtimeEvent: (event, label) => {
sent.push({ event, label });
return true;
},
},
});
return { viewport, sent, captures, state };
}
const ground = {
fresh: true,
target: 'ground',
at: 'keydown',
screenPx: { x: 400, y: 300 },
capturedAt: 9_000,
cameraKey: 'pose-A',
};
test('crop: sent once per snapshot, only at local/city scale, into the one retained slot', async () => {
const { viewport, sent, captures, state } = viewportFixture();
assert.equal(
await viewport.sendPointerCrop(ground, { viewScale: 'regional' }),
false,
'the scale guard lives in the shared send path',
);
assert.equal(
await viewport.sendPointerCrop(ground),
false,
'no scale, no crop',
);
assert.equal(
await viewport.sendPointerCrop(ground, { viewScale: 'city' }),
true,
);
assert.equal(
await viewport.sendPointerCrop(ground, { viewScale: 'city' }),
false,
'once per snapshot',
);
assert.deepEqual(captures, [{ x: 400, y: 300 }]);
assert.equal(sent[0].label, 'client.pointer_crop');
assert.match(sent[0].event.item.content[0].text, /ring marks the exact spot/);
assert.equal(
sent[0].event.item.content[1].image_url,
'data:image/jpeg;base64,CROP',
);
assert.deepEqual(viewport.retainedFrame, {
kind: 'crop',
rect: { x: 0.25, y: 0.2, w: 0.3, h: 0.5 },
cameraKey: 'pose-A',
});
assert.equal(
await viewport.sendPointerCrop(
{ ...ground, target: 'entity' },
{ viewScale: 'city' },
),
false,
'entities are named, not cropped',
);
state.clock = 60_000;
assert.equal(
await viewport.sendPointerCrop({ ...ground }, { viewScale: 'city' }),
false,
'too old',
);
// Pull: a ground pointer lookup sends the crop, deleting the old image.
state.clock = 10_000;
state.pointer = { ...ground, at: 'speech_start' };
const lookup = {
action: 'get_entity_context',
scope: 'pointer',
selected: null,
pointer: { latitude: 1, longitude: 2 },
scene: { basemap: { viewScale: 'city' } },
};
assert.equal(await viewport.sendVisualContextIfUseful(lookup), true);
assert.equal(
sent.at(-2).event.type,
'conversation.item.delete',
'one retained image at most',
);
assert.equal(sent.at(-1).label, 'client.pointer_crop');
assert.equal(
await viewport.sendVisualContextIfUseful({
...lookup,
selected: { id: 'x' },
}),
false,
);
assert.equal(
await viewport.sendVisualContextIfUseful({
...lookup,
scene: { basemap: { viewScale: 'regional' } },
}),
false,
);
viewport.reset();
assert.equal(viewport.lastPointerCrop, null);
assert.equal(viewport.retainedFrame, null);
});
test('crop: a camera move before or during capture drops it; pixels only name their own pose', async () => {
let release;
const { viewport, sent, state } = viewportFixture({
capturePointer: () =>
new Promise((resolve) => {
release = () =>
resolve({
dataUrl: 'data:image/jpeg;base64,CROP',
rect: { x: 0, y: 0, w: 1, h: 1 },
});
}),
});
state.camera = 'pose-B';
assert.equal(
await viewport.sendPointerCrop(ground, { viewScale: 'local' }),
false,
'moved before capture',
);
state.camera = null;
assert.equal(
await viewport.sendPointerCrop(
{ ...ground, cameraKey: null },
{ viewScale: 'local' },
),
false,
'a missing pose identity fails closed',
);
state.camera = 'pose-A';
const pending = viewport.sendPointerCrop(
{ ...ground },
{ viewScale: 'local' },
);
state.camera = 'pose-B';
release();
assert.equal(await pending, false, 'moved while capturing');
assert.equal(sent.length, 0);
});
test('crop: a snapshot that expires during capture is not published', async () => {
let release;
const { viewport, sent, state } = viewportFixture({
capturePointer: () =>
new Promise((resolve) => {
release = () =>
resolve({
dataUrl: 'data:image/jpeg;base64,CROP',
rect: { x: 0, y: 0, w: 1, h: 1 },
});
}),
});
const pending = viewport.sendPointerCrop(
{ ...ground },
{ viewScale: 'local' },
);
state.clock = 40_000;
release();
assert.equal(await pending, false);
assert.equal(sent.length, 0);
});
test('crop: an older capture that finishes last never replaces the newer image', async () => {
const releases = [];
const { viewport, sent } = viewportFixture({
capturePointer: () =>
new Promise((resolve) =>
releases.push((url) => resolve({ dataUrl: url, rect: null })),
),
});
const first = viewport.sendPointerCrop({ ...ground }, { viewScale: 'local' });
const second = viewport.sendPointerCrop(
{ ...ground },
{ viewScale: 'local' },
);
releases[1]('data:image/jpeg;base64,NEW');
assert.equal(await second, true);
releases[0]('data:image/jpeg;base64,OLD');
assert.equal(await first, false, 'superseded request');
assert.deepEqual(
sent.map((s) => s.event.item?.content?.[1]?.image_url).filter(Boolean),
['data:image/jpeg;base64,NEW'],
);
// A new user turn drops a capture still in flight from the previous one.
const third = viewport.sendPointerCrop({ ...ground }, { viewScale: 'local' });
viewport.beginTurn();
releases[2]('data:image/jpeg;base64,LATE');
assert.equal(await third, false);
});