37a738e271
新增画布生成对象 dialog 管理 hook 补充生成对象注册表 hook 单测 调整 Lovart 式画布背景色板弹层 更新图片画布前端拆分跟踪文档
178 lines
5.7 KiB
TypeScript
178 lines
5.7 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import { act, render, screen } from '@testing-library/react';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
|
|
import type { CanvasGenerationDialogState } from './ImageCanvasEditorTypes';
|
|
import { useCanvasGenerationDialogs } from './useCanvasGenerationDialogs';
|
|
|
|
function createDialog(
|
|
mode: CanvasGenerationDialogState['mode'],
|
|
prompt: string,
|
|
): Omit<CanvasGenerationDialogState, 'id'> {
|
|
return {
|
|
mode,
|
|
prompt,
|
|
status: 'idle',
|
|
composerOpen: true,
|
|
placeholder: {
|
|
x: mode === 'character' ? 30 : 10,
|
|
y: mode === 'character' ? 40 : 20,
|
|
width: 320,
|
|
height: 240,
|
|
originalWidth: 320,
|
|
originalHeight: 240,
|
|
},
|
|
};
|
|
}
|
|
|
|
function GenerationDialogsHarness({ onActivate }: { onActivate: () => void }) {
|
|
const dialogs = useCanvasGenerationDialogs({ onActivate });
|
|
const activeId = dialogs.activeCanvasGenerationDialog?.id ?? '-';
|
|
const activePrompt = dialogs.activeCanvasGenerationDialog?.prompt ?? '-';
|
|
const inactiveIds = dialogs.inactiveGenerateDialogs
|
|
.map((dialog) => `${dialog.id}:${dialog.prompt}:${dialog.composerOpen}`)
|
|
.join('|');
|
|
const allPrompts = dialogs.canvasGenerationDialogs
|
|
.map((dialog) => dialog.prompt)
|
|
.join(',');
|
|
|
|
return (
|
|
<div>
|
|
<span data-testid="active-id">{activeId}</span>
|
|
<span data-testid="active-prompt">{activePrompt}</span>
|
|
<span data-testid="inactive">{inactiveIds}</span>
|
|
<span data-testid="all-prompts">{allPrompts}</span>
|
|
<span data-testid="placeholder-x">
|
|
{String(
|
|
dialogs.getGeneratingDialogPlaceholder(
|
|
dialogs.activeCanvasGenerationDialog ?? {
|
|
mode: 'generate',
|
|
prompt: 'fallback',
|
|
status: 'idle',
|
|
},
|
|
)?.x ?? '-',
|
|
)}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={() => dialogs.openCanvasGenerationDialog(createDialog('generate', 'first'))}
|
|
>
|
|
open first
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => dialogs.openCanvasGenerationDialog(createDialog('character', 'second'))}
|
|
>
|
|
open second
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const target = dialogs.inactiveGenerateDialogs[0];
|
|
if (target) {
|
|
dialogs.activateCanvasGenerationDialog(target);
|
|
}
|
|
}}
|
|
>
|
|
activate inactive
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const target = dialogs.activeCanvasGenerationDialog;
|
|
if (target) {
|
|
dialogs.updateCanvasGenerationDialogById(target.id, (dialog) => ({
|
|
...dialog,
|
|
status: 'generating',
|
|
placeholder: dialog.placeholder
|
|
? {
|
|
...dialog.placeholder,
|
|
x: 99,
|
|
}
|
|
: dialog.placeholder,
|
|
}));
|
|
}
|
|
}}
|
|
>
|
|
update active
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const target = dialogs.activeCanvasGenerationDialog;
|
|
if (target) {
|
|
dialogs.removeCanvasGenerationDialogById(target.id);
|
|
}
|
|
}}
|
|
>
|
|
remove active
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const target = dialogs.activeCanvasGenerationDialog;
|
|
if (target) {
|
|
dialogs.updateCanvasGenerationDialogById(target.id, (dialog) => ({
|
|
...dialog,
|
|
sourceLayerId: 'layer-a',
|
|
}));
|
|
}
|
|
}}
|
|
>
|
|
bind layer
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => dialogs.removeCanvasGenerationDialogsByLayerId('layer-a')}
|
|
>
|
|
remove layer dialogs
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
describe('useCanvasGenerationDialogs', () => {
|
|
it('archives, activates, updates, and removes canvas generation dialogs', () => {
|
|
const onActivate = vi.fn();
|
|
render(<GenerationDialogsHarness onActivate={onActivate} />);
|
|
|
|
act(() => screen.getByRole('button', { name: 'open first' }).click());
|
|
expect(screen.getByTestId('active-prompt').textContent).toBe('first');
|
|
expect(screen.getByTestId('all-prompts').textContent).toBe('first');
|
|
|
|
act(() => screen.getByRole('button', { name: 'open second' }).click());
|
|
expect(screen.getByTestId('active-prompt').textContent).toBe('second');
|
|
expect(screen.getByTestId('inactive').textContent).toContain(
|
|
'generation-dialog-1:first:false',
|
|
);
|
|
expect(screen.getByTestId('all-prompts').textContent).toBe(
|
|
'first,second',
|
|
);
|
|
|
|
act(() =>
|
|
screen.getByRole('button', { name: 'activate inactive' }).click(),
|
|
);
|
|
expect(onActivate).toHaveBeenCalledTimes(1);
|
|
expect(screen.getByTestId('active-prompt').textContent).toBe('first');
|
|
expect(screen.getByTestId('inactive').textContent).toContain(
|
|
'generation-dialog-2:second:false',
|
|
);
|
|
|
|
act(() => screen.getByRole('button', { name: 'update active' }).click());
|
|
expect(screen.getByTestId('placeholder-x').textContent).toBe('99');
|
|
|
|
act(() => screen.getByRole('button', { name: 'bind layer' }).click());
|
|
act(() =>
|
|
screen.getByRole('button', { name: 'remove layer dialogs' }).click(),
|
|
);
|
|
expect(screen.getByTestId('active-prompt').textContent).toBe('-');
|
|
expect(screen.getByTestId('inactive').textContent).toContain('second');
|
|
|
|
act(() => screen.getByRole('button', { name: 'activate inactive' }).click());
|
|
act(() => screen.getByRole('button', { name: 'remove active' }).click());
|
|
expect(screen.getByTestId('active-prompt').textContent).toBe('-');
|
|
expect(screen.getByTestId('inactive').textContent).toBe('');
|
|
});
|
|
});
|