// @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'); }); });