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 { return { prompt: '森林棋盘', imageSrc: '/generated/match3d/background.png', imageObjectKey: null, status: 'ready', ...overrides, }; } function buildItemAsset( overrides: Partial = {}, ): Match3DGeneratedItemAsset { return { itemId: 'item-1', itemName: '蘑菇', imageSrc: '/generated/match3d/item.png', imageObjectKey: null, status: 'image_ready', ...overrides, }; } function buildProfile( overrides: Partial = {}, ): 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 { 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 { 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', ); });