补充前端交互状态机文档和Esc测试
- 新增前端交互状态机文档,梳理全局状态、工作区工具、语义分类树、键盘快捷键、范围选择、AI页、模板确认和导入导出交互。 - 明确记录 Esc 行为:只取消当前 mask 选区和临时绘制状态,不删除已有 mask,也不清空 active class。 - 补充 CanvasArea 测试,覆盖 Esc 取消选中 mask 但保留 mask/active class,以及 Esc 取消进行中的多边形绘制。 - 更新文档索引、AGENTS 和测试计划,把前端交互状态机纳入事实文档和 R13 文档测试覆盖。
This commit is contained in:
@@ -90,6 +90,38 @@ describe('CanvasArea', () => {
|
||||
expect(maskGroup()).toHaveAttribute('data-opacity', '0.3');
|
||||
});
|
||||
|
||||
it('clears only the selected mask state with Escape', async () => {
|
||||
useStore.setState({
|
||||
activeTemplateId: '2',
|
||||
activeClass: { id: 'c1', name: '胆囊', color: '#ff0000', zIndex: 20, maskId: 1 },
|
||||
activeClassId: 'c1',
|
||||
selectedMaskIds: ['m1'],
|
||||
masks: [
|
||||
{
|
||||
id: 'm1',
|
||||
frameId: 'frame-1',
|
||||
pathData: 'M 10 10 L 80 10 L 80 80 L 10 80 Z',
|
||||
label: '胆囊',
|
||||
color: '#ff0000',
|
||||
classId: 'c1',
|
||||
segmentation: [[10, 10, 80, 10, 80, 80, 10, 80]],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
render(<CanvasArea activeTool="move" frame={frame} />);
|
||||
fireEvent.keyDown(window, { key: 'Escape' });
|
||||
|
||||
await waitFor(() => expect(useStore.getState().selectedMaskIds).toEqual([]));
|
||||
expect(useStore.getState().masks).toHaveLength(1);
|
||||
expect(useStore.getState().masks[0]).toEqual(expect.objectContaining({
|
||||
id: 'm1',
|
||||
label: '胆囊',
|
||||
color: '#ff0000',
|
||||
}));
|
||||
expect(useStore.getState().activeClassId).toBe('c1');
|
||||
});
|
||||
|
||||
it('refines one SAM2 candidate mask from an initial box with positive and negative points', async () => {
|
||||
apiMock.predictMask
|
||||
.mockResolvedValueOnce({
|
||||
@@ -1817,6 +1849,21 @@ describe('CanvasArea', () => {
|
||||
expect(useStore.getState().selectedMaskIds).toEqual([useStore.getState().masks[0].id]);
|
||||
});
|
||||
|
||||
it('cancels in-progress polygon creation with Escape', () => {
|
||||
render(<CanvasArea activeTool="create_polygon" frame={frame} />);
|
||||
const stage = screen.getByTestId('konva-stage');
|
||||
fireEvent.click(stage, { clientX: 120, clientY: 80 });
|
||||
fireEvent.click(stage, { clientX: 220, clientY: 80 });
|
||||
|
||||
expect(screen.getAllByTestId('konva-circle')).toHaveLength(2);
|
||||
fireEvent.keyDown(window, { key: 'Escape' });
|
||||
|
||||
expect(useStore.getState().masks).toEqual([]);
|
||||
expect(useStore.getState().selectedMaskIds).toEqual([]);
|
||||
expect(screen.queryAllByTestId('konva-circle')).toHaveLength(0);
|
||||
expect(screen.getByText(/点击画布添加顶点/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('closes a clicked polygon by clicking the first node again', () => {
|
||||
render(<CanvasArea activeTool="create_polygon" frame={frame} />);
|
||||
const stage = screen.getByTestId('konva-stage');
|
||||
|
||||
Reference in New Issue
Block a user