mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
refactor(ui): extract application shortcuts and parameter controls
This commit is contained in:
1 parent
5fa8db1686
commit
7a5f615d55
14 files changed
+469
-92
No files matched your search
@@ -285,5 +285,14 @@
|
||||
"src/panelStackLayout.js"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"visual-input": {
|
||||
"exports": ["./ui/input"],
|
||||
"modules": [
|
||||
"src/ui/visualInput.js",
|
||||
"src/ui/applicationShortcuts.js",
|
||||
"src/ui/styleParameters.js"
|
||||
],
|
||||
"external": []
|
||||
}
|
||||
}
|
||||
@@ -569,7 +569,13 @@ try {
|
||||
trusted: event.isTrusted, detail: event.detail ?? null,
|
||||
style: event.target.closest('.style-btn')?.dataset.style || null,
|
||||
});
|
||||
for (const type of ['keydown', 'keyup', 'click']) grid.addEventListener(type, record, true);
|
||||
// A claimed hold deliberately blurs the button. Repeats and release then
|
||||
// target the document body, so observe Space beyond the original grid.
|
||||
const recordSpace = (event) => {
|
||||
if (event.code === 'Space') record(event);
|
||||
};
|
||||
for (const type of ['keydown', 'keyup']) document.addEventListener(type, recordSpace, true);
|
||||
grid.addEventListener('click', record, true);
|
||||
manager.setStyle = function (...args) {
|
||||
probe.activations.push(args[0]);
|
||||
return originalSetStyle.apply(this, args);
|
||||
@@ -609,7 +615,8 @@ try {
|
||||
manager.setStyle = originalSetStyle;
|
||||
voice.start = originalVoiceStart;
|
||||
observer.disconnect();
|
||||
for (const type of ['keydown', 'keyup', 'click']) grid.removeEventListener(type, record, true);
|
||||
for (const type of ['keydown', 'keyup']) document.removeEventListener(type, recordSpace, true);
|
||||
grid.removeEventListener('click', record, true);
|
||||
};
|
||||
window.__qaStyleKeyProbe = probe;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env node
|
||||
/** Browser acceptance for application shortcuts and generated parameter controls. */
|
||||
import fs from 'node:fs';
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
args: ['--no-sandbox', ...(process.platform === 'darwin' ? ['--use-angle=metal', '--enable-gpu'] : ['--use-gl=angle', '--use-angle=swiftshader'])],
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', (error) => errors.push(error.message));
|
||||
let failures = 0;
|
||||
const check = (name, passed) => {
|
||||
console.log(`[${passed ? 'PASS' : 'FAIL'}] ${name}`);
|
||||
if (!passed) failures += 1;
|
||||
};
|
||||
try {
|
||||
await page.setViewport({ width: 1440, height: 900 });
|
||||
const url = new URL(process.env.QA_BASE_URL || 'http://127.0.0.1:4173');
|
||||
url.searchParams.set('welcome', '0');
|
||||
await page.goto(url.href, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForFunction(() => window.__godsEyeView?.styleManager?._applicationShortcuts, { timeout: 60_000 });
|
||||
await page.waitForFunction(() => {
|
||||
const cover = document.getElementById('loading-screen');
|
||||
return cover?.classList.contains('hidden') && Number(getComputedStyle(cover).opacity) === 0;
|
||||
}, { timeout: 60_000 });
|
||||
await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager.setStyle('normal');
|
||||
document.activeElement?.blur();
|
||||
});
|
||||
await page.keyboard.press('2');
|
||||
check('native number shortcut selects CRT', await page.evaluate(() => window.__godsEyeView.styleManager.activeStyle === 'retro'));
|
||||
const initial = await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager.setPanelCollapsed('pp-toggles', false, { persist: false, syncShare: false });
|
||||
manager._sliderPanel.classList.remove('collapsed');
|
||||
const slider = manager._sliderContainer.querySelector('input');
|
||||
window.__qaOldSlider = slider;
|
||||
const name = 'pixelation';
|
||||
window.__qaParameter = { name, before: manager.stages.retro.uniforms[name] };
|
||||
slider.focus();
|
||||
return { before: Number(slider.value), step: Number(slider.step), label: slider.getAttribute('aria-label') };
|
||||
});
|
||||
check('generated range has an accessible label and a numeric step', initial.label === 'Pixelation' && initial.step > 0);
|
||||
await page.keyboard.press('ArrowRight');
|
||||
const changed = await page.evaluate(() => {
|
||||
const slider = window.__qaOldSlider;
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
return { value: Number(slider.value), readout: slider.nextElementSibling.textContent, uniform: manager.stages.retro.uniforms[window.__qaParameter.name] };
|
||||
});
|
||||
check('native range input changes the shader and formatted readout', changed.value > initial.before && changed.uniform === changed.value && Number(changed.readout) === changed.value);
|
||||
await page.keyboard.press('3');
|
||||
check('focused range retains native input instead of changing style', await page.evaluate(() => window.__godsEyeView.styleManager.activeStyle === 'retro'));
|
||||
check('replacing a style revokes its detached slider', await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
const before = manager.stages.retro.uniforms[window.__qaParameter.name];
|
||||
manager.setStyle('thermal');
|
||||
window.__qaOldSlider.value = '0';
|
||||
window.__qaOldSlider.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
return manager.stages.retro.uniforms[window.__qaParameter.name] === before;
|
||||
}));
|
||||
check('normal style clears rows; reopening restores current shader values', await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager.setStyle('normal');
|
||||
const cleared = manager._sliderContainer.children.length === 0;
|
||||
manager.setStyle('retro');
|
||||
return cleared && Number(manager._sliderContainer.querySelector('input').value) === manager.stages.retro.uniforms[window.__qaParameter.name];
|
||||
}));
|
||||
const hudBefore = await page.evaluate(() => {
|
||||
document.getElementById('hud-layout-select').focus();
|
||||
return window.__godsEyeView.styleManager.hud.visible;
|
||||
});
|
||||
await page.keyboard.press('h');
|
||||
check('HUD select keeps its native typing and selection', await page.evaluate((visible) => document.activeElement?.id === 'hud-layout-select' && window.__godsEyeView.styleManager.hud.visible === visible, hudBefore));
|
||||
fs.mkdirSync('qa-shots/visual-input', { recursive: true });
|
||||
await page.screenshot({ path: 'qa-shots/visual-input/desktop.png' });
|
||||
await page.setViewport({ width: 620, height: 900 });
|
||||
await page.waitForFunction(() => document.getElementById('left-panel-stack')?.dataset.layoutMode === 'mobile');
|
||||
await page.screenshot({ path: 'qa-shots/visual-input/narrow.png' });
|
||||
await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
window.__qaCurrentSlider = manager._sliderContainer.querySelector('input');
|
||||
manager._applicationShortcuts.destroy();
|
||||
manager._styleParameters.destroy();
|
||||
document.activeElement?.blur();
|
||||
});
|
||||
await page.keyboard.press('3');
|
||||
check('destroyed application shortcuts cannot change the selected style', await page.evaluate(() => window.__godsEyeView.styleManager.activeStyle === 'retro'));
|
||||
check('destroyed parameter controls cannot write through a retained element', await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
const before = manager.stages.retro.uniforms[window.__qaParameter.name];
|
||||
window.__qaCurrentSlider.value = '0';
|
||||
window.__qaCurrentSlider.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
return manager._sliderContainer.children.length === 0 && manager.stages.retro.uniforms[window.__qaParameter.name] === before;
|
||||
}));
|
||||
check('runtime has no uncaught browser errors', errors.length === 0);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
console.log(`RESULT: ${failures} failures`);
|
||||
process.exitCode = failures ? 1 : 0;
|
||||
Reference in new issue
Block a user