295 lines
8.5 KiB
TypeScript
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',
|
|
);
|
|
});
|