Files
Genarrative/apps/ai-game-creator-shell/tests/bindingOverview.test.ts
T
k88936 995db645e2
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / Backend tests (pull_request) Failing after 14s
Project CI / Native shell tests (pull_request) Failing after 1m49s
Project CI / Frontend tests (pull_request) Failing after 57s
收敛 UI Editor 节点状态
统一 StageStatus 为 NoProblem、NeedReview 和 Blocked

移除 Pending 与 Passed 的前后端、LLM 草稿及持久化夹具用法

补充旧状态拒绝测试并更新 UI Editor 技术方案
2026-08-19 15:24:51 +08:00

139 lines
3.6 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,
components: Component[],
componentsStatus: Node['metadata']['components_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',
components_status: componentsStatus,
allow_llm_edit_layout: true,
allow_llm_edit_component: true,
source: 'System',
},
components,
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'), text({ Bound: 'font-id' })],
'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: 3,
assetSlots: 3,
boundSlots: 2,
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');
});
});