refactor: 收口 RPG 结果预览门禁

This commit is contained in:
2026-06-04 03:09:13 +08:00
parent 671f5da86a
commit 23314e62aa
7 changed files with 385 additions and 151 deletions

View File

@@ -0,0 +1,168 @@
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<string, unknown> = {},
): 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(
'服务端预览',
);
});
});