mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
187 lines
5.9 KiB
JavaScript
187 lines
5.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { bindDisplayControls } from './displayControls.js';
|
|
|
|
function element(value = '') {
|
|
const el = new EventTarget();
|
|
el.value = value;
|
|
el.dataset = {};
|
|
return el;
|
|
}
|
|
|
|
test('sonar on/off control cannot fire after disposal', () => {
|
|
const sonarButton = element();
|
|
const calls = [];
|
|
const control = bindDisplayControls({
|
|
elements: { sonarButton },
|
|
actions: { toggleSonar: () => calls.push('toggle') },
|
|
});
|
|
sonarButton.dispatchEvent(new Event('click'));
|
|
control.destroy();
|
|
sonarButton.dispatchEvent(new Event('click'));
|
|
assert.deepEqual(calls, ['toggle']);
|
|
});
|
|
|
|
test('controls read current values without preventing native input behavior', () => {
|
|
const bloomSlider = element('24');
|
|
const hudLayout = element('tactical');
|
|
const calls = [];
|
|
const control = bindDisplayControls({
|
|
elements: { bloomSlider, hudLayout },
|
|
actions: {
|
|
setBloomIntensity: (value) => calls.push(value),
|
|
setHudLayout: (value) => calls.push(value),
|
|
},
|
|
});
|
|
const event = new Event('input', { cancelable: true });
|
|
bloomSlider.dispatchEvent(event);
|
|
bloomSlider.value = '37';
|
|
bloomSlider.dispatchEvent(new Event('input'));
|
|
hudLayout.value = 'minimal';
|
|
hudLayout.dispatchEvent(new Event('change'));
|
|
assert.deepEqual(calls, [24, 37, 'minimal']);
|
|
assert.equal(event.defaultPrevented, false);
|
|
control.destroy();
|
|
});
|
|
|
|
test('destroyed and replaced controls cannot issue stale actions', () => {
|
|
const bloomButton = element();
|
|
let oldCalls = 0;
|
|
let newCalls = 0;
|
|
const first = bindDisplayControls({
|
|
elements: { bloomButton },
|
|
actions: { toggleBloom: () => oldCalls++ },
|
|
});
|
|
bloomButton.dispatchEvent(new Event('click'));
|
|
first.destroy();
|
|
const second = bindDisplayControls({
|
|
elements: { bloomButton },
|
|
actions: { toggleBloom: () => newCalls++ },
|
|
});
|
|
first.destroy();
|
|
bloomButton.dispatchEvent(new Event('click'));
|
|
assert.equal(oldCalls, 1);
|
|
assert.equal(newCalls, 1);
|
|
second.destroy();
|
|
bloomButton.dispatchEvent(new Event('click'));
|
|
assert.equal(newCalls, 1);
|
|
});
|
|
|
|
test('the Cyber sonar control is an optional owned display action', () => {
|
|
const sonarButton = element();
|
|
const sonarRingsSlider = element('9');
|
|
const sonarRangeSlider = element('110');
|
|
const sonarIntensitySlider = element('65');
|
|
const sonarOpacitySlider = element('84');
|
|
const sonarSectorSlider = element('32');
|
|
const calls = [];
|
|
const control = bindDisplayControls({
|
|
elements: {
|
|
sonarButton,
|
|
sonarRingsSlider,
|
|
sonarRangeSlider,
|
|
sonarIntensitySlider,
|
|
sonarOpacitySlider,
|
|
sonarSectorSlider,
|
|
},
|
|
actions: {
|
|
toggleSonar: () => calls.push('toggle'),
|
|
setSonarRings: (value) => calls.push(['rings', value]),
|
|
setSonarRange: (value) => calls.push(['range', value]),
|
|
setSonarIntensity: (value) => calls.push(['intensity', value]),
|
|
setSonarOpacity: (value) => calls.push(['opacity', value]),
|
|
setSonarSector: (value) => calls.push(['sector', value]),
|
|
},
|
|
});
|
|
sonarButton.dispatchEvent(new Event('click'));
|
|
sonarRingsSlider.dispatchEvent(new Event('input'));
|
|
sonarRangeSlider.dispatchEvent(new Event('input'));
|
|
sonarIntensitySlider.dispatchEvent(new Event('input'));
|
|
sonarOpacitySlider.dispatchEvent(new Event('input'));
|
|
sonarSectorSlider.dispatchEvent(new Event('input'));
|
|
assert.deepEqual(calls, [
|
|
'toggle',
|
|
['rings', 9],
|
|
['range', 110],
|
|
['intensity', 65],
|
|
['opacity', 84],
|
|
['sector', 32],
|
|
]);
|
|
control.destroy();
|
|
sonarButton.dispatchEvent(new Event('click'));
|
|
assert.equal(calls.length, 6);
|
|
});
|
|
|
|
test('style, allocation and model choices retain their current data attributes', () => {
|
|
const style = element();
|
|
const allocation = element();
|
|
const mode = element();
|
|
style.dataset.style = 'thermal';
|
|
allocation.dataset.allocation = 'balanced';
|
|
mode.dataset.mode = 'all';
|
|
const calls = [];
|
|
const control = bindDisplayControls({
|
|
elements: {
|
|
styleButtons: [style],
|
|
allocationButtons: [allocation],
|
|
modelModeButtons: [mode],
|
|
},
|
|
actions: {
|
|
setStyle: (value) => calls.push(value),
|
|
setAllocation: (value) => calls.push(value),
|
|
setModelsMode: (value) => calls.push(value),
|
|
},
|
|
});
|
|
for (const el of [style, allocation, mode])
|
|
el.dispatchEvent(new Event('click'));
|
|
mode.dataset.mode = 'unknown';
|
|
mode.dispatchEvent(new Event('click'));
|
|
assert.deepEqual(calls, ['thermal', 'balanced', 'all', 'proximity']);
|
|
control.destroy();
|
|
});
|
|
|
|
test('optional controls are absent safely and subscriptions stay instance-owned', () => {
|
|
const calls = [];
|
|
const a = element();
|
|
const b = element();
|
|
const one = bindDisplayControls({
|
|
elements: { fadeSlider: null, outsideOpacitySlider: a },
|
|
actions: { setOutsideOpacity: () => calls.push('a') },
|
|
});
|
|
const two = bindDisplayControls({
|
|
elements: { fadeSlider: b },
|
|
actions: { setFade: () => calls.push('b') },
|
|
});
|
|
one.destroy();
|
|
a.dispatchEvent(new Event('input'));
|
|
b.dispatchEvent(new Event('input'));
|
|
assert.deepEqual(calls, ['b']);
|
|
two.destroy();
|
|
});
|
|
|
|
test('the native Scope checkbox reads checked state on change and disposes its listener', () => {
|
|
const scopeToggle = element();
|
|
scopeToggle.checked = true;
|
|
const scopeFeatherSlider = element('200');
|
|
const calls = [];
|
|
const controls = bindDisplayControls({
|
|
elements: { scopeToggle, scopeFeatherSlider },
|
|
actions: {
|
|
setScopeEnabled: (value) => calls.push(['enabled', value]),
|
|
setScopeFeather: (value) => calls.push(['feather', value]),
|
|
},
|
|
});
|
|
scopeToggle.checked = false;
|
|
scopeToggle.dispatchEvent(new Event('change'));
|
|
scopeToggle.checked = true;
|
|
scopeToggle.dispatchEvent(new Event('change'));
|
|
scopeFeatherSlider.dispatchEvent(new Event('input'));
|
|
controls.destroy();
|
|
scopeToggle.dispatchEvent(new Event('change'));
|
|
assert.deepEqual(calls, [
|
|
['enabled', false],
|
|
['enabled', true],
|
|
['feather', 200],
|
|
]);
|
|
});
|