This commit is contained in:
231
src/services/rpg-creation/rpgCreationPreviewAdapter.test.ts
Normal file
231
src/services/rpg-creation/rpgCreationPreviewAdapter.test.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import type { CustomWorldAgentSessionSnapshot } from '../../../packages/shared/src/contracts/customWorldAgent';
|
||||
import {
|
||||
buildRpgCreationPreviewFromResultPreview,
|
||||
buildRpgCreationPreviewFromSession,
|
||||
} from './rpgCreationPreviewAdapter';
|
||||
|
||||
const sessionWithPreview: CustomWorldAgentSessionSnapshot = {
|
||||
sessionId: 'session-preview-1',
|
||||
currentTurn: 3,
|
||||
anchorContent: {
|
||||
worldPromise: null,
|
||||
playerFantasy: null,
|
||||
themeBoundary: null,
|
||||
playerEntryPoint: null,
|
||||
coreConflict: null,
|
||||
keyRelationships: null,
|
||||
hiddenLines: null,
|
||||
iconicElements: null,
|
||||
},
|
||||
progressPercent: 100,
|
||||
lastAssistantReply: '第一版世界底稿已经准备好了。',
|
||||
stage: 'object_refining',
|
||||
focusCardId: null,
|
||||
creatorIntent: null,
|
||||
creatorIntentReadiness: {
|
||||
isReady: true,
|
||||
completedKeys: [],
|
||||
missingKeys: [],
|
||||
},
|
||||
anchorPack: null,
|
||||
lockState: null,
|
||||
draftProfile: {
|
||||
id: 'draft-profile-1',
|
||||
settingText: '草稿 profile 直接进入游戏。',
|
||||
name: '只作为 fallback 的本地草稿名',
|
||||
subtitle: 'fallback',
|
||||
summary: 'fallback',
|
||||
tone: 'fallback',
|
||||
playerGoal: 'fallback',
|
||||
templateWorldType: 'WUXIA',
|
||||
majorFactions: [],
|
||||
coreConflicts: [],
|
||||
attributeSchema: {
|
||||
id: 'schema:draft:test',
|
||||
worldId: 'custom:草稿',
|
||||
schemaVersion: 1,
|
||||
schemaName: '草稿六维',
|
||||
generatedFrom: {
|
||||
worldType: 'CUSTOM',
|
||||
worldName: '只作为 fallback 的本地草稿名',
|
||||
settingSummary: '草稿 profile 直接进入游戏。',
|
||||
tone: 'fallback',
|
||||
conflictCore: '验证草稿直读链路',
|
||||
},
|
||||
slots: [
|
||||
{
|
||||
slotId: 'axis_a',
|
||||
name: '稿骨',
|
||||
definition: '草稿承压维度。',
|
||||
positiveSignals: ['承压'],
|
||||
negativeSignals: ['虚浮'],
|
||||
combatUseText: '顶住正面压力。',
|
||||
socialUseText: '稳住对话姿态。',
|
||||
explorationUseText: '维持探索状态。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_b',
|
||||
name: '稿步',
|
||||
definition: '草稿换位维度。',
|
||||
positiveSignals: ['灵动'],
|
||||
negativeSignals: ['迟滞'],
|
||||
combatUseText: '快速换位。',
|
||||
socialUseText: '顺势接话。',
|
||||
explorationUseText: '穿越复杂路径。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_c',
|
||||
name: '稿识',
|
||||
definition: '草稿洞察维度。',
|
||||
positiveSignals: ['洞察'],
|
||||
negativeSignals: ['误判'],
|
||||
combatUseText: '看破破绽。',
|
||||
socialUseText: '识别隐藏动机。',
|
||||
explorationUseText: '整理线索。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_d',
|
||||
name: '稿魄',
|
||||
definition: '草稿推进维度。',
|
||||
positiveSignals: ['果断'],
|
||||
negativeSignals: ['犹疑'],
|
||||
combatUseText: '推进突破口。',
|
||||
socialUseText: '关键时刻定调。',
|
||||
explorationUseText: '面对未知继续前探。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_e',
|
||||
name: '稿契',
|
||||
definition: '草稿关系维度。',
|
||||
positiveSignals: ['协同'],
|
||||
negativeSignals: ['疏离'],
|
||||
combatUseText: '形成协同收益。',
|
||||
socialUseText: '建立信任交换。',
|
||||
explorationUseText: '从关系打开线索。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_f',
|
||||
name: '稿澜',
|
||||
definition: '草稿续航维度。',
|
||||
positiveSignals: ['回稳'],
|
||||
negativeSignals: ['紊乱'],
|
||||
combatUseText: '久战不乱。',
|
||||
socialUseText: '情绪稳定。',
|
||||
explorationUseText: '长线保持行动力。',
|
||||
},
|
||||
],
|
||||
},
|
||||
playableNpcs: [
|
||||
{
|
||||
id: 'draft-playable-1',
|
||||
name: '草稿角色',
|
||||
title: '直读测试',
|
||||
role: '可扮演角色',
|
||||
description: '从 draftProfile 直接进入角色选择页。',
|
||||
backstory: '草稿角色的背景不经过 resultPreview 转换。',
|
||||
personality: '直接、清醒',
|
||||
motivation: '验证草稿直读链路',
|
||||
combatStyle: '以直读链路破局',
|
||||
initialAffinity: 18,
|
||||
relationshipHooks: ['来自草稿'],
|
||||
tags: ['draft-profile'],
|
||||
skills: [],
|
||||
initialItems: [],
|
||||
imageSrc: '/generated-characters/draft-playable-1/portrait.png',
|
||||
},
|
||||
],
|
||||
storyNpcs: [],
|
||||
items: [],
|
||||
landmarks: [],
|
||||
},
|
||||
messages: [],
|
||||
draftCards: [
|
||||
{
|
||||
id: 'world-foundation',
|
||||
kind: 'world',
|
||||
title: '世界底稿',
|
||||
subtitle: '阶段三预览',
|
||||
summary: '测试服务端 result preview 优先级。',
|
||||
status: 'warning',
|
||||
linkedIds: [],
|
||||
warningCount: 0,
|
||||
},
|
||||
],
|
||||
pendingClarifications: [],
|
||||
suggestedActions: [],
|
||||
recommendedReplies: [],
|
||||
qualityFindings: [],
|
||||
assetCoverage: {
|
||||
roleAssets: [],
|
||||
sceneAssets: [],
|
||||
allRoleAssetsReady: false,
|
||||
allSceneAssetsReady: false,
|
||||
},
|
||||
resultPreview: {
|
||||
source: 'session_preview',
|
||||
preview: {
|
||||
id: 'preview-profile-1',
|
||||
settingText: '被海雾吞没的旧航路群岛',
|
||||
name: '服务端结果预览',
|
||||
subtitle: '优先于前端 fallback',
|
||||
summary: '结果页应该优先消费 session.resultPreview。',
|
||||
tone: '压抑、潮湿、悬疑',
|
||||
playerGoal: '查清沉船与禁航区异动的真相。',
|
||||
templateWorldType: 'WUXIA',
|
||||
majorFactions: ['守灯会', '航运公会'],
|
||||
coreConflicts: ['守灯会与航运公会争夺旧航路控制权'],
|
||||
playableNpcs: [],
|
||||
storyNpcs: [],
|
||||
items: [],
|
||||
landmarks: [],
|
||||
generationMode: 'full',
|
||||
generationStatus: 'complete',
|
||||
sessionId: 'session-preview-1',
|
||||
},
|
||||
generatedAt: '2026-04-21T10:00:00.000Z',
|
||||
qualityFindings: [],
|
||||
blockers: [],
|
||||
},
|
||||
updatedAt: '2026-04-21T10:00:00.000Z',
|
||||
};
|
||||
|
||||
test('buildRpgCreationPreviewFromResultPreview normalizes server preview envelope', () => {
|
||||
const profile = buildRpgCreationPreviewFromResultPreview(
|
||||
sessionWithPreview.resultPreview,
|
||||
);
|
||||
|
||||
expect(profile?.name).toBe('服务端结果预览');
|
||||
expect(profile?.subtitle).toBe('优先于前端 fallback');
|
||||
expect(profile?.id).toBe('preview-profile-1');
|
||||
expect(profile?.settingText).toBe('被海雾吞没的旧航路群岛');
|
||||
});
|
||||
|
||||
test('buildRpgCreationPreviewFromSession prefers server result preview', () => {
|
||||
const profile = buildRpgCreationPreviewFromSession(sessionWithPreview);
|
||||
|
||||
expect(profile?.name).toBe('服务端结果预览');
|
||||
expect(profile?.summary).toBe('结果页应该优先消费 session.resultPreview。');
|
||||
expect(profile?.id).toBe('preview-profile-1');
|
||||
});
|
||||
|
||||
test('buildRpgCreationPreviewFromSession does not require resultPreview', () => {
|
||||
const profile = buildRpgCreationPreviewFromSession({
|
||||
...sessionWithPreview,
|
||||
resultPreview: null,
|
||||
});
|
||||
|
||||
expect(profile?.name).toBe('只作为 fallback 的本地草稿名');
|
||||
expect(profile?.playableNpcs[0]?.imageSrc).toBe(
|
||||
'/generated-characters/draft-playable-1/portrait.png',
|
||||
);
|
||||
expect(profile?.attributeSchema.slots.map((slot) => slot.name)).toEqual([
|
||||
'稿骨',
|
||||
'稿步',
|
||||
'稿识',
|
||||
'稿魄',
|
||||
'稿契',
|
||||
'稿澜',
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user