1
This commit is contained in:
@@ -6,13 +6,35 @@ import { useState } from 'react';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import type { CustomWorldPlayableNpc, CustomWorldProfile } from '../types';
|
||||
import { CustomWorldResultView } from './CustomWorldResultView';
|
||||
import * as rpgCreationAssetClient from '../services/rpg-creation/rpgCreationAssetClient';
|
||||
import { RpgCreationResultView } from './rpg-creation-result/RpgCreationResultView';
|
||||
|
||||
vi.mock('../services/aiService', () => ({
|
||||
generateCustomWorldPlayableNpc: vi.fn(),
|
||||
generateCustomWorldStoryNpc: vi.fn(),
|
||||
generateCustomWorldLandmark: vi.fn(),
|
||||
}));
|
||||
vi.mock('../services/rpg-creation/rpgCreationAssetClient', () => {
|
||||
const generatePlayableNpc = vi.fn();
|
||||
const generateStoryNpc = vi.fn();
|
||||
const generateLandmark = vi.fn();
|
||||
const generateSceneImage = vi.fn();
|
||||
const generateSceneNpc = vi.fn();
|
||||
|
||||
return {
|
||||
rpgCreationAssetClient: {
|
||||
generatePlayableNpc,
|
||||
generateStoryNpc,
|
||||
generateLandmark,
|
||||
generateSceneImage,
|
||||
generateSceneNpc,
|
||||
},
|
||||
generateCustomWorldPlayableNpc: generatePlayableNpc,
|
||||
generateCustomWorldStoryNpc: generateStoryNpc,
|
||||
generateCustomWorldLandmark: generateLandmark,
|
||||
generateCustomWorldSceneImage: generateSceneImage,
|
||||
generateCustomWorldSceneNpc: generateSceneNpc,
|
||||
};
|
||||
});
|
||||
|
||||
const mockedRpgCreationAssetClient = vi.mocked(
|
||||
rpgCreationAssetClient.rpgCreationAssetClient,
|
||||
);
|
||||
|
||||
vi.mock('./CharacterAnimator', () => ({
|
||||
CharacterAnimator: () => <div>角色预览</div>,
|
||||
@@ -24,15 +46,11 @@ vi.mock('./CustomWorldNpcVisualEditor', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('./CustomWorldEntityEditorModal', () => ({
|
||||
CustomWorldEntityEditorModal: () => null,
|
||||
vi.mock('./rpg-creation-editor/RpgCreationEntityEditorModal', () => ({
|
||||
RpgCreationEntityEditorModal: () => null,
|
||||
default: () => null,
|
||||
}));
|
||||
|
||||
async function loadAiService() {
|
||||
return import('../services/aiService');
|
||||
}
|
||||
|
||||
function createBackstoryReveal() {
|
||||
return {
|
||||
publicSummary: '公开背景',
|
||||
@@ -259,7 +277,7 @@ function ResultViewHarness() {
|
||||
const [profile, setProfile] = useState(baseProfile);
|
||||
|
||||
return (
|
||||
<CustomWorldResultView
|
||||
<RpgCreationResultView
|
||||
profile={profile}
|
||||
previewCharacters={[]}
|
||||
isGenerating={false}
|
||||
@@ -273,11 +291,10 @@ function ResultViewHarness() {
|
||||
}
|
||||
|
||||
test('clicking新增可扮演角色 shows pending item, disables button, and marks result as new', async () => {
|
||||
const aiService = await loadAiService();
|
||||
const user = userEvent.setup();
|
||||
|
||||
let resolveGeneration: ((value: CustomWorldPlayableNpc) => void) | null = null;
|
||||
vi.mocked(aiService.generateCustomWorldPlayableNpc).mockImplementation(
|
||||
mockedRpgCreationAssetClient.generatePlayableNpc.mockImplementation(
|
||||
() =>
|
||||
new Promise<CustomWorldPlayableNpc>((resolve) => {
|
||||
resolveGeneration = resolve;
|
||||
@@ -346,7 +363,7 @@ test('playable tab prefers generated portrait over runtime preview placeholder',
|
||||
} as CustomWorldProfile;
|
||||
|
||||
render(
|
||||
<CustomWorldResultView
|
||||
<RpgCreationResultView
|
||||
profile={profile}
|
||||
previewCharacters={[
|
||||
{
|
||||
@@ -403,7 +420,7 @@ test('readOnly result view hides edit and create actions for agent preview mode'
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<CustomWorldResultView
|
||||
<RpgCreationResultView
|
||||
profile={baseProfile}
|
||||
previewCharacters={[]}
|
||||
isGenerating={false}
|
||||
@@ -425,3 +442,80 @@ test('readOnly result view hides edit and create actions for agent preview mode'
|
||||
await user.click(screen.getByRole('button', { name: /场景角色/u }));
|
||||
expect(screen.queryByRole('button', { name: /批量删除/u })).toBeNull();
|
||||
});
|
||||
|
||||
test('agent result view shows publish blockers and disables publish-enter action', () => {
|
||||
render(
|
||||
<RpgCreationResultView
|
||||
profile={baseProfile}
|
||||
previewCharacters={[]}
|
||||
isGenerating={false}
|
||||
progress={0}
|
||||
progressLabel=""
|
||||
error={null}
|
||||
onBack={() => {}}
|
||||
onProfileChange={() => {}}
|
||||
compactAgentResultMode
|
||||
publishReady={false}
|
||||
publishBlockers={[
|
||||
'仍有角色缺少正式主图或动作资产,发布前需要先补齐。',
|
||||
'营地还缺少正式场景图资产,发布前需要先确认营地图。',
|
||||
]}
|
||||
qualityFindings={[
|
||||
{
|
||||
id: 'role-assets-pending',
|
||||
severity: 'warning',
|
||||
code: 'role_assets_pending',
|
||||
message: '仍有角色资产未完全补齐。',
|
||||
},
|
||||
]}
|
||||
previewSourceLabel="服务端预览"
|
||||
enterWorldActionLabel="发布并进入世界"
|
||||
onEnterWorld={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText(/当前结果页数据源:服务端预览/u)).toBeTruthy();
|
||||
expect(screen.getByText(/当前还有 2 个发布阻断项/u)).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText(/仍有角色缺少正式主图或动作资产/u),
|
||||
).toBeTruthy();
|
||||
const actionButton = screen.getByRole('button', {
|
||||
name: '发布并进入世界',
|
||||
});
|
||||
expect((actionButton as HTMLButtonElement).disabled).toBe(true);
|
||||
});
|
||||
|
||||
test('agent result view keeps publish-enter action enabled when publish gate is clear', () => {
|
||||
render(
|
||||
<RpgCreationResultView
|
||||
profile={baseProfile}
|
||||
previewCharacters={[]}
|
||||
isGenerating={false}
|
||||
progress={0}
|
||||
progressLabel=""
|
||||
error={null}
|
||||
onBack={() => {}}
|
||||
onProfileChange={() => {}}
|
||||
compactAgentResultMode
|
||||
publishReady
|
||||
publishBlockers={[]}
|
||||
qualityFindings={[
|
||||
{
|
||||
id: 'scene-assets-pending',
|
||||
severity: 'warning',
|
||||
code: 'scene_assets_pending',
|
||||
message: '仍有场景分幕图未补齐。',
|
||||
},
|
||||
]}
|
||||
previewSourceLabel="服务端预览"
|
||||
enterWorldActionLabel="发布并进入世界"
|
||||
onEnterWorld={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText(/发布后仍有 1 条 warning 可继续优化/u)).toBeTruthy();
|
||||
const actionButton = screen.getByRole('button', {
|
||||
name: '发布并进入世界',
|
||||
});
|
||||
expect((actionButton as HTMLButtonElement).disabled).toBe(false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user