diff --git a/src/domWrapper.ts b/src/domWrapper.ts index 92b38ab46..bc55587f6 100644 --- a/src/domWrapper.ts +++ b/src/domWrapper.ts @@ -136,6 +136,14 @@ export class DOMWrapper extends BaseWrapper { this.trigger('input') // trigger `change` for `v-model.lazy` return this.trigger('change') + } else if (tagName === 'DIV' && this.attributes().contenteditable) { + // for contenteditable elements, we set the innerHTML + // and trigger input and change events + // the value will be coerced to a string + // and object types will be stringified (either default [object Object] or custom toString)]) + element.innerHTML = value + this.trigger('input') + return this.trigger('change') } else { throw Error(`wrapper.setValue() cannot be called on ${tagName}`) } diff --git a/tests/setValue.spec.ts b/tests/setValue.spec.ts index 911a039b4..e63a551c4 100644 --- a/tests/setValue.spec.ts +++ b/tests/setValue.spec.ts @@ -343,4 +343,25 @@ describe('setValue', () => { }) }) }) + + describe('on contenteditable elements', () => { + it('sets element innerHTML', async () => { + const richContent = '

Rich title

Rich description

' + const onInput = vi.fn() + const onChange = vi.fn() + const Comp = defineComponent({ + setup() { + return () => h('div', { contenteditable: 'true', onInput, onChange }) + } + }) + + const wrapper = mount(Comp) + const editable = wrapper.find('div') + await editable.setValue(richContent) + + expect(editable.element.innerHTML).toBe(richContent) + expect(onInput).toHaveBeenCalledTimes(1) + expect(onChange).toHaveBeenCalledTimes(1) + }) + }) })