Files
Genarrative/src/services/customWorldBuilder.test.ts
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

100 lines
5.3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { buildExpandedCustomWorldProfile } from './customWorldBuilder';
describe('buildExpandedCustomWorldProfile', () => {
it('attaches theme pack, story graph, and narrative profiles', () => {
const profile = buildExpandedCustomWorldProfile(
{
id: 'custom-world-test',
name: '裂潮边城',
subtitle: '风暴前夜',
summary: '一座被裂潮与旧案同时牵动的边城。',
tone: '紧张、克制、暗流涌动',
playerGoal: '查清边城裂潮背后的真相',
templateWorldType: 'WUXIA',
majorFactions: ['巡边司', '潮商会'],
coreConflicts: ['裂潮反复冲垮旧防线', '旧案名单再次出现'],
playableNpcs: [
{
id: 'playable-1',
name: '沈砺',
title: '灰炬向导',
role: '向导',
description: '熟悉裂潮边路的灰炬向导。',
backstory: '曾在旧撤离线里失去一整支同行队。',
personality: '谨慎寡言,先看风向再开口。',
motivation: '想查清旧撤离线为何再次失控。',
combatStyle: '短弓牵制后贴近补刀。',
initialAffinity: 18,
relationshipHooks: ['旧撤离线', '名单'],
tags: ['裂潮', '向导'],
backstoryReveal: {
publicSummary: '他只说自己熟悉边路。',
chapters: [
{ id: 'surface', title: '表层来意', affinityRequired: 0, teaser: '他总盯着风向和路标。', content: '他先把注意力放在边路是否还能走。 ', contextSnippet: '他总先谈路和风。' },
{ id: 'scar', title: '旧事裂痕', affinityRequired: 30, teaser: '旧撤离线像在他身上留下了什么。', content: '那次撤离失控后,他一直没再离开这片边路。', contextSnippet: '撤离旧事还没过去。' },
{ id: 'bind', title: '隐藏执念', affinityRequired: 60, teaser: '名单上的名字让他一直不肯放手。', content: '他一直在比对那份回响名单与旧撤离线。', contextSnippet: '他一直在查名单。' },
{ id: 'truth', title: '最终底牌', affinityRequired: 90, teaser: '他知道裂潮里有人故意改过路标。', content: '他怀疑有人借裂潮重启旧案。', contextSnippet: '有人在利用裂潮。' },
],
},
skills: [],
initialItems: [],
},
],
storyNpcs: [
{
id: 'story-1',
name: '梁砺',
title: '断桥巡守',
role: '巡守',
description: '守着断桥与旧哨火的巡守。',
backstory: '旧案爆发时,他是最后一个封桥的人。',
personality: '警觉直接,不喜欢绕弯。',
motivation: '不想让旧案再次借裂潮翻上来。',
combatStyle: '长兵先压,再卡住路口。',
initialAffinity: 6,
relationshipHooks: ['封桥', '旧哨火'],
tags: ['巡守', '断桥'],
backstoryReveal: {
publicSummary: '他只承认自己还在守桥。',
chapters: [
{ id: 'surface', title: '表层来意', affinityRequired: 0, teaser: '他只说桥还不能放开。', content: '他总先谈桥和路。', contextSnippet: '桥还不能放开。' },
{ id: 'scar', title: '旧事裂痕', affinityRequired: 30, teaser: '封桥那夜明显留下了后劲。', content: '他始终忘不了那夜桥上的名单。', contextSnippet: '封桥旧事还压着他。' },
{ id: 'bind', title: '隐藏执念', affinityRequired: 60, teaser: '他像还在替谁守着一个错误。', content: '他一直替旧命令继续守线。', contextSnippet: '他还在守旧命令。' },
{ id: 'truth', title: '最终底牌', affinityRequired: 90, teaser: '有人逼他在封桥和救人之间选过。', content: '那夜真正下封桥令的人还没有露面。', contextSnippet: '封桥命令另有来头。' },
],
},
skills: [],
initialItems: [],
},
],
items: [],
landmarks: [
{
id: 'landmark-1',
name: '断桥旧哨',
description: '旧哨火和断桥一起守着边城北口。',
sceneNpcIds: ['story-1'],
connections: [],
},
],
},
'玩家想要一个裂潮边城与旧案回响交织的世界。',
);
expect(profile.themePack?.displayName).toBeTruthy();
expect(profile.storyGraph?.visibleThreads.length).toBeGreaterThan(0);
expect(profile.storyGraph?.hiddenThreads.length).toBeGreaterThan(0);
expect(profile.storyNpcs[0]?.narrativeProfile?.immediatePressure).toBeTruthy();
expect(profile.playableNpcs[0]?.narrativeProfile?.relatedThreadIds.length).toBeGreaterThan(0);
expect(profile.ownedSettingLayers?.expressionProfile.themePack.displayName).toBe(
profile.themePack?.displayName,
);
expect(profile.ownedSettingLayers?.referenceProfile.roleArchetypes.length).toBeGreaterThan(0);
expect(profile.ownedSettingLayers?.compatibilityProfile?.legacyTemplateWorldType).toBe(
'WUXIA',
);
});
});