import { describe, expect, it } from 'vitest'; import type { CanvasGenerationInputs, CanvasLayer, } from './ImageCanvasEditorTypes'; import { createGeneratedResultLayer, createIconSpritesheetResultLayers, createQuickEditResultLayer, } from './ImageCanvasGenerationLayerModel'; function createGenerated(overrides = {}) { return { imageSrc: 'data:image/png;base64,generated', width: 1024, height: 1024, sourceType: 'generated' as const, prompt: '生成提示词', actualPrompt: '实际提示词', model: 'gpt-image-2', provider: 'VectorEngine', taskId: 'task-generated', objectKey: 'generated/object.png', assetObjectId: 'asset-object-generated', ...overrides, }; } function createSourceLayer(overrides: Partial = {}): CanvasLayer { return { id: 'layer-source', resourceId: 'resource-source', title: '源图', src: 'data:image/png;base64,source', x: 120, y: 140, width: 320, height: 240, originalWidth: 1536, originalHeight: 1024, zIndex: 2, sourceType: 'generated', groupId: 'group-a', assetKind: 'spec', ...overrides, }; } function createGenerationInputs(): CanvasGenerationInputs { return { fields: [{ title: '生成提示词', value: '生成提示词' }], references: [], }; } describe('ImageCanvasGenerationLayerModel', () => { it('creates generated result layers centered on the active placeholder', () => { const layer = createGeneratedResultLayer({ generated: createGenerated({ width: 2048, height: 1152 }), generatedIndex: 7, canvasSize: { width: 900, height: 640 }, viewport: { x: 10, y: 20, scale: 2 }, frame: { x: 80, y: 60, width: 560, height: 315, originalWidth: 2048, originalHeight: 1152, }, assetKind: 'spec', title: 'UI素材规范 7', generationInputs: createGenerationInputs(), }); expect(layer).toMatchObject({ id: 'layer-generated-7', resourceId: 'local-resource-generated-7', title: 'UI素材规范 7', x: -664, y: -358.5, width: 2048, height: 1152, originalWidth: 2048, originalHeight: 1152, zIndex: 17, sourceType: 'generated', assetKind: 'spec', prompt: '生成提示词', actualPrompt: '实际提示词', objectKey: 'generated/object.png', assetObjectId: 'asset-object-generated', }); expect(layer.generationInputs?.fields[0]?.value).toBe('生成提示词'); }); it('creates edit result layers beside the source image', () => { const sourceLayer = createSourceLayer(); const layer = createGeneratedResultLayer({ generated: createGenerated({ prompt: '修改要求' }), generatedIndex: 8, canvasSize: { width: 900, height: 640 }, viewport: { x: 0, y: 0, scale: 1 }, sourceLayer, generationInputs: createGenerationInputs(), }); expect(layer).toMatchObject({ id: 'layer-edit-8', resourceId: 'local-resource-edit-8', title: '源图 修改结果', x: 472, y: 140, width: 1024, height: 1024, sourceResourceId: 'resource-source', prompt: '修改要求', }); }); it('creates quick edit layers with source group and asset kind preserved', () => { const sourceLayer = createSourceLayer(); const layer = createQuickEditResultLayer({ generated: createGenerated({ width: 1536, height: 1024 }), generatedIndex: 9, sourceLayer, generationInputs: createGenerationInputs(), }); expect(layer).toMatchObject({ id: 'layer-quick-edit-9', resourceId: 'local-resource-quick-edit-9', title: '源图 快速编辑', x: 472, y: 140, width: 1536, height: 1024, originalWidth: 1536, originalHeight: 1024, sourceResourceId: 'resource-source', groupId: 'group-a', assetKind: 'spec', }); }); it('creates wrapped icon layers with icon metadata', () => { const layers = createIconSpritesheetResultLayers({ generated: { spritesheetImageSrc: 'data:image/png;base64,sheet', spritesheetWidth: 512, spritesheetHeight: 512, iconImageSrcs: [], prompt: '图标 prompt', actualPrompt: '图标 actual prompt', model: 'gpt-image-2', provider: 'VectorEngine', taskId: 'task-icons', }, iconResults: [ { name: '返回按钮', imageSrc: 'data:image/png;base64,back', width: 256, height: 256, }, { name: '设置按钮', imageSrc: 'data:image/png;base64,settings', width: 512, height: 256, }, { name: '提示按钮', imageSrc: 'data:image/png;base64,hint', width: 128, height: 128, }, ], startIndex: 11, canvasSize: { width: 900, height: 640 }, viewport: { x: 0, y: 0, scale: 1 }, frame: { x: 200, y: 100, width: 360, height: 360, originalWidth: 512, originalHeight: 512, }, generationInputs: createGenerationInputs(), }); expect(layers).toHaveLength(3); expect(layers[0]).toMatchObject({ id: 'layer-icon-11', title: '返回按钮', x: 200, y: 100, width: 256, height: 256, assetKind: 'icon', prompt: '图标 prompt', actualPrompt: '图标 actual prompt', }); expect(layers[1]).toMatchObject({ id: 'layer-icon-12', title: '设置按钮', x: 200, y: 380, width: 512, height: 256, assetKind: 'icon', }); expect(layers[2]).toMatchObject({ id: 'layer-icon-13', title: '提示按钮', x: 200, y: 660, width: 128, height: 128, assetKind: 'icon', }); }); });