This commit is contained in:
150
src/services/customWorldCover.test.ts
Normal file
150
src/services/customWorldCover.test.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { WorldType, type CustomWorldProfile } from '../types';
|
||||
import { resolveCustomWorldCoverPresentation } from './customWorldCover';
|
||||
|
||||
function createBaseProfile(): CustomWorldProfile {
|
||||
return {
|
||||
id: 'custom-world-cover-test',
|
||||
settingText: '潮雾群岛',
|
||||
name: '潮雾群岛',
|
||||
subtitle: '封面规则测试',
|
||||
summary: '用于验证默认封面优先级。',
|
||||
tone: '潮湿、压抑',
|
||||
playerGoal: '查明旧航道真相。',
|
||||
templateWorldType: WorldType.WUXIA,
|
||||
compatibilityTemplateWorldType: WorldType.WUXIA,
|
||||
majorFactions: [],
|
||||
coreConflicts: [],
|
||||
attributeSchema: {
|
||||
id: 'schema:test',
|
||||
worldId: 'CUSTOM',
|
||||
schemaVersion: 1,
|
||||
schemaName: '测试属性',
|
||||
generatedFrom: {
|
||||
worldType: WorldType.CUSTOM,
|
||||
worldName: '潮雾群岛',
|
||||
settingSummary: '封面规则测试',
|
||||
tone: '潮湿、压抑',
|
||||
conflictCore: '旧航道真相',
|
||||
},
|
||||
slots: [],
|
||||
},
|
||||
playableNpcs: [
|
||||
{
|
||||
id: 'playable-1',
|
||||
name: '林潮',
|
||||
title: '守潮人',
|
||||
role: '可扮演角色',
|
||||
description: '负责守住第一道进港口。',
|
||||
backstory: '他在港口旧案里失去过同伴。',
|
||||
personality: '谨慎克制。',
|
||||
motivation: '想查清货船去向。',
|
||||
combatStyle: '借地形换位。',
|
||||
initialAffinity: 20,
|
||||
relationshipHooks: ['旧案'],
|
||||
tags: ['港口'],
|
||||
backstoryReveal: {
|
||||
publicSummary: '他对港口格外熟悉。',
|
||||
chapters: [],
|
||||
},
|
||||
skills: [],
|
||||
initialItems: [],
|
||||
imageSrc: '/images/roles/linchao.webp',
|
||||
},
|
||||
],
|
||||
storyNpcs: [],
|
||||
items: [],
|
||||
camp: {
|
||||
id: 'camp-1',
|
||||
name: '守夜营地',
|
||||
description: '潮线后的临时据点。',
|
||||
imageSrc: '/images/camp/camp.webp',
|
||||
sceneNpcIds: [],
|
||||
connections: [],
|
||||
},
|
||||
landmarks: [
|
||||
{
|
||||
id: 'landmark-1',
|
||||
name: '潮汐码头',
|
||||
description: '涨潮时会吞掉半截栈桥。',
|
||||
imageSrc: '/images/landmark/docks.webp',
|
||||
sceneNpcIds: [],
|
||||
connections: [],
|
||||
},
|
||||
],
|
||||
sceneChapterBlueprints: [
|
||||
{
|
||||
id: 'scene-chapter-1',
|
||||
sceneId: 'landmark-1',
|
||||
title: '潮汐码头',
|
||||
summary: '第一章开局场景。',
|
||||
sceneTaskDescription: '追查潮汐码头失踪案的第一条线索。',
|
||||
linkedThreadIds: [],
|
||||
linkedLandmarkIds: ['landmark-1'],
|
||||
acts: [
|
||||
{
|
||||
id: 'act-1',
|
||||
sceneId: 'landmark-1',
|
||||
title: '雾里靠岸',
|
||||
summary: '玩家第一次进入港口。',
|
||||
stageCoverage: ['opening'],
|
||||
backgroundImageSrc: '/images/scene/act-1.webp',
|
||||
backgroundAssetId: 'asset-scene-act-1',
|
||||
encounterNpcIds: [],
|
||||
primaryNpcId: 'playable-1',
|
||||
oppositeNpcId: 'playable-1',
|
||||
eventDescription: '玩家第一次进入港口,发现涨潮后的异常痕迹。',
|
||||
linkedThreadIds: [],
|
||||
advanceRule: 'after_primary_contact',
|
||||
actGoal: '拿到第一句真话。',
|
||||
transitionHook: '下一幕将进入封锁区。',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
describe('resolveCustomWorldCoverPresentation', () => {
|
||||
it('优先使用开局场景第一幕图片作为默认封面底图', () => {
|
||||
const profile = createBaseProfile();
|
||||
|
||||
const result = resolveCustomWorldCoverPresentation(profile);
|
||||
|
||||
expect(result.imageSrc).toBe('/images/scene/act-1.webp');
|
||||
expect(result.renderMode).toBe('scene_with_roles');
|
||||
expect(result.characterImageSrcs).toEqual(['/images/roles/linchao.webp']);
|
||||
});
|
||||
|
||||
it('当第一幕图片缺失时按营地图与地标图顺序回退', () => {
|
||||
const profile = createBaseProfile();
|
||||
const firstSceneChapter = profile.sceneChapterBlueprints?.[0];
|
||||
const firstSceneAct = firstSceneChapter?.acts[0];
|
||||
if (!firstSceneChapter || !firstSceneAct) {
|
||||
throw new Error('expected base profile to provide an opening scene chapter');
|
||||
}
|
||||
profile.sceneChapterBlueprints = [
|
||||
{
|
||||
...firstSceneChapter,
|
||||
acts: [
|
||||
{
|
||||
...firstSceneAct,
|
||||
backgroundImageSrc: null,
|
||||
backgroundAssetId: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const fallbackToCamp = resolveCustomWorldCoverPresentation(profile);
|
||||
expect(fallbackToCamp.imageSrc).toBe('/images/camp/camp.webp');
|
||||
|
||||
profile.camp = {
|
||||
...profile.camp!,
|
||||
imageSrc: '',
|
||||
};
|
||||
const fallbackToLandmark = resolveCustomWorldCoverPresentation(profile);
|
||||
expect(fallbackToLandmark.imageSrc).toBe('/images/landmark/docks.webp');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user