4456eb0277
Re-enable users-branch UI, snap session tokens to square/hex grid from the control preview, refine inactive/open-info NPC menus, block marker actions while an effect brush is active, and dim materials/NPC overlays only when they are open. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.7 KiB
TypeScript
84 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
import test from 'node:test';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||
const root = path.resolve(here, '..', '..', '..', '..');
|
||
|
||
void test('SceneOverlayHost: один dim для materials + npcs в Control и Presentation', () => {
|
||
const host = fs.readFileSync(path.join(here, 'SceneOverlayHost.tsx'), 'utf8');
|
||
const control = fs.readFileSync(path.join(root, 'app/renderer/control/ControlApp.tsx'), 'utf8');
|
||
const presentation = fs.readFileSync(path.join(root, 'app/renderer/shared/PresentationView.tsx'), 'utf8');
|
||
const css = fs.readFileSync(
|
||
path.join(root, 'app/renderer/shared/materials/MaterialOverlay.module.css'),
|
||
'utf8',
|
||
);
|
||
|
||
assert.ok(host.includes('styles.dim'));
|
||
assert.ok(host.includes('hostHitThrough'));
|
||
// Dim только при active; жёлтая рамка без затемнения.
|
||
assert.match(host, /\{active \? <div className=\{styles\.dim\}/);
|
||
assert.ok(host.includes('showViewportGuide'));
|
||
assert.ok(control.includes('SceneOverlayHost'));
|
||
assert.ok(control.includes('embedded'));
|
||
assert.ok(presentation.includes('SceneOverlayHost'));
|
||
assert.ok(presentation.includes('embedded'));
|
||
|
||
// Control/Presentation монтируют оверлеи только как embedded внутри host.
|
||
assert.ok(control.includes('<MaterialOverlay'));
|
||
assert.ok(control.includes('<NpcsSceneOverlay'));
|
||
assert.ok(control.includes('embedded'));
|
||
assert.ok(presentation.includes('embedded'));
|
||
assert.match(css, /\.hostHitThrough\s*\{[^}]*pointer-events:\s*none/s);
|
||
assert.match(css, /\.dim\s*\{[^}]*inset:\s*0/s);
|
||
});
|
||
|
||
void test('MaterialOverlay / NpcsSceneOverlay поддерживают embedded без собственного dim', () => {
|
||
const material = fs.readFileSync(
|
||
path.join(root, 'app/renderer/shared/materials/MaterialOverlay.tsx'),
|
||
'utf8',
|
||
);
|
||
const npcs = fs.readFileSync(path.join(root, 'app/renderer/shared/npcs/NpcsSceneOverlay.tsx'), 'utf8');
|
||
assert.ok(material.includes('embedded'));
|
||
assert.ok(material.includes('useSceneOverlayView'));
|
||
assert.ok(npcs.includes('embedded'));
|
||
assert.ok(npcs.includes('useSceneOverlayView'));
|
||
// В embedded-ветке не рисуем второй dim.
|
||
assert.match(material, /if \(embedded\) \{\s*return frame;/);
|
||
assert.match(npcs, /if \(embedded\) \{\s*return <>\{frames\}<\/>;/);
|
||
});
|
||
|
||
void test('overlays: layout IPC live через rAF coalesce, RO host coalesced', () => {
|
||
const host = fs.readFileSync(path.join(here, 'SceneOverlayHost.tsx'), 'utf8');
|
||
const material = fs.readFileSync(
|
||
path.join(root, 'app/renderer/shared/materials/MaterialOverlay.tsx'),
|
||
'utf8',
|
||
);
|
||
const npcs = fs.readFileSync(path.join(root, 'app/renderer/shared/npcs/NpcsSceneOverlay.tsx'), 'utf8');
|
||
|
||
assert.ok(host.includes('requestAnimationFrame'));
|
||
assert.ok(host.includes('prev.w === w && prev.h === h'));
|
||
|
||
// Лайв: publishDraft шлёт onLayoutChange внутри rAF (не на каждый pointermove).
|
||
assert.ok(material.includes('publishDraft'));
|
||
assert.ok(material.includes('onLayoutChangeRef'));
|
||
assert.match(material, /requestAnimationFrame\(\(\) => \{[\s\S]*?onLayoutChangeRef\.current\?\.\(pending\)/);
|
||
assert.match(
|
||
material,
|
||
/if \(drag\.mode === 'move'\) \{[\s\S]*?publishDraft\(\{[\s\S]*?return;\s*\}/,
|
||
);
|
||
|
||
assert.ok(npcs.includes('publishDraft'));
|
||
assert.ok(npcs.includes('onLayoutChangeRef'));
|
||
assert.match(
|
||
npcs,
|
||
/requestAnimationFrame\(\(\) => \{[\s\S]*?onLayoutChangeRef\.current\?\.\(item\.npcId, pending\)/,
|
||
);
|
||
assert.match(
|
||
npcs,
|
||
/if \(drag\.mode === 'move'\) \{[\s\S]*?publishDraft\(\{[\s\S]*?return;\s*\}/,
|
||
);
|
||
});
|