// 图片显示解析回归:文档里的相对路径图片在编辑区经 NodeView 读成 data URL 显示; // 文档内容(序列化)保持相对路径不变。upload 插件以 instanceof 把关事件类型, // jsdom 缺 ClipboardEvent/DragEvent 全局,这里垫上。 import { describe, it, expect } from 'vitest' import { createMarkdownEditor, getMarkdown } from '../src/editor/editor' import { editorViewCtx } from '@milkdown/kit/core' class FakeClipboardEvent extends Event { clipboardData: unknown constructor(type: string, init?: { clipboardData?: unknown }) { super(type, { bubbles: true, cancelable: true }) this.clipboardData = init?.clipboardData } } ;(globalThis as Record).ClipboardEvent = FakeClipboardEvent ;(globalThis as Record).DragEvent = class extends Event {} const tick = (ms = 40) => new Promise((r) => setTimeout(r, ms)) describe('图片显示解析', () => { it('相对路径图片在 DOM 里被换成 data URL,文档仍是相对路径', async () => { const host = document.createElement('div') document.body.appendChild(host) const editor = createMarkdownEditor(host, '看图 ![截图](doc.assets/a.png) 完', {}, { resolveImageDisplay: async (src) => (src === 'doc.assets/a.png' ? 'data:image/png;base64,QUJD' : null), }) await editor.create() await tick() const img = host.querySelector('img:not(.ProseMirror-separator)') expect(img?.getAttribute('src')).toBe('data:image/png;base64,QUJD') expect(img?.getAttribute('alt')).toBe('截图') expect(getMarkdown(editor)).toContain('![截图](doc.assets/a.png)') await editor.destroy() host.remove() }) it('粘贴图片落盘为相对路径后同样能显示', async () => { const host = document.createElement('div') document.body.appendChild(host) const editor = createMarkdownEditor(host, '正文', {}, { onImageFile: async () => 'doc.assets/pasted.png', resolveImageDisplay: async (src) => (src === 'doc.assets/pasted.png' ? 'data:image/png;base64,QUJD' : null), }) await editor.create() const view = editor.action((ctx) => ctx.get(editorViewCtx)) const file = new File(['png'], 'image.png', { type: 'image/png' }) const event = new FakeClipboardEvent('paste', { clipboardData: { files: [file], items: [], getData: () => '' }, }) view.dom.dispatchEvent(event) await tick(80) expect(getMarkdown(editor)).toContain('doc.assets/pasted.png') const img = host.querySelector('img:not(.ProseMirror-separator)') expect(img?.getAttribute('src')).toBe('data:image/png;base64,QUJD') await editor.destroy() host.remove() }) it('解析不到(文件缺失)时不崩溃、文档不变', async () => { const host = document.createElement('div') document.body.appendChild(host) const editor = createMarkdownEditor(host, '![x](missing.png)', {}, { resolveImageDisplay: async () => null, }) await editor.create() await tick() expect(host.querySelector('img')).not.toBeNull() expect(getMarkdown(editor)).toContain('![x](missing.png)') await editor.destroy() host.remove() }) })