import { describe, expect, test } from 'vitest'; import { createRpgCreationPublishedProfileFixture } from '../../../packages/shared/src/contracts/rpgCreationFixtures'; import type { CustomWorldProfile } from '../../types'; import { buildPlatformRpgAgentResultPublishGateView, type PlatformRpgAgentResultBlockerView, resolvePlatformRpgAgentResultPreviewSourceLabel, } from './platformRpgAgentResultPreviewModel'; function buildProfile( overrides: Record = {}, ): CustomWorldProfile { return { ...createRpgCreationPublishedProfileFixture(), worldHook: '潮雾列岛旧灯塔重新点亮。', playerPremise: '玩家从回潮旧灯塔切入沉船旧案。', coreConflicts: ['守灯会与沉船旧案的冲突'], sceneChapterBlueprints: [ { id: 'chapter-1', acts: [ { id: 'act-1', }, ], }, ], ...overrides, } as unknown as CustomWorldProfile; } const missingWorldHookBlocker: PlatformRpgAgentResultBlockerView = { code: 'publish_missing_world_hook', message: '缺少世界钩子', }; const missingPlayerPremiseBlocker: PlatformRpgAgentResultBlockerView = { code: 'publish_missing_player_premise', message: '缺少玩家前提', }; const missingCoreConflictBlocker: PlatformRpgAgentResultBlockerView = { code: 'publish_missing_core_conflict', message: '缺少核心冲突', }; const missingMainChapterBlocker: PlatformRpgAgentResultBlockerView = { code: 'publish_missing_main_chapter', message: '缺少主章节', }; const missingFirstActBlocker: PlatformRpgAgentResultBlockerView = { code: 'publish_missing_first_act', message: '缺少首幕', }; const structuralBlockers: PlatformRpgAgentResultBlockerView[] = [ missingWorldHookBlocker, missingPlayerPremiseBlocker, missingCoreConflictBlocker, missingMainChapterBlocker, missingFirstActBlocker, ]; describe('platformRpgAgentResultPreviewModel', () => { test('uses fallback blockers and publish readiness without a profile', () => { expect( buildPlatformRpgAgentResultPublishGateView( null, structuralBlockers.slice(0, 2), false, ), ).toEqual({ blockers: ['缺少世界钩子', '缺少玩家前提'], publishReady: false, }); }); test('filters structural blockers already satisfied by the profile', () => { expect( buildPlatformRpgAgentResultPublishGateView( buildProfile(), [ ...structuralBlockers, { code: 'future_blocker', message: '未知服务端阻断', }, ], false, ), ).toEqual({ blockers: ['未知服务端阻断'], publishReady: false, }); }); test('keeps unresolved structural blockers when profile fields are empty', () => { expect( buildPlatformRpgAgentResultPublishGateView( buildProfile({ worldHook: '', playerPremise: '', settingText: '', creatorIntent: null, anchorContent: null, coreConflicts: [], chapters: [], sceneChapterBlueprints: [], sceneChapters: [], }), structuralBlockers, true, ), ).toEqual({ blockers: structuralBlockers.map((entry) => entry.message), publishReady: false, }); }); test('resolves structural blockers from nested profile compatibility fields', () => { expect( buildPlatformRpgAgentResultPublishGateView( buildProfile({ worldHook: '', playerPremise: '', settingText: '', creatorIntent: { worldHook: '旧灯塔潮路重新开启。', }, anchorContent: { playerEntryPoint: { openingProblem: '玩家被卷入沉船旧案。', }, }, coreConflicts: [''], chapters: [], sceneChapterBlueprints: null, sceneChapters: [ { acts: [{}], }, ], }), [ missingWorldHookBlocker, missingPlayerPremiseBlocker, missingFirstActBlocker, ], false, ), ).toEqual({ blockers: [], publishReady: true, }); }); test('maps preview source to result label', () => { expect(resolvePlatformRpgAgentResultPreviewSourceLabel(null)).toBeNull(); expect( resolvePlatformRpgAgentResultPreviewSourceLabel('published_profile'), ).toBe('已发布世界'); expect( resolvePlatformRpgAgentResultPreviewSourceLabel('session_preview'), ).toBe('会话预览'); expect( resolvePlatformRpgAgentResultPreviewSourceLabel('future_source'), ).toBe( '服务端预览', ); }); });