diff --git a/app/components/PostBodyMarkdownEditor.vditor.test.ts b/app/components/PostBodyMarkdownEditor.vditor.test.ts new file mode 100644 index 0000000..5dcfb34 --- /dev/null +++ b/app/components/PostBodyMarkdownEditor.vditor.test.ts @@ -0,0 +1,107 @@ +import { describe, expect, test } from 'bun:test' +import { createPostBodyMarkdownEditorBridge } from './post-body-markdown-editor-vditor-bridge' + +describe('PostBodyMarkdownEditor Vditor bridge', () => { + test('内容变化时触发 update:modelValue', () => { + let modelValue = 'hello' + const updates: string[] = [] + let onInput: ((value: string) => void) | null = null + + const bridge = createPostBodyMarkdownEditorBridge({ + getModelValue: () => modelValue, + emitUpdate: (value) => updates.push(value), + createEditor: ({ onInput: input }) => { + onInput = input + return { + getValue: () => modelValue, + setValue: () => undefined, + destroy: () => undefined, + } + }, + }) + + bridge.mount({} as HTMLElement) + onInput?.('hello world') + + expect(updates).toEqual(['hello world']) + }) + + test('props 变化可同步到实例 setValue', () => { + let modelValue = 'a' + const setCalls: Array<{ value: string; render?: boolean }> = [] + let editorValue = modelValue + + const bridge = createPostBodyMarkdownEditorBridge({ + getModelValue: () => modelValue, + emitUpdate: () => undefined, + createEditor: () => ({ + getValue: () => editorValue, + setValue: (value, render) => { + setCalls.push({ value, render }) + editorValue = value + }, + destroy: () => undefined, + }), + }) + + bridge.mount({} as HTMLElement) + modelValue = 'b' + bridge.syncFromProps() + bridge.syncFromProps() + + expect(setCalls).toEqual([{ value: 'b', render: true }]) + }) + + test('setValue 抛错后可恢复同步状态并继续响应 input', () => { + let modelValue = 'a' + const updates: string[] = [] + let onInput: ((value: string) => void) | null = null + let editorValue = modelValue + + const bridge = createPostBodyMarkdownEditorBridge({ + getModelValue: () => modelValue, + emitUpdate: (value) => updates.push(value), + createEditor: ({ onInput: input }) => { + onInput = input + return { + getValue: () => editorValue, + setValue: () => { + throw new Error('setValue failed') + }, + destroy: () => undefined, + } + }, + }) + + bridge.mount({} as HTMLElement) + modelValue = 'b' + expect(() => bridge.syncFromProps()).toThrow('setValue failed') + + onInput?.('c') + + expect(updates).toEqual(['c']) + }) + + test('卸载时销毁实例', () => { + let destroyed = 0 + + const bridge = createPostBodyMarkdownEditorBridge({ + getModelValue: () => '', + emitUpdate: () => undefined, + createEditor: () => ({ + getValue: () => '', + setValue: () => undefined, + destroy: () => { + destroyed += 1 + }, + }), + }) + + bridge.mount({} as HTMLElement) + bridge.unmount() + bridge.unmount() + + expect(destroyed).toBe(1) + expect(bridge.getEditor()).toBeNull() + }) +}) diff --git a/app/components/PostBodyMarkdownEditor.vue b/app/components/PostBodyMarkdownEditor.vue index 683a0a0..99cef72 100644 --- a/app/components/PostBodyMarkdownEditor.vue +++ b/app/components/PostBodyMarkdownEditor.vue @@ -1,7 +1,9 @@