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)); /** * Фаза 6 (срез): layout-only мутации не должны слать полный Project во все окна. * Редактор НПС применяет позицию из ответа invoke локально. */ void test('session IPC: нет emitSessionState на graph/NPC position hot-path', () => { const index = fs.readFileSync(path.join(here, 'index.ts'), 'utf8'); const createWindows = fs.readFileSync(path.join(here, 'windows/createWindows.ts'), 'utf8'); const npcsEditor = fs.readFileSync( path.join(here, '../renderer/npcs/NpcsEditorApp.tsx'), 'utf8', ); assert.ok(index.includes('sendToAppWindows(ipcChannels.session.stateChanged')); assert.ok(createWindows.includes('SESSION_STATE_WINDOW_KINDS')); assert.ok(createWindows.includes('sendToAppWindows')); const kindsBlock = /SESSION_STATE_WINDOW_KINDS: readonly WindowKind\[\] = \[([\s\S]*?)\] as const/.exec( createWindows, ); assert.ok(kindsBlock, 'SESSION_STATE_WINDOW_KINDS объявлен'); assert.doesNotMatch(kindsBlock[1] ?? '', /'editor'/, 'editor не получает session.stateChanged'); assert.match(kindsBlock[1] ?? '', /'presentation'/); assert.match(kindsBlock[1] ?? '', /'control'/); // Handlers больше не вызывают emitSessionState сразу после layout-update. const npcPosHandler = /registerHandler\(ipcChannels\.project\.updateNpcPosition,\s*async\s*\(\{ npcId, x, y \}\) => \{([\s\S]*?)\}\);/.exec( index, ); const graphPosHandler = /registerHandler\(ipcChannels\.project\.updateSceneGraphNodePosition,\s*async\s*\(\{ nodeId, x, y \}\) => \{([\s\S]*?)\}\);/.exec( index, ); assert.ok(npcPosHandler, 'updateNpcPosition handler'); assert.ok(graphPosHandler, 'updateSceneGraphNodePosition handler'); assert.doesNotMatch(npcPosHandler[1] ?? '', /emitSessionState/); assert.doesNotMatch(graphPosHandler[1] ?? '', /emitSessionState/); assert.match(npcPosHandler[1] ?? '', /return \{ project \}/); assert.match(graphPosHandler[1] ?? '', /return \{ project \}/); assert.ok(npcsEditor.includes('updateNpcPosition')); assert.match( npcsEditor, /onNodePositionCommit[\s\S]*?setSession\([\s\S]*?npcs: prev\.project\.npcs\.map/, ); assert.match(npcsEditor, /await api\.invoke\(ipcChannels\.project\.updateNpcPosition/); });