openpencil/tests/engine/editor/clipboard/file-placement.test.ts
Danila Poyarkov 7e8feb998a fix(canvas): import dropped SVG files
- Parse dropped SVGs through the shared XML-backed import pipeline
- Preserve transforms, gradients, viewport alignment, and reusable shapes
- Place mixed image drops in one ordered undoable transaction
- Cover file filtering, atomic placement, undo, and browser drops

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-29 15:20:06 +03:00

65 lines
2.2 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { createEditor } from '@open-pencil/core/editor'
function svgFile(name = 'mark.svg', width = 40, height = 20) {
return new File(
[
`<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect width="${width}" height="${height}" fill="#f00"/></svg>`
],
name,
{ type: 'image/svg+xml' }
)
}
describe('dropped file placement', () => {
test('places files in order with one selection and undo entry', async () => {
const editor = createEditor()
await editor.placeFiles([svgFile(), svgFile('symbol.svg', 20, 10)], 200, 100)
const roots = editor.graph.getChildren(editor.state.currentPageId)
expect(roots.map((node) => node.name)).toEqual(['mark', 'symbol'])
expect(roots.map((node) => node.x)).toEqual([160, 220])
expect([...editor.state.selectedIds]).toEqual(roots.map((node) => node.id))
expect(editor.undo.undoLabel).toBe('Place files')
editor.undoAction()
expect(editor.graph.getChildren(editor.state.currentPageId)).toHaveLength(0)
expect(editor.state.selectedIds.size).toBe(0)
editor.redoAction()
expect(editor.graph.getChildren(editor.state.currentPageId)).toHaveLength(2)
expect(editor.state.selectedIds.size).toBe(2)
})
test('reads every file before mutating the graph', async () => {
const editor = createEditor()
const unreadable = {
name: 'broken.svg',
type: 'image/svg+xml',
text: () => Promise.reject(new Error('read failed'))
} as File
await expect(editor.placeFiles([svgFile(), unreadable], 200, 100)).rejects.toThrow(
'read failed'
)
expect(editor.graph.getChildren(editor.state.currentPageId)).toHaveLength(0)
expect(editor.undo.canUndo).toBe(false)
})
test('accepts an SVG filename when the drag source omits its MIME type', async () => {
const editor = createEditor()
const file = new File(
['<svg viewBox="0 0 10 10"><circle cx="5" cy="5" r="5"/></svg>'],
'fallback.SVG'
)
await editor.placeFiles([file], 50, 50)
const frame = editor.graph.getChildren(editor.state.currentPageId)[0]
expect(frame.name).toBe('fallback')
expect(frame.type).toBe('FRAME')
})
})