feat(planning): consolidate recorded-route localization and spatial scene
Preserve the completed teach-and-repeat laboratory stage: reference preparation, cascaded acquisition, local tracking and recovery, recording lifecycle, replay qualification, and persistent Rerun scene controls. Document the open grid-picking regression and Rerun upgrade contract. No autonomous driving or loop-closure optimization is claimed.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { before, after, test } from 'node:test';
|
||||
import { createElement } from 'react';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { createServer } from 'vite';
|
||||
|
||||
let server, SpatialScene;
|
||||
before(async () => {
|
||||
server = await createServer({ appType: 'custom', logLevel: 'silent', server: { middlewareMode: true } });
|
||||
({ SpatialScene } = await server.ssrLoadModule(new URL('../../../packages/spatial-ui/src/SpatialScene.tsx', import.meta.url).pathname));
|
||||
});
|
||||
after(async () => { await server?.close(); });
|
||||
|
||||
const render = (focused = false) => renderToStaticMarkup(createElement(SpatialScene, {
|
||||
viewportRef: { current: null }, primaryFocused: focused, toolbar: null, renderer: null,
|
||||
sourceControls: createElement('div', { className: focused ? 'scene-focus-exit' : 'scene-source-controls' }, 'SOURCE_CONTROLS'),
|
||||
status: { label: 'Накопление данных', tone: 'neutral', message: 'Сканер неподвижен.' },
|
||||
metrics: createElement('div', null, 'METRICS'),
|
||||
}));
|
||||
|
||||
test('scene tools, visual engine and metrics share one top-left flow in that order', () => {
|
||||
const markup = render();
|
||||
const stack = markup.indexOf('class="scene-information"');
|
||||
const controls = markup.indexOf('SOURCE_CONTROLS');
|
||||
const status = markup.indexOf('ВИЗУАЛЬНЫЙ ДВИЖОК');
|
||||
const metrics = markup.indexOf('METRICS');
|
||||
assert.ok(stack < controls && controls < status && status < metrics);
|
||||
assert.equal((markup.match(/SOURCE_CONTROLS/g) ?? []).length, 1);
|
||||
assert.doesNotMatch(markup, /scene-status--top-left/);
|
||||
});
|
||||
|
||||
test('focus exit remains viewport-owned outside the hidden information stack', () => {
|
||||
const markup = render(true);
|
||||
assert.ok(markup.indexOf('scene-focus-exit') < markup.indexOf('scene-information'));
|
||||
assert.match(markup, /class="scene-information" aria-hidden="true"/);
|
||||
assert.equal((markup.match(/SOURCE_CONTROLS/g) ?? []).length, 1);
|
||||
});
|
||||
|
||||
test('scene layout uses flow, retains compact metrics and removes only the calibration perimeter', async () => {
|
||||
const css = await readFile(new URL('../../../packages/spatial-ui/src/spatial.css', import.meta.url), 'utf8');
|
||||
const responsive = await readFile(new URL('../src/styles/responsive.css', import.meta.url), 'utf8');
|
||||
const calibration = await readFile(new URL('../../../plugins/xgrids-k1/frontend/src/components/K1SpatialSession.css', import.meta.url), 'utf8');
|
||||
assert.match(css, /\.scene-information \{[^}]*position: absolute;[^}]*display: grid;/);
|
||||
assert.match(css, /\.scene-information > \.scene-source-controls \{ position: static; pointer-events: auto;/);
|
||||
assert.match(css, /\.scene-information\[aria-hidden="true"\] \{ display: none;/);
|
||||
assert.doesNotMatch(css.match(/\.scene-metrics \{[^}]*\}/)?.[0] ?? '', /top:|right:|position: absolute/);
|
||||
assert.doesNotMatch(responsive, /\.scene-metrics\s*\{\s*display: none/);
|
||||
assert.match(calibration, /\.xgrids-k1-spatial-controls \{[^}]*border: 0;/);
|
||||
});
|
||||
Reference in New Issue
Block a user