Files
Genarrative/src/components/platform-entry/platformMatch3DRuntimeProfile.test.ts

295 lines
8.5 KiB
TypeScript

import { expect, test } from 'vitest';
import type { Match3DAgentSessionSnapshot } from '../../../packages/shared/src/contracts/match3dAgent';
import type { Match3DRunSnapshot } from '../../../packages/shared/src/contracts/match3dRuntime';
import type {
Match3DGeneratedBackgroundAsset,
Match3DGeneratedItemAsset,
Match3DWorkProfile,
} from '../../../packages/shared/src/contracts/match3dWorks';
import type { PlatformMatch3DGalleryCard } from '../rpg-entry/rpgEntryWorldPresentation';
import {
buildMatch3DProfileFromSession,
mapMatch3DWorkToPublicWorkDetail,
mapPublicWorkDetailToMatch3DWork,
resolveActiveMatch3DRuntimeProfile,
resolveMatch3DRuntimeBackgroundImageSrc,
resolveMatch3DRuntimeGeneratedBackgroundAsset,
resolveMatch3DRuntimeGeneratedItemAssets,
} from './platformMatch3DRuntimeProfile';
function buildBackgroundAsset(
overrides: Partial<Match3DGeneratedBackgroundAsset> = {},
): Match3DGeneratedBackgroundAsset {
return {
prompt: '森林棋盘',
imageSrc: '/generated/match3d/background.png',
imageObjectKey: null,
status: 'ready',
...overrides,
};
}
function buildItemAsset(
overrides: Partial<Match3DGeneratedItemAsset> = {},
): Match3DGeneratedItemAsset {
return {
itemId: 'item-1',
itemName: '蘑菇',
imageSrc: '/generated/match3d/item.png',
imageObjectKey: null,
status: 'image_ready',
...overrides,
};
}
function buildProfile(
overrides: Partial<Match3DWorkProfile> = {},
): Match3DWorkProfile {
return {
workId: 'match3d-work-1',
profileId: 'match3d-profile-1',
ownerUserId: 'user-1',
sourceSessionId: 'match3d-session-1',
gameName: '森林抓鹅',
themeText: '森林',
summary: '找出蘑菇。',
tags: ['森林', '蘑菇'],
coverImageSrc: '/cover.png',
referenceImageSrc: null,
clearCount: 12,
difficulty: 4,
publicationStatus: 'published',
playCount: 1,
updatedAt: '2026-05-20T00:00:00.000Z',
publishedAt: '2026-05-20T00:00:00.000Z',
publishReady: true,
backgroundPrompt: null,
backgroundImageSrc: null,
backgroundImageObjectKey: null,
generatedBackgroundAsset: null,
generatedItemAssets: [buildItemAsset()],
...overrides,
};
}
function buildRun(overrides: Partial<Match3DRunSnapshot> = {}): Match3DRunSnapshot {
return {
runId: 'match3d-run-1',
profileId: 'match3d-profile-1',
status: 'running',
snapshotVersion: 1,
startedAtMs: 1000,
durationLimitMs: 60000,
remainingMs: 55000,
clearCount: 12,
totalItemCount: 12,
clearedItemCount: 0,
items: [],
traySlots: [],
...overrides,
};
}
function buildPublicWork(
overrides: Partial<PlatformMatch3DGalleryCard> = {},
): PlatformMatch3DGalleryCard {
return {
sourceType: 'match3d',
workId: 'match3d-work-1',
profileId: 'match3d-profile-1',
sourceSessionId: 'match3d-session-1',
publicWorkCode: 'M3D-00000001',
ownerUserId: 'user-1',
authorDisplayName: '玩家',
worldName: '森林抓鹅',
subtitle: '抓大鹅',
summaryText: '找出蘑菇。',
coverImageSrc: '/cover.png',
backgroundPrompt: null,
backgroundImageSrc: null,
backgroundImageObjectKey: null,
generatedBackgroundAsset: null,
generatedItemAssets: [buildItemAsset()],
themeTags: ['森林', '蘑菇'],
visibility: 'published',
publishedAt: '2026-05-20T00:00:00.000Z',
updatedAt: '2026-05-20T00:00:00.000Z',
...overrides,
};
}
test('Match3D runtime profile maps public detail and promotes item background asset', () => {
const backgroundAsset = buildBackgroundAsset({
imageSrc: '/generated/match3d/background-from-item.png',
imageObjectKey: 'oss/background-from-item.png',
});
const work = mapPublicWorkDetailToMatch3DWork(
buildPublicWork({
generatedBackgroundAsset: null,
backgroundImageSrc: null,
generatedItemAssets: [
buildItemAsset({
backgroundAsset,
}),
],
}),
);
expect(work?.generatedBackgroundAsset).toEqual(backgroundAsset);
expect(work?.backgroundImageSrc).toBe(
'/generated/match3d/background-from-item.png',
);
expect(work?.backgroundImageObjectKey).toBe('oss/background-from-item.png');
});
test('Match3D runtime profile maps work summary to public detail with promoted background asset', () => {
const backgroundAsset = buildBackgroundAsset({
imageSrc: '/generated/match3d/detail-background.png',
});
const detail = mapMatch3DWorkToPublicWorkDetail(
buildProfile({
generatedBackgroundAsset: null,
backgroundImageSrc: null,
generatedItemAssets: [
buildItemAsset({
backgroundAsset,
}),
],
}),
);
expect(detail).toMatchObject({
sourceType: 'match3d',
workId: 'match3d-work-1',
profileId: 'match3d-profile-1',
backgroundImageSrc: '/generated/match3d/detail-background.png',
generatedBackgroundAsset: backgroundAsset,
});
});
test('Match3D runtime profile builds draft profile from session snapshot', () => {
const backgroundAsset = buildBackgroundAsset({
imageSrc: '/generated/match3d/draft-background.png',
});
const session: Match3DAgentSessionSnapshot = {
sessionId: 'match3d-session-draft',
currentTurn: 2,
progressPercent: 100,
stage: 'draft_compiled',
anchorPack: {
theme: { key: 'theme', label: '主题', value: '森林', status: 'confirmed' },
clearCount: {
key: 'clearCount',
label: '消除数',
value: '12',
status: 'confirmed',
},
difficulty: {
key: 'difficulty',
label: '难度',
value: '4',
status: 'confirmed',
},
},
messages: [],
lastAssistantReply: null,
updatedAt: '2026-05-21T00:00:00.000Z',
draft: {
profileId: 'match3d-draft-profile',
gameName: '草稿抓鹅',
themeText: '森林',
summaryText: '草稿摘要',
tags: ['森林'],
coverImageSrc: null,
referenceImageSrc: '/reference.png',
clearCount: 12,
difficulty: 4,
publishReady: true,
generatedItemAssets: [
buildItemAsset({
backgroundAsset,
}),
],
},
};
const profile = buildMatch3DProfileFromSession(session);
expect(profile?.profileId).toBe('match3d-draft-profile');
expect(profile?.sourceSessionId).toBe('match3d-session-draft');
expect(profile?.publicationStatus).toBe('draft');
expect(profile?.coverImageSrc).toBe('/reference.png');
expect(profile?.generatedBackgroundAsset).toEqual(backgroundAsset);
expect(profile?.backgroundImageSrc).toBe(
'/generated/match3d/draft-background.png',
);
});
test('Match3D runtime profile selects active profile by run profile id', () => {
const runtimeProfile = buildProfile({
profileId: 'runtime-profile',
gameName: '运行态抓鹅',
});
const draftProfile = buildProfile({
profileId: 'draft-profile',
gameName: '旧草稿抓鹅',
});
expect(
resolveActiveMatch3DRuntimeProfile(
buildRun({ profileId: 'runtime-profile' }),
runtimeProfile,
draftProfile,
),
).toBe(runtimeProfile);
expect(
resolveActiveMatch3DRuntimeProfile(
buildRun({ profileId: 'draft-profile' }),
runtimeProfile,
draftProfile,
),
).toBe(draftProfile);
});
test('Match3D runtime profile resolves generated assets from matching public detail', () => {
const staleProfile = buildProfile({
profileId: 'stale-profile',
generatedBackgroundAsset: buildBackgroundAsset({
imageSrc: '/generated/match3d/stale-background.png',
}),
generatedItemAssets: [
buildItemAsset({
itemId: 'stale-item',
imageSrc: '/generated/match3d/stale-item.png',
}),
],
});
const publicBackground = buildBackgroundAsset({
imageSrc: '/generated/match3d/public-background.png',
});
const publicWork = buildPublicWork({
profileId: 'public-profile',
generatedBackgroundAsset: publicBackground,
generatedItemAssets: [
buildItemAsset({
itemId: 'public-item',
imageSrc: '/generated/match3d/public-item.png',
}),
],
});
const run = buildRun({ profileId: 'public-profile' });
expect(
resolveMatch3DRuntimeGeneratedItemAssets(run, staleProfile, publicWork).some(
(asset) => asset.imageSrc === '/generated/match3d/public-item.png',
),
).toBe(true);
expect(
resolveMatch3DRuntimeGeneratedBackgroundAsset(run, staleProfile, publicWork),
).toEqual(publicBackground);
expect(resolveMatch3DRuntimeBackgroundImageSrc(run, staleProfile, publicWork)).toBe(
'/generated/match3d/public-background.png',
);
});