import { beforeAll, describe, expect, test } from 'bun:test' import { unzipSync } from 'fflate' import { exportFigFile, FigmaAPI, initCodec, parseFigFile, SceneGraph } from '@open-pencil/core' import { expectDefined } from '#tests/helpers/assert' describe('fig export/import with images', () => { beforeAll(async () => { await initCodec() }) test('exported zip contains images entries', async () => { const graph = new SceneGraph() const page = graph.getPages()[0] const figma = new FigmaAPI(graph) const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x00, 0x01, 0x02, 0x03]) const { hash } = figma.createImage(bytes) graph.createNode('RECTANGLE', page.id, { name: 'ImageNode', width: 100, height: 100, fills: [ { type: 'IMAGE', color: { r: 0, g: 0, b: 0, a: 1 }, opacity: 1, visible: true, imageHash: hash, imageScaleMode: 'FILL' } ] }) const zip = await exportFigFile(graph) const entries = unzipSync(zip) expect(entries[`images/${hash}`]).toBeDefined() expect(new Uint8Array(entries[`images/${hash}`])).toEqual(bytes) }) test('graph without images has no images entries', async () => { const graph = new SceneGraph() graph.createNode('RECTANGLE', graph.getPages()[0].id, { name: 'Plain', width: 50, height: 50 }) const zip = await exportFigFile(graph) const entries = unzipSync(zip) const imageKeys = Object.keys(entries).filter((k) => k.startsWith('images/')) expect(imageKeys).toHaveLength(0) }) test('round-trip preserves images', async () => { const graph = new SceneGraph() const page = graph.getPages()[0] const figma = new FigmaAPI(graph) const bytes1 = new Uint8Array([11, 22, 33, 44, 55]) const bytes2 = new Uint8Array([66, 77, 88, 99]) const { hash: hash1 } = figma.createImage(bytes1) const { hash: hash2 } = figma.createImage(bytes2) graph.createNode('RECTANGLE', page.id, { name: 'Img1', width: 100, height: 100, fills: [ { type: 'IMAGE', color: { r: 0, g: 0, b: 0, a: 1 }, opacity: 1, visible: true, imageHash: hash1, imageScaleMode: 'FILL' } ] }) graph.createNode('ELLIPSE', page.id, { name: 'Img2', width: 80, height: 80, fills: [ { type: 'IMAGE', color: { r: 0, g: 0, b: 0, a: 1 }, opacity: 1, visible: true, imageHash: hash2, imageScaleMode: 'FIT' } ] }) const zip = await exportFigFile(graph) const restored = await parseFigFile(zip.buffer as ArrayBuffer) expect(restored.images.size).toBe(2) expect(new Uint8Array(expectDefined(restored.images.get(hash1), 'restored image 1'))).toEqual( bytes1 ) expect(new Uint8Array(expectDefined(restored.images.get(hash2), 'restored image 2'))).toEqual( bytes2 ) const restoredImg1 = expectDefined( [...restored.getAllNodes()].find((node) => node.name === 'Img1'), 'restored image node 1' ) const restoredImg2 = expectDefined( [...restored.getAllNodes()].find((node) => node.name === 'Img2'), 'restored image node 2' ) expect(restoredImg1.fills[0].imageHash).toBe(hash1) expect(restoredImg2.fills[0].imageHash).toBe(hash2) }) })