Files
Genarrative/apps/ai-game-creator-shell/tests/nodeTransformGeometry.test.ts
T
k88936 51f629b2f9
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / Backend tests (pull_request) Failing after 14s
Project CI / Frontend tests (pull_request) Successful in 2m43s
Project CI / Native shell tests (pull_request) Failing after 14m29s
UI编辑器节点改为单组件模型
修改 Node、Binding DTO、识别与分离链路为 component 单字段

为识别和绑定 LLM 工具引入 PureNode/WithComponent 显式载荷

移除前端组件索引、排序和组件栈操作

同步生成 ts-rs TypeScript 类型、状态校验、测试与专题文档
2026-09-10 13:08:29 +08:00

120 lines
3.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
findNodePageContext,
pageRectFromSize,
resolveAnchorPresetTransform,
resolveChildrenTransformsForParentRect,
resolvePageRect,
resolveReparentTransform,
} from '../src/features/ui-editor/nodeTransformGeometry';
import type { Node } from '../src/features/ui-editor/types/Node';
import type { Transform } from '../src/features/ui-editor/types/Transform';
const ROOT_TRANSFORM: Transform = {
anchor_min: [0, 0],
anchor_max: [1, 1],
offset_min: [0, 0],
offset_max: [0, 0],
};
function node(id: string, transform: Transform, children: Node[] = []): Node {
return {
id,
layout: { transform } as Node['layout'],
metadata: {} as Node['metadata'],
component: null,
children_display_mode: 'Stack',
children,
};
}
describe('nodeTransformGeometry', () => {
it('resolves nested context and inverts page offsets at the same seam', () => {
const childTransform: Transform = {
anchor_min: [0.5, 0.5],
anchor_max: [0.5, 0.5],
offset_min: [-10, -15],
offset_max: [30, 25],
};
const root = node('root', ROOT_TRANSFORM, [
node(
'parent',
{
anchor_min: [0, 0],
anchor_max: [0, 0],
offset_min: [20, 30],
offset_max: [220, 130],
},
[node('child', childTransform)],
),
]);
const context = findNodePageContext(
root,
'child',
pageRectFromSize([400, 300]),
);
expect(context).toMatchObject({
parentRect: { min: [20, 30], max: [220, 130] },
rect: { min: [110, 65], max: [150, 105] },
});
expect(
resolveReparentTransform(
childTransform,
context!.rect,
context!.parentRect,
),
).toEqual(childTransform);
});
it('preserves direct child page rectangles when a parent changes', () => {
const child = node('child', {
anchor_min: [0.25, 0],
anchor_max: [0.75, 1],
offset_min: [5, 10],
offset_max: [-10, -15],
});
const oldParentRect = {
min: [20, 30] as [number, number],
max: [220, 130] as [number, number],
};
const newParentRect = {
min: [40, 50] as [number, number],
max: [340, 250] as [number, number],
};
const oldChildRect = resolvePageRect(child.layout.transform, oldParentRect);
const [{ transform }] = resolveChildrenTransformsForParentRect(
[child],
oldParentRect,
newParentRect,
);
expect(resolvePageRect(transform, newParentRect)).toEqual(oldChildRect);
});
it('keeps the page rectangle stable when inspector anchors change', () => {
const transform: Transform = {
anchor_min: [0.5, 0.5],
anchor_max: [0.5, 0.5],
offset_min: [-60, -20],
offset_max: [40, 30],
};
const parentSize = { width: 300, height: 200 };
const pageRect = pageRectFromSize([parentSize.width, parentSize.height]);
const next = resolveAnchorPresetTransform(
transform,
[0, 0],
[1, 1],
parentSize,
);
expect(resolvePageRect(next, pageRect)).toEqual(
resolvePageRect(transform, pageRect),
);
});
});