merge main 07094d9 into feat/voice-outlines

This commit is contained in:
manjunath committed 2026-11-02 11:05:08 +05:30
commit c5aa0d28c3
593 files changed
+42386 -19629

No files matched your search

+17 -12
View File
@@ -1,22 +1,27 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { expandApplicationHtml, APPLICATION_TEMPLATES } from '../../build/application-html.js';
import { APPLICATION_VIEWS } from '../ui/views/index.js';
import { readApplicationHtml } from '../testSupport/applicationHtml.mjs';
test('the standalone document expands every component once and preserves unique element ids', () => {
const source = readFileSync(new URL('../../index.html', import.meta.url), 'utf8');
const html = expandApplicationHtml(source);
assert.equal([...source.matchAll(/gev:template /g)].length, APPLICATION_TEMPLATES.length);
assert.doesNotMatch(html, /gev:template/);
const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map(match => match[1]);
const source = readFileSync(new URL('../../index.html', import.meta.url), 'utf8');
test('the standalone document hosts every view once and keeps element ids unique', async () => {
const hosts = [...source.matchAll(/data-gev-view="([^"]+)"/g)].map((match) => match[1]);
// Order is stacking order for fixed elements that share a z-index.
assert.deepEqual(hosts, ['scene-chrome', 'cockpit', 'display-controls', 'command-dock', 'layer-panels', 'context', 'welcome', 'provider-settings', 'intel-hud']);
assert.deepEqual([...hosts].sort(), Object.keys(APPLICATION_VIEWS).sort());
const html = await readApplicationHtml();
const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map((match) => match[1]);
assert.equal(new Set(ids).size, ids.length);
assert.match(html, /id="cesiumContainer"/);
assert.match(html, /type="module" src="\/src\/main.js"/);
});
test('component selection includes only requested markup and refuses filesystem traversal', () => {
const html = expandApplicationHtml('<!-- gev:template welcome -->\n');
assert.match(html, /id="first-run-launcher"/);
assert.doesNotMatch(html, /id="cesiumContainer"/);
assert.throws(() => expandApplicationHtml('<!-- gev:template ../../.env -->'), /Unknown application template/);
test('the loading screen is static markup, so it paints before any script runs', () => {
const loading = source.indexOf('id="loading-screen"');
assert.ok(loading > 0);
assert.ok(loading < source.indexOf('type="module" src="/src/main.js"'));
assert.match(source, /class="loader-status" data-i18n>Initializing photorealistic world\.\.\.</);
assert.doesNotMatch(source, /gev:template/);
});
+13 -40
View File
@@ -9,6 +9,8 @@ import {
} from '../../server/providers/space/launch-library.js';
import { keySetupStatus } from '../keySetupCore.mjs';
import { initKeySetup } from '../keySetup.js';
import { createPinia } from 'pinia';
import { useProviderSettingsStore } from '../ui/stores/providerSettings.js';
test('LL2 requests from the same UTC minute share a cache key without mutating callers', () => {
const first = new Date('2026-10-17T16:20:00.001Z');
@@ -57,60 +59,31 @@ test('LL2 headers identify the app and preserve optional server-only authorizati
});
test('actual setup rendering distinguishes optional paid LL2 from unrelated free keys', async () => {
const created = [];
const node = () => {
const value = {
dataset: {},
children: [],
append(...children) {
this.children.push(...children);
},
querySelector() {
return null;
},
querySelectorAll() {
return [];
},
addEventListener() {},
removeEventListener() {},
setAttribute() {},
remove() {},
};
created.push(value);
return value;
};
const rows = node();
const root = node();
root.querySelector = (selector) =>
selector === '[data-key-setup-rows]' ? rows : null;
const chip = node();
const store = useProviderSettingsStore(createPinia());
const status = keySetupStatus({});
status.keys = status.keys.filter((key) =>
['launch-library', 'mapillary'].includes(key.id),
);
const setup = await initKeySetup({
documentRef: {
getElementById: (id) => (id === 'key-setup-chip' ? chip : root),
createElement: node,
getElementById: (id) => (id === 'key-setup' ? { dataset: {} } : null),
addEventListener() {},
removeEventListener() {},
},
store,
fetchImpl: async () => ({ ok: true, json: async () => status }),
});
assert.ok(setup);
try {
const ll2 = rows.children.find(
(row) => row.dataset.keyId === 'launch-library',
const row = (id) => store.view.rows.find((key) => key.id === id);
const ll2 = row('launch-library');
assert.match(ll2.tierTitle, /optional paid token/i);
assert.match(ll2.unlocks, /leave blank/i);
assert.match(ll2.unlocks, /no key/i);
assert.equal(
row('mapillary').tierTitle,
'Free key — register, paste, done',
);
const free = rows.children.find((row) => row.dataset.keyId === 'mapillary');
const tier = (row) =>
row.children[0].children.find(
(child) => child.className === 'key-setup-tier',
);
assert.match(tier(ll2).title, /optional paid token/i);
assert.match(ll2.children[1].textContent, /leave blank/i);
assert.match(ll2.children[1].textContent, /no key/i);
assert.equal(tier(free).title, 'Free key — register, paste, done');
const serialized = JSON.stringify(status);
assert.ok(!serialized.includes('owned-fixture-token'));
} finally {
+6 -3
View File
@@ -77,13 +77,15 @@ test('the documented outcomes hold: default, stored open, stored shut, and a sha
// against the code that decides them.
const { PanelPositionControls } =
await import('../ui/panelPositionControls.js');
const { presentPanelLocally } = await import('../testSupport/panelState.mjs');
const { readPanelState } = await import('../ui/rail/panelState.js');
const html = await readFile(
path.join(root, 'src/ui/templates/layer-panels.html'),
path.join(root, 'src/ui/views/panels/CctvPanel.vue'),
'utf8',
);
assert.match(
html,
/<div id="cctv-panel" class="panel-collapsible collapsed"/,
/<RailPanel id="cctv-panel"[^>]*\bstart-collapsed\b/,
'the CCTV panel starts collapsed in the markup',
);
@@ -110,7 +112,8 @@ test('the documented outcomes hold: default, stored open, stored shut, and a sha
};
try {
const controls = new PanelPositionControls({
syncPanelCollapseButton: () => {},
presentPanel: presentPanelLocally,
shownPanel: readPanelState,
layoutRightPanels: () => {},
syncCctvPanelViewport: () => {},
showToast: () => {},
+2 -1
View File
@@ -1,5 +1,6 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { fileURLToPath } from 'node:url';
import sharp from 'sharp';
import {
CUBE_FACES,
@@ -24,7 +25,7 @@ test('painted-out planets leave no disc brighter than the sky around them', asyn
}));
for (const face of CUBE_FACES) {
const { data, info } = await sharp(
new URL(`milkyway_${FACE_FILE_SUFFIX[face]}.webp`, SKY).pathname,
fileURLToPath(new URL(`milkyway_${FACE_FILE_SUFFIX[face]}.webp`, SKY)),
)
.raw()
.toBuffer({ resolveWithObject: true });
+27 -20
View File
@@ -1,3 +1,4 @@
import '../testSupport/registerDom.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -8,7 +9,8 @@ import {
detectOn,
} from '../../scripts/qa-transit-controls.mjs';
import { createStyleParameters } from '../ui/styleParameters.js';
import { bindDisplayControls } from '../ui/displayControls.js';
import { createPinia } from 'pinia';
import { useDisplayStore } from '../ui/stores/display.js';
import { thermalShader } from '../styles/thermal.js';
import {
cycleMode,
@@ -18,6 +20,9 @@ import {
} from '../data/detection.js';
const pause = async () => {};
// The page fixture swaps the globals for stand-ins; generated rows render
// into a real element, so keep the registered document.
const realDocument = globalThis.document;
class Element extends EventTarget {
constructor() {
super();
@@ -67,8 +72,7 @@ function pageFixture(t) {
const label = selector.match(/aria-label="([^"]+)"/)[1];
return elements
.get('param-sliders')
.children.flatMap((row) => row.children)
.find((el) => el.getAttribute('aria-label') === label);
.querySelector(`input.param-slider[aria-label="${label}"]`);
}
return elements.get(selector.slice(1));
};
@@ -128,8 +132,7 @@ test('live visual cities follow local operating hours in summer and winter', ()
test('thermal controls wait for activation and use the real generated parameter rows', async (t) => {
const { page, document, elements } = pageFixture(t);
const container = new Element();
container.ownerDocument = document;
const container = realDocument.createElement('div');
elements.set('param-sliders', container);
const parameters = createStyleParameters({ container });
t.after(() => parameters.destroy());
@@ -159,9 +162,7 @@ test('thermal controls wait for activation and use the real generated parameter
page.$eval = async (selector, fn, ...args) => {
if (selector.startsWith('.style-btn')) return fn(new Element(), ...args);
const label = selector.match(/aria-label="([^"]+)"/)[1];
const slider = container.children
.flatMap((row) => row.children)
.find((el) => el.getAttribute('aria-label') === label);
const slider = container.querySelector(`[aria-label="${label}"]`);
assert.ok(slider);
return fn(slider, ...args);
};
@@ -189,26 +190,32 @@ test('DETECT uses the real OFF/restore button and density input to reach DENSE',
setMode('BALANCED');
setMode('OFF');
const modes = [];
const controls = bindDisplayControls({
elements: { detectionButton: button, densitySlider: slider },
actions: {
cycleDetection() {
cycleMode();
modes.push(getMode());
},
setDensity(value) {
setDetectionTuning({ densityPct: Number(value) });
},
// As DisplayPanel does: the toggle and the slider call the Display
// controls' actions through the display store.
const store = useDisplayStore(createPinia());
const token = store.connect({
cycleDetection() {
cycleMode();
modes.push(getMode());
},
setDensity(value) {
setDetectionTuning({ densityPct: Number(value) });
},
});
const onClick = () => store.act('cycleDetection');
const onInput = () => store.act('setDensity', slider.value);
button.addEventListener('click', onClick);
slider.addEventListener('input', onInput);
t.after(() => {
controls.destroy();
button.removeEventListener('click', onClick);
slider.removeEventListener('input', onInput);
store.detach(token);
setMode('OFF');
});
assert.equal(await detectOn(page, pause), 'DENSE');
assert.deepEqual(modes, ['BALANCED', 'OFF', 'DENSE']);
const template = readFileSync(
new URL('../ui/templates/display-controls.html', import.meta.url),
new URL('../ui/views/panels/DisplayPanel.vue', import.meta.url),
'utf8',
);
assert.match(template, /id="detection-density-slider"/);
+5
View File
@@ -32,6 +32,7 @@ test('explicit build inputs preserve browser-only defines, plugin order and loop
assert.equal(config.plugins[0].enforce, 'pre');
assert.equal(config.plugins[1].name, 'host-check');
assert.equal(config.plugins[1].enforce, 'pre');
assert.equal(config.plugins[3].name, 'vite:vue');
assert.equal(config.plugins[4], plugin);
assert.equal(config.server.host, 'localhost');
assert.equal(config.server.port, 4173);
@@ -67,6 +68,10 @@ test('explicit build inputs preserve browser-only defines, plugin order and loop
assert.ok(!csp.includes("script-src 'self' 'unsafe-inline'"));
assert.deepEqual(config.preview.headers, config.server.headers);
assert.deepEqual(config.define, {
__VUE_I18N_FULL_INSTALL__: 'false',
__VUE_I18N_LEGACY_API__: 'false',
__INTLIFY_PROD_DEVTOOLS__: 'false',
__INTLIFY_DROP_MESSAGE_COMPILER__: 'true',
'import.meta.env.GOOGLE_MAPS_API_KEY': '"browser-fixture"',
'import.meta.env.CESIUM_ION_TOKEN': '"ion-fixture"',
'import.meta.env.MAPILLARY_CLIENT_TOKEN': '""',