mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
208 lines
7.6 KiB
JavaScript
208 lines
7.6 KiB
JavaScript
// src/ui/displayPanel.test.mjs — the Display panel renders bloom and sharpen
|
|
// from what VisualSettings publishes, and shows its initial markup before.
|
|
import '../testSupport/registerDom.mjs';
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { createPinia } from 'pinia';
|
|
import { createApp, nextTick } from 'vue';
|
|
import { useDisplayStore } from './stores/display.js';
|
|
import DisplayPanel from './views/panels/DisplayPanel.vue';
|
|
import { VisualSettings } from './visualSettings.js';
|
|
|
|
function fixture(t) {
|
|
document.body.replaceChildren();
|
|
const host = document.body.appendChild(document.createElement('div'));
|
|
const pinia = createPinia();
|
|
const app = createApp(DisplayPanel).use(pinia);
|
|
app.mount(host);
|
|
t.after(() => app.unmount());
|
|
const $ = (id) => document.getElementById(id);
|
|
return { store: useDisplayStore(pinia), $ };
|
|
}
|
|
|
|
/** A VisualSettings over stand-in effects, publishing to `store`. */
|
|
function settings(store) {
|
|
const owner = Object.create(VisualSettings.prototype);
|
|
const effects = {
|
|
bloomEnabled: false,
|
|
sharpenEnabled: false,
|
|
bloomIntensity: 0,
|
|
sharpenIntensity: 0.49,
|
|
applyBloomIntensity(value) {
|
|
this.bloomIntensity = value;
|
|
},
|
|
applySharpenIntensity(value) {
|
|
this.sharpenIntensity = value;
|
|
},
|
|
setBloomEnabled(on) {
|
|
this.bloomEnabled = on;
|
|
},
|
|
setSharpenEnabled(on) {
|
|
this.sharpenEnabled = on;
|
|
},
|
|
syncBloomEnabled() {},
|
|
};
|
|
const shares = [];
|
|
Object.assign(owner, {
|
|
store,
|
|
_visualEffects: effects,
|
|
_sharpenPct: 49,
|
|
services: { governorRequestRender() {} },
|
|
_syncShareState: () => shares.push(true),
|
|
_layoutRightPanels() {},
|
|
});
|
|
return { owner, effects, shares };
|
|
}
|
|
|
|
test('before VisualSettings renders, the panel shows its initial markup', (t) => {
|
|
const { $ } = fixture(t);
|
|
assert.equal($('bloom-toggle').className, 'pp-toggle-btn');
|
|
assert.equal($('bloom-slider-row').className, 'pp-slider-row');
|
|
assert.equal($('bloom-intensity-slider').value, '0');
|
|
assert.equal($('bloom-intensity-value').textContent, '0%');
|
|
assert.equal($('sharpen-intensity-slider').value, '49');
|
|
assert.equal($('sharpen-intensity-value').textContent, '49%');
|
|
});
|
|
|
|
test('bloom and sharpen render their state, slider and readout', async (t) => {
|
|
const { store, $ } = fixture(t);
|
|
const { owner, effects, shares } = settings(store);
|
|
|
|
owner._setBloomEnabled(true);
|
|
owner._setBloomIntensity(140.4);
|
|
await nextTick();
|
|
assert.equal($('bloom-toggle').classList.contains('active'), true);
|
|
assert.equal($('bloom-slider-row').classList.contains('visible'), true);
|
|
assert.equal($('bloom-intensity-slider').value, '140');
|
|
assert.equal($('bloom-intensity-value').textContent, '140%');
|
|
assert.equal(effects.bloomIntensity, 140);
|
|
|
|
owner._setSharpenEnabled(true);
|
|
owner._setSharpenIntensity(130);
|
|
await nextTick();
|
|
assert.equal($('sharpen-toggle').classList.contains('active'), true);
|
|
assert.equal($('sharpen-slider-row').classList.contains('visible'), true);
|
|
assert.equal($('sharpen-intensity-slider').value, '100', 'clamped to 100');
|
|
assert.equal($('sharpen-intensity-value').textContent, '100%');
|
|
assert.equal(effects.sharpenIntensity, 1);
|
|
assert.equal(owner.sharpenIntensityPct, 100);
|
|
assert.ok(shares.length > 0, 'changes reach the share state');
|
|
|
|
owner._setBloomEnabled(false);
|
|
await nextTick();
|
|
assert.equal($('bloom-toggle').classList.contains('active'), false);
|
|
assert.equal($('bloom-slider-row').classList.contains('visible'), false);
|
|
assert.equal($('bloom-intensity-value').textContent, '140%', 'the amount stays');
|
|
});
|
|
|
|
test('a publish never rewrites a slider the user is dragging', async (t) => {
|
|
const { store, $ } = fixture(t);
|
|
const { owner } = settings(store);
|
|
owner._setSharpenIntensity(30);
|
|
await nextTick();
|
|
const slider = $('sharpen-intensity-slider');
|
|
let writes = 0;
|
|
const descriptor = Object.getOwnPropertyDescriptor(
|
|
Object.getPrototypeOf(slider),
|
|
'value',
|
|
);
|
|
Object.defineProperty(slider, 'value', {
|
|
get: () => descriptor.get.call(slider),
|
|
set: (next) => {
|
|
writes++;
|
|
descriptor.set.call(slider, next);
|
|
},
|
|
});
|
|
// The input handler applies the dragged value; the publish that follows
|
|
// carries the same value, so the slider is left alone.
|
|
owner._setSharpenIntensity(30);
|
|
owner._setBloomEnabled(true);
|
|
await nextTick();
|
|
assert.equal(writes, 0);
|
|
assert.equal(slider.value, '30');
|
|
});
|
|
|
|
/** VisualSettings with a stand-in detection engine. */
|
|
function detectionSettings(store) {
|
|
const { owner } = settings(store);
|
|
const engine = {
|
|
mode: 'OFF',
|
|
tuning: { densityPct: 50, allocationStrategy: 'ELASTIC' },
|
|
fade: { fadeRatio: 0.07, outsideOpacity: 0.01 },
|
|
};
|
|
Object.assign(owner, {
|
|
_detectionDensityPct: 50,
|
|
_detectionFadePct: 7,
|
|
_detectionOutsidePct: 1,
|
|
_detectionModeLabel: null,
|
|
_detectionAllocationShown: null,
|
|
viewer: { scene: { requestRender() {} } },
|
|
});
|
|
owner.services = {
|
|
...owner.services,
|
|
getDetectionMode: () => engine.mode,
|
|
setDetectionModeByLabel: (label) => {
|
|
engine.mode = label;
|
|
},
|
|
getDetectionTuning: () => ({ ...engine.tuning }),
|
|
setDetectionTuning: (next) => Object.assign(engine.tuning, next),
|
|
getKeyholeFadeTuning: () => ({ ...engine.fade }),
|
|
setKeyholeFadeTuning: (next) => Object.assign(engine.fade, next),
|
|
};
|
|
return { owner, engine };
|
|
}
|
|
|
|
test('detection renders its mode, rows, sliders and allocation', async (t) => {
|
|
const { store, $ } = fixture(t);
|
|
const { owner, engine } = detectionSettings(store);
|
|
const button = $('detection-toggle');
|
|
assert.equal(button.querySelector('.pp-label').textContent, 'DETECT');
|
|
assert.equal(button.getAttribute('aria-label'), 'Detection overlay');
|
|
|
|
owner._setDetectionMode('DENSE');
|
|
owner._setDetectionDensity(80);
|
|
await nextTick();
|
|
assert.equal(button.querySelector('.pp-label').textContent, 'DENSE');
|
|
assert.equal(button.getAttribute('aria-pressed'), 'true');
|
|
assert.equal(button.getAttribute('aria-label'), 'Detection overlay: dense');
|
|
assert.equal(button.className, 'pp-toggle-btn active panoptic');
|
|
for (const id of [
|
|
'detection-slider-row',
|
|
'detection-allocation-row',
|
|
'detection-fade-row',
|
|
'detection-opacity-row',
|
|
])
|
|
assert.equal($(id).classList.contains('visible'), true, id);
|
|
assert.equal($('detection-density-slider').value, '75', 'nearest stop');
|
|
assert.equal($('detection-density-value').textContent, '75%');
|
|
assert.equal(engine.tuning.densityPct, 75);
|
|
|
|
owner._setDetectionFade({ fadePct: 55 });
|
|
owner._setDetectionAllocation('weighted', { persist: false });
|
|
await nextTick();
|
|
assert.equal($('detection-fade-slider').value, '40', 'clamped to 40');
|
|
assert.equal($('detection-fade-value').textContent, '40%');
|
|
assert.equal($('detection-opacity-value').textContent, '1%', 'kept');
|
|
assert.equal(engine.fade.fadeRatio, 0.4);
|
|
const weighted = $('detection-allocation-weighted');
|
|
const elastic = $('detection-allocation-elastic');
|
|
assert.equal(weighted.classList.contains('active'), true);
|
|
assert.equal(weighted.getAttribute('aria-checked'), 'true');
|
|
assert.equal(elastic.classList.contains('active'), false);
|
|
assert.equal(elastic.getAttribute('aria-checked'), 'false');
|
|
assert.deepEqual(owner.getDetectionState(), {
|
|
detectionMode: 'DENSE',
|
|
densityPct: 75,
|
|
allocationStrategy: 'WEIGHTED',
|
|
fadePct: 40,
|
|
outsideOpacityPct: 1,
|
|
});
|
|
|
|
owner._setDetectionMode('OFF');
|
|
await nextTick();
|
|
assert.equal(button.querySelector('.pp-label').textContent, 'DETECT');
|
|
assert.equal(button.getAttribute('aria-label'), 'Detection overlay: off');
|
|
assert.equal(button.className, 'pp-toggle-btn');
|
|
assert.equal($('detection-slider-row').classList.contains('visible'), false);
|
|
});
|