Files
Genarrative/src/components/image-editor/ImageCanvasBottomToolbarView.test.tsx
T
menghao 03a4410272
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 4m1s
Project CI / Native shell tests (push) Failing after 11m56s
game agent无限画布开发 (#136)
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-12 10:54:16 +08:00

169 lines
5.4 KiB
TypeScript

/* @vitest-environment jsdom */
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createRef, type RefObject } from 'react';
import { describe, expect, it, vi } from 'vitest';
import { ImageCanvasBottomToolbarView } from './ImageCanvasBottomToolbarView';
describe('ImageCanvasBottomToolbarView', () => {
function renderToolbar(
overrides: Partial<Parameters<typeof ImageCanvasBottomToolbarView>[0]> = {},
) {
const switchTool = vi.fn();
const specToolWrapRef = createRef<HTMLSpanElement>();
const musicToolWrapRef = createRef<HTMLSpanElement>();
const publicationToolWrapRef = createRef<HTMLSpanElement>();
const view = render(
<ImageCanvasBottomToolbarView
specToolWrapRef={specToolWrapRef}
musicToolWrapRef={musicToolWrapRef}
publicationToolWrapRef={publicationToolWrapRef}
effectiveTool="generate"
onSwitchTool={switchTool}
onOpenToolOptions={vi.fn()}
onCloseToolOptions={vi.fn()}
{...overrides}
/>,
);
return {
...view,
toolbar: screen.getByRole('toolbar', { name: 'AI画布工具栏' }),
switchTool,
refs: {
specToolWrapRef,
musicToolWrapRef,
publicationToolWrapRef,
},
};
}
function renderToolbarView(
effectiveTool: Parameters<
typeof ImageCanvasBottomToolbarView
>[0]['effectiveTool'],
refs: {
specToolWrapRef: RefObject<HTMLSpanElement | null>;
musicToolWrapRef: RefObject<HTMLSpanElement | null>;
publicationToolWrapRef: RefObject<HTMLSpanElement | null>;
},
) {
return (
<ImageCanvasBottomToolbarView
specToolWrapRef={refs.specToolWrapRef}
musicToolWrapRef={refs.musicToolWrapRef}
publicationToolWrapRef={refs.publicationToolWrapRef}
effectiveTool={effectiveTool}
onSwitchTool={vi.fn()}
onOpenToolOptions={vi.fn()}
onCloseToolOptions={vi.fn()}
/>
);
}
it('renders the expected canvas tools and forwards user selections', async () => {
const user = userEvent.setup();
const { toolbar, switchTool } = renderToolbar();
expect(toolbar.className).toContain('genarrative-image-canvas__toolbar');
expect(toolbar.className).toContain(
'genarrative-image-canvas__toolbar--floating',
);
expect(
toolbar.querySelectorAll('.genarrative-image-canvas__toolbar-group'),
).toHaveLength(12);
expect(
toolbar.querySelectorAll('.genarrative-image-canvas__toolbar-divider'),
).toHaveLength(2);
const toolExpectations = [
['选择工具', 'select'],
['抓手工具', 'hand'],
['上传工具', 'upload'],
['生成图片', 'generate'],
['生成视频', 'video'],
['生成音乐', 'music'],
['生成规范', 'spec'],
['生成角色形象', 'character'],
['生成图标素材', 'icon'],
['生成UI设计图', 'ui-design'],
['宣发素材', 'publication'],
['生成游戏场景', 'scene'],
] as const;
for (const [label, tool] of toolExpectations) {
await user.click(within(toolbar).getByRole('button', { name: label }));
expect(switchTool).toHaveBeenLastCalledWith(tool);
}
expect(switchTool).toHaveBeenCalledTimes(toolExpectations.length);
});
it('only exposes persistent pressed state for navigation tools', () => {
const { toolbar, rerender, refs } = renderToolbar({
effectiveTool: 'select',
});
expect(
within(toolbar)
.getByRole('button', { name: '选择工具' })
.getAttribute('aria-pressed'),
).toBe('true');
expect(
within(toolbar)
.getByRole('button', { name: '生成图片' })
.getAttribute('aria-pressed'),
).toBe('false');
rerender(renderToolbarView('hand', refs));
expect(
within(toolbar)
.getByRole('button', { name: '抓手工具' })
.getAttribute('aria-pressed'),
).toBe('true');
rerender(renderToolbarView('music', refs));
expect(
within(toolbar)
.getByRole('button', { name: '生成音乐' })
.getAttribute('aria-pressed'),
).toBe('false');
});
it('opens and closes bottom option tools on pointer and keyboard focus', async () => {
const user = userEvent.setup();
const openToolOptions = vi.fn();
const closeToolOptions = vi.fn();
const { toolbar, refs } = renderToolbar({
onOpenToolOptions: openToolOptions,
onCloseToolOptions: closeToolOptions,
});
await user.hover(within(toolbar).getByRole('button', { name: '生成规范' }));
await user.unhover(
within(toolbar).getByRole('button', { name: '生成规范' }),
);
await user.hover(within(toolbar).getByRole('button', { name: '生成音乐' }));
await user.unhover(
within(toolbar).getByRole('button', { name: '生成音乐' }),
);
const publicationTool = within(toolbar).getByRole('button', {
name: '宣发素材',
});
publicationTool.focus();
publicationTool.blur();
expect(openToolOptions).toHaveBeenCalledWith('spec');
expect(closeToolOptions).toHaveBeenCalledWith('spec');
expect(openToolOptions).toHaveBeenCalledWith('music');
expect(closeToolOptions).toHaveBeenCalledWith('music');
expect(openToolOptions).toHaveBeenCalledWith('publication');
expect(closeToolOptions).toHaveBeenCalledWith('publication');
});
});