124 lines
4.3 KiB
TypeScript
124 lines
4.3 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import type { ComponentProps } from 'react';
|
|
import { render, screen } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { expect, test, vi } from 'vitest';
|
|
|
|
import { buildVisualNovelForbiddenCopyPattern } from '../visual-novel-runtime/visualNovelForbiddenCopy';
|
|
import { mockVisualNovelSession } from '../visual-novel-runtime/visualNovelMockData';
|
|
import { VisualNovelAgentWorkspace } from './VisualNovelAgentWorkspace';
|
|
import { AuthUiContext } from '../auth/AuthUiContext';
|
|
|
|
vi.mock('../../services/creation-agent/creationAgentDocumentInput', () => ({
|
|
parseCreationAgentDocumentInput: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../services/visual-novel-creation', () => ({
|
|
uploadVisualNovelAsset: vi.fn(),
|
|
}));
|
|
|
|
const mockedParseCreationAgentDocumentInput = vi.mocked(
|
|
await import('../../services/creation-agent/creationAgentDocumentInput'),
|
|
);
|
|
const mockedVisualNovelAssetClient = vi.mocked(
|
|
await import('../../services/visual-novel-creation'),
|
|
);
|
|
|
|
function renderWorkspace(ui?: Partial<ComponentProps<typeof VisualNovelAgentWorkspace>>) {
|
|
return render(
|
|
<AuthUiContext.Provider
|
|
value={
|
|
{
|
|
user: { id: 'user-1' },
|
|
platformTheme: 'light',
|
|
} as never
|
|
}
|
|
>
|
|
<VisualNovelAgentWorkspace
|
|
session={mockVisualNovelSession}
|
|
onBack={() => {}}
|
|
{...ui}
|
|
/>
|
|
</AuthUiContext.Provider>,
|
|
);
|
|
}
|
|
|
|
test('visual novel workspace renders mock creation shell without forbidden entry', async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenResult = vi.fn();
|
|
|
|
renderWorkspace({ onOpenResult });
|
|
|
|
expect(screen.getByRole('heading', { name: '视觉小说' })).toBeTruthy();
|
|
expect(screen.getByRole('button', { name: '一句话' })).toBeTruthy();
|
|
expect(screen.queryByText(buildVisualNovelForbiddenCopyPattern())).toBeNull();
|
|
|
|
await user.click(screen.getByRole('button', { name: '进入结果页' }));
|
|
|
|
expect(onOpenResult).toHaveBeenCalledWith(mockVisualNovelSession);
|
|
});
|
|
|
|
test('visual novel workspace opens editable blank draft from blank source', async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenResult = vi.fn();
|
|
|
|
renderWorkspace({ session: null, onOpenResult });
|
|
|
|
await user.click(screen.getByRole('button', { name: '空白' }));
|
|
const openResultButtons = screen.getAllByRole('button', {
|
|
name: '进入结果页',
|
|
});
|
|
await user.click(openResultButtons[0]!);
|
|
|
|
expect(onOpenResult).toHaveBeenCalledTimes(1);
|
|
const session = onOpenResult.mock.calls[0]?.[0];
|
|
expect(session?.sourceMode).toBe('blank');
|
|
expect(session?.draft?.sourceMode).toBe('blank');
|
|
expect(session?.draft?.runtimeConfig.textModeEnabled).toBe(true);
|
|
});
|
|
|
|
test('visual novel workspace uploads document asset and passes asset id to session', async () => {
|
|
const user = userEvent.setup();
|
|
const onCreateSession = vi.fn();
|
|
const parseMock = mockedParseCreationAgentDocumentInput.parseCreationAgentDocumentInput;
|
|
const uploadMock = mockedVisualNovelAssetClient.uploadVisualNovelAsset;
|
|
|
|
parseMock.mockResolvedValue({
|
|
document: {
|
|
fileName: '世界设定.docx',
|
|
contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
sizeBytes: 128,
|
|
text: '第一章\n雨夜书店\n第二章\n失踪乘客',
|
|
sourceAssetId: 'asset-doc-source',
|
|
},
|
|
});
|
|
uploadMock.mockResolvedValue({
|
|
assetObjectId: 'asset-doc-1',
|
|
assetKind: 'visual_novel_document',
|
|
objectKey: 'generated-character-drafts/visual-novel/draft/document/1.docx',
|
|
imageSrc: '/generated-character-drafts/visual-novel/draft/document/1.docx',
|
|
});
|
|
|
|
renderWorkspace({ session: null, onCreateSession });
|
|
|
|
await user.click(screen.getByRole('button', { name: '文档' }));
|
|
const fileInput = screen.getByLabelText('上传文档') as HTMLInputElement;
|
|
const file = new File(['first chapter'], '世界设定.docx', {
|
|
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
});
|
|
await user.upload(fileInput, file);
|
|
|
|
await user.click(screen.getByRole('button', { name: '生成底稿' }));
|
|
|
|
expect(parseMock).toHaveBeenCalledTimes(1);
|
|
expect(uploadMock).toHaveBeenCalledTimes(1);
|
|
expect(onCreateSession).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
sourceMode: 'document',
|
|
sourceAssetIds: ['asset-doc-1'],
|
|
seedText: expect.stringContaining('第一章'),
|
|
}),
|
|
);
|
|
});
|