import { describe, expect, it } from 'vitest'; import type { CanvasLayer } from './ImageCanvasEditorTypes'; import { buildProjectCoverSnapshotSignature, resolveProjectCoverDrawableLayers, } from './ImageCanvasProjectCoverSnapshotModel'; function layer(overrides: Partial = {}): CanvasLayer { return { id: 'layer-a', resourceId: 'resource-a', title: '图层', src: '/generated/layer-a.png', x: 10, y: 20, width: 320, height: 240, originalWidth: 320, originalHeight: 240, zIndex: 2, sourceType: 'generated', ...overrides, }; } describe('ImageCanvasProjectCoverSnapshotModel', () => { it('builds a stable cover signature from visible drawable layers', () => { const signature = buildProjectCoverSnapshotSignature({ viewport: { x: 12, y: -8, scale: 0.75 }, layers: [ layer({ id: 'hidden', hidden: true }), layer({ id: 'audio', mediaType: 'audio', src: '/generated/audio.mp3', }), layer({ id: 'front', objectKey: 'generated/front.png', zIndex: 5, }), layer({ id: 'back', src: '/generated/back.png', zIndex: 1, }), ], }); expect(signature).toContain('"scale":0.75'); expect(signature).toContain('"id":"back"'); expect(signature).toContain('"id":"front"'); expect(signature).not.toContain('"id":"hidden"'); expect(signature).not.toContain('"id":"audio"'); }); it('uses the first image-sequence frame as the drawable source', () => { expect( resolveProjectCoverDrawableLayers([ layer({ mediaType: 'image-sequence', imageSequenceFrames: [ { frameIndex: 1, imageSrc: '/generated/frame-1.png', objectKey: 'generated/frame-1.png', width: 320, height: 240, }, ], }), ]), ).toMatchObject([ { src: '/generated/frame-1.png', objectKey: 'generated/frame-1.png', }, ]); }); });