Files
Genarrative/apps/ai-game-creator-shell/tests/bindingOverview.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

134 lines
3.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
getBindingOverview,
nodeHasBlockedComponents,
nodeHasPendingBinding,
nodeNeedsComponentReview,
} from '../src/features/ui-editor/bindingOverview';
import { getNextMatchingUiTreeNodeTarget } from '../src/features/ui-editor/stageStatusOverview';
import type { Component } from '../src/features/ui-editor/types/Component';
import type { Node } from '../src/features/ui-editor/types/Node';
import type { SpriteAsset } from '../src/features/ui-editor/types/SpriteAsset';
import type { UITree } from '../src/features/ui-editor/types/UITree';
function image(targetGraphic: string | null): Component {
return {
Image: {
target_graphic: targetGraphic,
image_type: { Simple: { preserve_aspect: false } },
},
};
}
function text(font: 'SystemFont' | { Bound: string }): Component {
return {
Text: {
content: '文本',
font,
font_style: 'Normal',
font_sizing: { Fixed: 14 },
color: [255, 255, 255, 255],
alignment: 'UpperLeft',
horizontal_overflow: 'Wrap',
vertical_overflow: 'Truncate',
line_spacing: 1,
},
};
}
function node(
id: string,
component: Component | null,
componentStatus: Node['metadata']['component_status'] = 'NoProblem',
children: Node[] = [],
): Node {
return {
id,
layout: {
transform: {
anchor_min: [0, 0],
anchor_max: [1, 1],
offset_min: [0, 0],
offset_max: [0, 0],
},
custom_minimum_size: [0, 0],
size_flags_horizontal: 1,
size_flags_vertical: 1,
size_flags_stretch_ratio: 1,
container: 'None',
},
metadata: {
name: id,
description: '',
layout_status: 'NoProblem',
component_status: componentStatus,
allow_llm_edit_layout: true,
allow_llm_edit_component: true,
source: 'System',
},
component,
children,
};
}
function sprite(id: string): SpriteAsset {
return {
asset_id: id,
metadata: { name: id, asset_type: 'Normal' },
path: `${id}.png`,
pixel_size: [16, 16],
pixels_per_unit: 1,
border: { left: 0, right: 0, top: 0, bottom: 0 },
};
}
const sprites = {
validSprite: sprite('validSprite'),
unused: sprite('unused'),
};
const trees: UITree[] = [
{
src_ui_design: 'page-a',
root: node('root', image('validSprite'), 'NoProblem', [
node('review', image(null), { NeedReview: '确认素材' }),
node('blocked', text('SystemFont'), { Blocked: '素材绑定失败' }),
]),
},
];
describe('getBindingOverview', () => {
it('uses per-component helpers to include both image and text slots', () => {
expect(getBindingOverview(trees, sprites)).toEqual({
componentsNeedingAssets: 2,
assetSlots: 2,
boundSlots: 1,
pendingSlots: 1,
needsAttention: 2,
blocked: 1,
independentAssets: 2,
});
});
it('reuses the common preorder next-target search for every binding queue', () => {
expect(
getNextMatchingUiTreeNodeTarget(trees, null, (target) =>
nodeHasPendingBinding(target),
)?.node.id,
).toBe('review');
expect(
getNextMatchingUiTreeNodeTarget(trees, 'review', (target) =>
nodeHasPendingBinding(target),
)?.node.id,
).toBe('review');
expect(
getNextMatchingUiTreeNodeTarget(trees, null, nodeNeedsComponentReview)
?.node.id,
).toBe('review');
expect(
getNextMatchingUiTreeNodeTarget(trees, null, nodeHasBlockedComponents)
?.node.id,
).toBe('blocked');
});
});