import { TLEmbedShape } from '@tldraw/editor' import { defaultHandleExternalEmbedContent } from '../lib/defaultExternalContentHandlers' import { extractIframeFromHtml } from '../lib/ui/hooks/useClipboardEvents' import { TestEditor } from './TestEditor' let editor: TestEditor beforeEach(() => { editor = new TestEditor() editor.selectAll().deleteShapes(editor.getSelectedShapeIds()) }) afterEach(() => { editor?.dispose() }) describe('extractIframeFromHtml', () => { it('extracts iframe with width and height attributes', () => { const result = extractIframeFromHtml( '' ) expect(result).toEqual({ src: 'https://www.openstreetmap.org/export/embed.html?bbox=-0.1258', width: 425, height: 350, }) }) it('extracts iframe with surrounding HTML content', () => { const result = extractIframeFromHtml( '
View Larger Map' ) expect(result).not.toBeNull() expect(result!.src).toBe('https://www.openstreetmap.org/export/embed.html') expect(result!.width).toBe(425) expect(result!.height).toBe(350) }) it('extracts iframe with style-only dimensions (percentage-based falls back to defaults)', () => { const result = extractIframeFromHtml( '' ) expect(result).not.toBeNull() expect(result!.src).toContain('w.soundcloud.com/player') expect(result!.width).toBe(425) expect(result!.height).toBe(350) }) it('extracts pixel dimensions from style attribute', () => { const result = extractIframeFromHtml( '' ) expect(result).toEqual({ src: 'https://example.com/embed', width: 600, height: 400, }) }) it('prefers HTML attributes over style dimensions', () => { const result = extractIframeFromHtml( '' ) expect(result).toEqual({ src: 'https://example.com/embed', width: 800, height: 600, }) }) it('returns null for non-HTTP src', () => { const result = extractIframeFromHtml( '' ) expect(result).toBeNull() }) it('returns null for missing src', () => { const result = extractIframeFromHtml('') expect(result).toBeNull() }) it('returns null for non-iframe HTML', () => { const result = extractIframeFromHtml('
Hello world
') expect(result).toBeNull() }) it('returns null for empty string', () => { const result = extractIframeFromHtml('') expect(result).toBeNull() }) }) describe('Pasting arbitrary iframe embeds', () => { it('creates an embed shape from an arbitrary iframe URL', () => { defaultHandleExternalEmbedContent(editor, { url: 'https://www.openstreetmap.org/export/embed.html?bbox=-0.1258', embed: { width: 425, height: 350 }, }) const shapes = editor.getCurrentPageShapes() const embedShape = shapes.find((s) => s.type === 'embed') as TLEmbedShape | undefined expect(embedShape).toBeDefined() expect(embedShape!.props.url).toBe( 'https://www.openstreetmap.org/export/embed.html?bbox=-0.1258' ) expect(embedShape!.props.w).toBe(425) expect(embedShape!.props.h).toBe(350) }) it('creates an embed from a SoundCloud iframe', () => { defaultHandleExternalEmbedContent(editor, { url: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F2184622839&show_artwork=true', embed: { width: 425, height: 350 }, }) const embedShape = editor.getOnlySelectedShape() as TLEmbedShape expect(embedShape).not.toBeNull() expect(embedShape.type).toBe('embed') expect(embedShape.props.url).toContain('w.soundcloud.com/player') }) it('selects the created embed shape', () => { defaultHandleExternalEmbedContent(editor, { url: 'https://example.com/widget', embed: { width: 600, height: 400 }, }) const selected = editor.getOnlySelectedShape() expect(selected).not.toBeNull() expect(selected!.type).toBe('embed') }) it('places the embed at the specified point', () => { defaultHandleExternalEmbedContent(editor, { url: 'https://example.com/widget', point: { x: 500, y: 500 }, embed: { width: 200, height: 200 }, }) const embedShape = editor.getOnlySelectedShape() as TLEmbedShape expect(embedShape).not.toBeNull() expect(embedShape.x).toBeCloseTo(400, 0) expect(embedShape.y).toBeCloseTo(400, 0) }) }) describe('EmbedShapeUtil with unknown URLs', () => { it('allows resizing of embed shapes with unknown URLs', () => { editor.createShapes([ { type: 'embed', x: 0, y: 0, props: { url: 'https://unknown-service.example.com/embed', w: 400, h: 300, }, }, ]) const shape = editor.getCurrentPageShapes().find((s) => s.type === 'embed') as TLEmbedShape const util = editor.getShapeUtil('embed') expect(util.canResize(shape)).toBe(true) }) it('uses the shape dimensions for geometry of unknown embeds', () => { editor.createShapes([ { type: 'embed', x: 0, y: 0, props: { url: 'https://unknown-service.example.com/embed', w: 500, h: 400, }, }, ]) const shape = editor.getCurrentPageShapes().find((s) => s.type === 'embed') as TLEmbedShape const bounds = editor.getShapeGeometry(shape).bounds expect(bounds.w).toBe(500) expect(bounds.h).toBe(400) }) it('preserves behavior for known embed definitions', () => { editor.createShapes([ { type: 'embed', x: 0, y: 0, props: { url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', w: 720, h: 500, }, }, ]) const shape = editor.getCurrentPageShapes().find((s) => s.type === 'embed') as TLEmbedShape const util = editor.getShapeUtil('embed') // YouTube embeds have doesResize: true in the definition expect(util.canResize(shape)).toBe(true) // Geometry should use the shape's own dimensions const bounds = editor.getShapeGeometry(shape).bounds expect(bounds.w).toBe(720) expect(bounds.h).toBe(500) }) })