mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
The panel now renders from the CCTV store, so the meta line is no longer written to a DOM node by _renderCctvState. Assert on presentCctvPanel's meta text instead.
128 lines
3.6 KiB
JavaScript
128 lines
3.6 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import { CctvControls } from './cctvControls.js';
|
|
|
|
function element() {
|
|
const classes = new Set();
|
|
return {
|
|
dataset: {},
|
|
src: '',
|
|
removeAttribute(name) {
|
|
if (name === 'src') this.src = '';
|
|
},
|
|
classList: {
|
|
add(...values) {
|
|
values.forEach((value) => classes.add(value));
|
|
},
|
|
remove(...values) {
|
|
values.forEach((value) => classes.delete(value));
|
|
},
|
|
contains(value) {
|
|
return classes.has(value);
|
|
},
|
|
toggle(value, enabled) {
|
|
if (enabled) classes.add(value);
|
|
else classes.delete(value);
|
|
},
|
|
},
|
|
};
|
|
}
|
|
function fixture(t) {
|
|
const prior = globalThis.Image;
|
|
const requests = [];
|
|
globalThis.Image = class {
|
|
constructor() {
|
|
requests.push(this);
|
|
}
|
|
};
|
|
t.after(() => {
|
|
globalThis.Image = prior;
|
|
});
|
|
const controls = new CctvControls({
|
|
elements: { _cctvFrame: element(), _cctvFrameWrap: element() },
|
|
cctv: {},
|
|
actions: { isEnabled: () => true },
|
|
});
|
|
t.after(() => controls.destroy());
|
|
return { controls, requests };
|
|
}
|
|
|
|
test('a late image completion cannot replace a newer camera preview', (t) => {
|
|
const { controls, requests } = fixture(t);
|
|
controls._queueCctvFrame('first.jpg', 'a', true);
|
|
const stale = requests[0].onload;
|
|
controls._queueCctvFrame('second.jpg', 'b', true);
|
|
assert.equal(requests[0].onload, null);
|
|
requests[1].onload();
|
|
stale();
|
|
assert.equal(controls._frame.src, 'second.jpg');
|
|
assert.equal(controls._frame.cameraId, 'b');
|
|
});
|
|
|
|
test('failed refresh preserves settled pixels, but changing cameras clears them', (t) => {
|
|
const { controls, requests } = fixture(t);
|
|
controls._queueCctvFrame('first.jpg', 'a', true);
|
|
requests[0].onload();
|
|
controls._queueCctvFrame('refresh.jpg', 'a', false);
|
|
requests[1].onerror();
|
|
assert.equal(controls._frame.src, 'first.jpg');
|
|
assert.equal(controls._frame.hasFrame, true);
|
|
controls._queueCctvFrame('other.jpg', 'b', true);
|
|
assert.equal(controls._frame.src, '');
|
|
assert.equal(controls._frame.hasFrame, false);
|
|
});
|
|
|
|
test('destroy invalidates image callbacks and releases each subscription once', (t) => {
|
|
const { controls, requests } = fixture(t);
|
|
let unsubscribed = 0;
|
|
controls.cctv.subscribe = () => () => {
|
|
unsubscribed++;
|
|
};
|
|
controls.connect();
|
|
controls.connect();
|
|
assert.equal(unsubscribed, 1);
|
|
controls._queueCctvFrame('first.jpg', 'a', true);
|
|
const late = requests[0].onload;
|
|
controls.destroy();
|
|
controls.destroy();
|
|
controls.connect();
|
|
late();
|
|
assert.equal(unsubscribed, 2);
|
|
assert.equal(requests[0].onload, null);
|
|
assert.equal(requests[0].onerror, null);
|
|
assert.equal(controls._frame.src, '');
|
|
controls._queueCctvFrame('late.jpg', 'b', true);
|
|
assert.equal(requests.length, 1);
|
|
});
|
|
|
|
test('disposing during camera enable prevents the delayed focus and future clicks', async () => {
|
|
const button = new EventTarget();
|
|
let resolveEnable;
|
|
let enables = 0;
|
|
let focuses = 0;
|
|
const controls = new CctvControls({
|
|
elements: { _cctvPanel: {}, _cctvNextBtn: button },
|
|
cctv: {},
|
|
actions: {
|
|
isEnabled: () => true,
|
|
syncViewport() {},
|
|
toggleEnabled() {
|
|
enables++;
|
|
return new Promise((resolve) => {
|
|
resolveEnable = resolve;
|
|
});
|
|
},
|
|
runExplicitFocus() {
|
|
focuses++;
|
|
},
|
|
},
|
|
});
|
|
button.dispatchEvent(new Event('click'));
|
|
controls.destroy();
|
|
resolveEnable(true);
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
button.dispatchEvent(new Event('click'));
|
|
assert.equal(enables, 1);
|
|
assert.equal(focuses, 0);
|
|
});
|