Files
Genarrative/apps/ai-game-creator-shell/tests/uiTreeNodeCycle.test.ts
T
kdletters fbd30d7c66
Project CI / AI game creator shell Rust smoke (push) Successful in 2m15s
Project CI / AI game creator shell Rust crates (push) Successful in 1m23s
Project CI / Backend tests (push) Successful in 4m34s
Project CI / Native shell tests (push) Successful in 6m35s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 9m49s
Project CI / Frontend tests (push) Successful in 2m43s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 11m59s
Project CI / AI game creator shell web tests (push) Successful in 1m46s
Project CI / Repository checks (push) Successful in 2m25s
修复 UI 编辑器循环游标与复制态被延迟 effect 覆盖
界面树循环游标改为渲染期换算有效游标,不再用被动 effect 事后重置
复制路径按钮把复制态绑定到具体路径,去掉延迟重置的 effect
复制态断言改为等待异步落盘,避免同步断言抢跑
新增 useUiTreeNodeCycle 循环顺序与界面树替换重置用例
2026-10-02 11:17:37 +08:00

97 lines
2.8 KiB
TypeScript

// @vitest-environment jsdom
import { act, renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import {
isNeedReview,
type UiTreeNodeTarget,
} from '../src/features/ui-editor/stageStatusOverview';
import type { Node as UiNode } from '../src/features/ui-editor/types/Node';
import type { UITree } from '../src/features/ui-editor/types/UITree';
import { useUiTreeNodeCycle } from '../src/view/ui-editor/useUiTreeNodeCycle';
function node(
id: string,
layoutStatus: UiNode['metadata']['layout_status'],
): UiNode {
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: layoutStatus,
component_status: 'NoProblem',
allow_llm_edit_layout: true,
allow_llm_edit_component: true,
source: 'System',
},
component: null,
children_display_mode: undefined,
offset: { min: [0, 0], max: [0, 0] },
children: [],
};
}
function reviewTree(): UITree {
return {
src_ui_design: 'page',
root: {
...node('page-root', 'NoProblem'),
children: [
node('review-a', { NeedReview: '请检查 0' }),
node('review-b', { NeedReview: '请检查 1' }),
node('review-c', { NeedReview: '请检查 2' }),
],
},
};
}
const matchesReviewNode = ({ node }: UiTreeNodeTarget) =>
isNeedReview(node.metadata.layout_status);
describe('useUiTreeNodeCycle', () => {
it('按顺序循环待检查节点,并在界面树整体替换后重新从第一项开始', () => {
const uiTrees = [reviewTree()];
const onFocusNode = vi.fn();
const { result, rerender } = renderHook(
({ trees }: { trees: UITree[] }) =>
useUiTreeNodeCycle({
uiTrees: trees,
matches: matchesReviewNode,
onFocusNode,
}),
{ initialProps: { trees: uiTrees } },
);
act(() => result.current.focusNext());
expect(onFocusNode).toHaveBeenLastCalledWith('page', 'review-a');
act(() => result.current.focusNext());
expect(onFocusNode).toHaveBeenLastCalledWith('page', 'review-b');
// 同一版界面树上的无关渲染不得重置循环游标。
rerender({ trees: uiTrees });
act(() => result.current.focusNext());
expect(onFocusNode).toHaveBeenLastCalledWith('page', 'review-c');
// 界面树被整体替换时,下一项回到第一项。
rerender({ trees: [...uiTrees] });
act(() => result.current.focusNext());
expect(onFocusNode).toHaveBeenLastCalledWith('page', 'review-a');
});
});