From 544f9ac040c1b44e17d7d6529363b0e71f244c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 23 Sep 2026 21:35:57 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=20UI=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=A1=A5=E6=8E=A5=E5=8D=95=E6=B5=8B=E5=88=B0?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 退役 ensureUiDesignResourceForPrototype / findLinkedUiDesignResource 的 6 条旧用例已随实现删除而无对应导出,测试文件整体失败 - 改为覆盖 createUiDesignDocFromImages:空图片列表拒绝且不调用命令,正常调用透传项目身份与设计图引用 --- .../tests/uiDesignResourceBridge.test.ts | 220 +++--------------- 1 file changed, 31 insertions(+), 189 deletions(-) diff --git a/apps/ai-game-creator-shell/tests/uiDesignResourceBridge.test.ts b/apps/ai-game-creator-shell/tests/uiDesignResourceBridge.test.ts index 42d2f5003..e7b65929c 100644 --- a/apps/ai-game-creator-shell/tests/uiDesignResourceBridge.test.ts +++ b/apps/ai-game-creator-shell/tests/uiDesignResourceBridge.test.ts @@ -1,201 +1,43 @@ import { describe, expect, it, vi } from 'vitest'; -import type { - GameCreationAppAssetManifestEntry, - GameCreationAppManifest, -} from '../../../packages/shared/src/contracts/gameCreationApp'; -import { - GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, -} from '../../../packages/shared/src/contracts/gameCreationApp'; -import { - ensureUiDesignResourceForPrototype, - findLinkedUiDesignResource, -} from '../src/features/ui-editor/uiDesignResourceBridge'; - -function manifestWithPrototype(): GameCreationAppManifest { - const prototype: GameCreationAppAssetManifestEntry = { - id: 'prototype-asset', - kind: 'ui-design', - mediaType: 'image/png', - localPath: 'assets/ui-prototype.png', - source: { kind: 'canvas', referenceResourceIds: [] }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }; - return { - schemaVersion: 'game-creator-app.v1', - projectId: 'project-1', - projectName: 'UI bridge', - tasks: [], - assets: [prototype], - versions: [], - godotProjectRoot: null, - preview: null, - resourceCanvasLayouts: [], - } as unknown as GameCreationAppManifest; -} +import { createUiDesignDocFromImages } from '../src/features/ui-editor/uiDesignResourceBridge'; describe('ui design resource bridge', () => { - it('finds only a JSON UI resource linked to the exact prototype asset', () => { - const manifest = manifestWithPrototype(); - manifest.assets.push({ - id: 'unrelated-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/unrelated.json', - source: { kind: 'generated', referenceResourceIds: ['other'] }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }); - expect(findLinkedUiDesignResource(manifest, 'prototype-asset')).toBeNull(); - manifest.assets.push({ - id: 'linked-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/linked.json', - source: { kind: 'generated', referenceResourceIds: ['prototype-asset'] }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }); - expect(findLinkedUiDesignResource(manifest, 'prototype-asset')?.id).toBe( - 'linked-ui', - ); - }); - - it('reuses workflow resources linked by the prototype canonical resource id', () => { - const manifest = manifestWithPrototype(); - manifest.assets[0]!.source.resourceId = 'canvas-resource-1'; - manifest.assets.push({ - id: 'workflow-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/workflow.json', - source: { - kind: 'generated', - resourceId: 'ui-workflow-page-1', - referenceResourceIds: ['canvas-resource-1', 'design-resource-1'], - }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }); - expect(findLinkedUiDesignResource(manifest, 'prototype-asset')?.id).toBe( - 'workflow-ui', - ); - }); - - it('prefers a completed workflow resource when an older bridge resource also matches', () => { - const manifest = manifestWithPrototype(); - manifest.assets.push( - { - id: 'bridge-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/UI 设计 1.json', - source: { - kind: 'generated', - referenceResourceIds: ['prototype-asset'], - }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }, - { - id: 'completed-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/ui-workflow-page.json', - source: { - kind: 'generated', - generationKind: 'ui-workflow.completed', - referenceResourceIds: ['prototype-asset'], - }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }, - ); - expect(findLinkedUiDesignResource(manifest, 'prototype-asset')?.id).toBe( - 'completed-ui', - ); - }); - - it('reuses an existing link without invoking a mutating command', async () => { - const manifest = manifestWithPrototype(); - const linked = { - id: 'linked-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/linked.json', - source: { - kind: 'generated' as const, - referenceResourceIds: ['prototype-asset'], - }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }; - manifest.assets.push(linked); + it('rejects an empty image list without invoking the command', async () => { const invoke = vi.fn(); - const result = await ensureUiDesignResourceForPrototype({ + await expect( + createUiDesignDocFromImages({ + projectPath: '/project', + expectedProjectId: 'project-1', + images: [], + invoke, + }), + ).rejects.toThrow('请至少选择一张界面图'); + expect(invoke).not.toHaveBeenCalled(); + }); + + it('creates a document through the command with the project identity injected', async () => { + const created = { + asset: { id: 'ui-1' }, + manifest: { projectId: 'project-1' }, + relativePath: 'ui/UI 设计 1.json', + imageIds: ['image-a'], + committedProjectRevision: 7, + }; + const invoke = vi.fn().mockResolvedValue(created); + const result = await createUiDesignDocFromImages({ projectPath: '/project', - manifest, - prototypeAssetId: 'prototype-asset', + expectedProjectId: 'project-1', + images: [{ assetId: 'image-a', path: null }], invoke, }); - expect(result.asset).toEqual(linked); - expect(result.created).toBe(false); - expect(invoke).not.toHaveBeenCalled(); - }); - - it('invokes the atomic Tauri bridge for a missing link', async () => { - const manifest = manifestWithPrototype(); - const result = { - asset: { - id: 'new-ui', - kind: GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND, - mediaType: GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, - localPath: 'ui/UI 设计 1.json', - source: { - kind: 'generated' as const, - referenceResourceIds: ['prototype-asset'], - }, - imageSequenceFrames: null, - imageSequenceDurationMs: null, - }, - manifest: { ...manifest, assets: [...manifest.assets] }, - committedProjectRevision: 7, - created: true, - }; - const invoke = vi.fn().mockResolvedValue(result); - await expect( - ensureUiDesignResourceForPrototype({ + expect(invoke).toHaveBeenCalledWith('create_ui_design_doc_from_images', { + input: { projectPath: '/project', - manifest, - prototypeAssetId: ' prototype-asset ', - invoke, - }), - ).resolves.toEqual(result); - expect(invoke).toHaveBeenCalledWith( - 'ensure_ui_design_resource_for_prototype', - { - input: { - projectPath: '/project', - expectedProjectId: 'project-1', - prototypeAssetId: 'prototype-asset', - }, + expectedProjectId: 'project-1', + images: [{ assetId: 'image-a', path: null }], }, - ); - }); - - it('rejects non-prototype assets before invoking Tauri', async () => { - const manifest = manifestWithPrototype(); - const invoke = vi.fn(); - await expect( - ensureUiDesignResourceForPrototype({ - projectPath: '/project', - manifest, - prototypeAssetId: 'missing', - invoke, - }), - ).rejects.toThrow('目标资源不是 UI 原型图片'); - expect(invoke).not.toHaveBeenCalled(); + }); + expect(result).toBe(created); }); });