Files
Genarrative/src/services/customWorldCreatorIntent.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

203 lines
7.2 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
buildCustomWorldAnchorPackFromIntent,
buildCustomWorldCreatorIntentDisplayText,
buildCustomWorldCreatorIntentFoundationText,
buildPendingClarifications,
createEmptyCustomWorldCreatorIntent,
evaluateCustomWorldCreatorIntentReadiness,
mergeCustomWorldCreatorIntent,
normalizeCustomWorldCreatorIntent,
} from './customWorldCreatorIntent';
describe('customWorldCreatorIntent', () => {
it('builds a readable summary from creator intent cards', () => {
const intent = {
...createEmptyCustomWorldCreatorIntent('card'),
worldHook: '一个会被灵潮反复改写地形的边境世界。',
themeKeywords: ['边境', '灵潮'],
toneDirectives: ['紧张', '潮湿'],
playerPremise: '玩家是带着旧名单回来的前巡夜人。',
coreConflicts: ['旧案名单再次出现'],
keyCharacters: [
{
id: 'character-1',
name: '沈砺',
role: '灰炬向导',
publicMask: '看起来只是熟路的带路人',
hiddenHook: '他一直在追查撤离线失控真相',
relationToPlayer: '会先怀疑玩家身份',
notes: '',
locked: true,
},
],
};
const summary = buildCustomWorldCreatorIntentDisplayText(intent);
expect(summary).toContain(
'世界一句话:一个会被灵潮反复改写地形的边境世界。',
);
expect(summary).toContain('主题关键词:边境、灵潮');
expect(summary).toContain('关键角色:沈砺 / 灰炬向导');
});
it('builds six-anchor foundation text from structured creator intent', () => {
const intent = {
...createEmptyCustomWorldCreatorIntent('card'),
worldHook: '一个会被灵潮反复改写地形的边境世界。',
themeKeywords: ['边境', '灵潮'],
toneDirectives: ['紧张', '潮湿'],
playerPremise: '玩家是带着旧名单回来的前巡夜人。',
openingSituation: '返乡第一夜,封锁线外出现了本不该存在的灯火。',
coreConflicts: ['旧案名单再次出现'],
keyCharacters: [
{
id: 'character-1',
name: '沈砺',
role: '灰炬向导',
publicMask: '看起来只是熟路的带路人',
hiddenHook: '他一直在追查撤离线失控真相',
relationToPlayer: '会先怀疑玩家身份',
notes: '',
locked: true,
},
],
iconicElements: ['会逆向蔓延的潮雾'],
};
const foundationText = buildCustomWorldCreatorIntentFoundationText(intent);
expect(foundationText).toContain(
'世界一句话:一个会被灵潮反复改写地形的边境世界。',
);
expect(foundationText).toContain('玩家开局:玩家是带着旧名单回来的前巡夜人。');
expect(foundationText).toContain('主题气质:边境、灵潮 / 紧张、潮湿');
expect(foundationText).toContain('关键关系:沈砺 · 灰炬向导');
expect(foundationText).toContain('标志元素:会逆向蔓延的潮雾');
});
it('builds anchor pack from creator intent and keeps locked ids', () => {
const intent = {
...createEmptyCustomWorldCreatorIntent('card'),
worldHook: '边境世界',
coreConflicts: ['裂潮失控'],
keyFactions: [
{
id: 'faction-1',
name: '巡边司',
publicGoal: '维持边境秩序',
tension: '正在被旧案拖入裂潮',
notes: '',
locked: true,
},
],
keyLandmarks: [
{
id: 'landmark-1',
name: '断桥旧哨',
purpose: '边境咽喉',
mood: '压迫',
secret: '封桥旧令来源不明',
locked: true,
},
],
};
const anchorPack = buildCustomWorldAnchorPackFromIntent(intent);
expect(anchorPack?.keyConflictSummaries).toEqual(['裂潮失控']);
expect(anchorPack?.keyFactionSummaries[0]).toContain('巡边司');
expect(anchorPack?.lockedAnchorIds).toEqual(
expect.arrayContaining(['faction-1', 'landmark-1']),
);
});
it('normalizes sparse creator intent payloads', () => {
const intent = normalizeCustomWorldCreatorIntent({
sourceMode: 'card',
worldHook: '雾海边城',
themeKeywords: ['雾海', '旧案'],
keyCharacters: [
{
name: '梁砺',
role: '断桥巡守',
},
],
});
expect(intent?.sourceMode).toBe('card');
expect(intent?.keyCharacters[0]?.name).toBe('梁砺');
expect(intent?.keyCharacters[0]?.id).toBeTruthy();
});
it('merges creator intent patches without dropping unrelated anchors', () => {
const baseIntent = {
...createEmptyCustomWorldCreatorIntent('freeform'),
worldHook: '潮雾会改写地形的列岛世界。',
playerPremise: '玩家是失职返乡的守灯人。',
};
const merged = mergeCustomWorldCreatorIntent(baseIntent, {
coreConflicts: ['守灯会与沉船商盟争夺航道解释权'],
toneDirectives: ['冷峻'],
});
if (!merged) {
throw new Error('expected merged creator intent');
}
expect(merged.worldHook).toBe('潮雾会改写地形的列岛世界。');
expect(merged.playerPremise).toBe('玩家是失职返乡的守灯人。');
expect(merged.coreConflicts).toEqual(['守灯会与沉船商盟争夺航道解释权']);
expect(merged.toneDirectives).toEqual(['冷峻']);
});
it('replaces array anchors when a patch marks explicit rewrite fields', () => {
const merged = mergeCustomWorldCreatorIntent(
{
...createEmptyCustomWorldCreatorIntent('freeform'),
themeKeywords: ['海岛', '旧案'],
coreConflicts: ['守灯会与沉船商盟争夺航道解释权'],
},
{
themeKeywords: ['宫廷', '悬疑'],
coreConflicts: ['王庭继承人与旧灯塔盟约对抗'],
replaceFields: ['themeKeywords', 'coreConflicts'],
},
);
if (!merged) {
throw new Error('expected merged creator intent');
}
expect(merged.themeKeywords).toEqual(['宫廷', '悬疑']);
expect(merged.coreConflicts).toEqual(['王庭继承人与旧灯塔盟约对抗']);
});
it('evaluates readiness and limits clarifications to top gaps', () => {
const readiness = evaluateCustomWorldCreatorIntentReadiness({
...createEmptyCustomWorldCreatorIntent('freeform'),
worldHook: '一个被潮雾切开的列岛世界。',
themeKeywords: ['海岛'],
toneDirectives: ['冷峻'],
coreConflicts: ['旧灯塔正在被沉船商盟接管'],
});
const clarifications = buildPendingClarifications(
{
...createEmptyCustomWorldCreatorIntent('freeform'),
worldHook: '一个被潮雾切开的列岛世界。',
themeKeywords: ['海岛'],
toneDirectives: ['冷峻'],
coreConflicts: ['旧灯塔正在被沉船商盟接管'],
},
readiness,
);
expect(readiness.isReady).toBe(false);
expect(readiness.completedKeys).toContain('world_hook');
expect(readiness.missingKeys).toContain('player_premise');
expect(clarifications).toHaveLength(3);
expect(clarifications[0]?.targetKey).toBe('player_premise');
});
});