diff --git a/src/dom-wrapper.ts b/src/dom-wrapper.ts index 5532604f0..e410eb240 100644 --- a/src/dom-wrapper.ts +++ b/src/dom-wrapper.ts @@ -56,13 +56,14 @@ export class DOMWrapper implements WrapperAPI { ) } - async setChecked(checked: boolean = true) { + private async setChecked(checked: boolean = true) { // typecast so we get typesafety const element = (this.element as unknown) as HTMLInputElement + const type = this.attributes().type - if (element.tagName !== 'INPUT') { + if (type === 'radio' && !checked) { throw Error( - `You need to call setChecked on an input element. You called it on a ${this.element.tagName}` + `wrapper.setChecked() cannot be called with parameter false on a ' element.` ) } @@ -78,6 +79,52 @@ export class DOMWrapper implements WrapperAPI { return this.trigger('change') } + setValue(value?: any) { + const element = (this.element as unknown) as HTMLInputElement + const tagName = element.tagName + const type = this.attributes().type + + if (tagName === 'OPTION') { + return this.setSelected() + } else if (tagName === 'INPUT' && type === 'checkbox') { + return this.setChecked(value) + } else if (tagName === 'INPUT' && type === 'radio') { + return this.setChecked(value) + } else if ( + tagName === 'INPUT' || + tagName === 'TEXTAREA' || + tagName === 'SELECT' + ) { + element.value = value + + if (tagName === 'SELECT') { + return this.trigger('change') + } + this.trigger('input') + // trigger `change` for `v-model.lazy` + return this.trigger('change') + } else { + throw Error(`wrapper.setValue() cannot be called on ${tagName}`) + } + } + + private setSelected() { + const element = (this.element as unknown) as HTMLOptionElement + + if (element.selected) { + return + } + + element.selected = true + let parentElement = element.parentElement + + if (parentElement.tagName === 'OPTGROUP') { + parentElement = parentElement.parentElement + } + + return new DOMWrapper(parentElement).trigger('change') + } + async trigger(eventString: string) { const evt = document.createEvent('Event') evt.initEvent(eventString) diff --git a/src/error-wrapper.ts b/src/error-wrapper.ts index bb942e9a4..44cc75781 100644 --- a/src/error-wrapper.ts +++ b/src/error-wrapper.ts @@ -14,6 +14,10 @@ export class ErrorWrapper { return Error(`Cannot call ${method} on an empty wrapper.`) } + attributes() { + throw this.wrapperError('attributes') + } + classes() { throw this.wrapperError('classes') } @@ -34,6 +38,10 @@ export class ErrorWrapper { throw this.wrapperError('setChecked') } + setValue() { + throw this.wrapperError('setValue') + } + text() { throw this.wrapperError('text') } diff --git a/src/vue-wrapper.ts b/src/vue-wrapper.ts index 172be7f64..aaefa78c2 100644 --- a/src/vue-wrapper.ts +++ b/src/vue-wrapper.ts @@ -76,10 +76,6 @@ export class VueWrapper implements WrapperAPI { return Array.from(results).map((x) => new DOMWrapper(x)) } - async setChecked(checked: boolean = true) { - return new DOMWrapper(this.element).setChecked(checked) - } - trigger(eventString: string) { const rootElementWrapper = new DOMWrapper(this.element) return rootElementWrapper.trigger(eventString) diff --git a/tests/components/ComponentWithInput.vue b/tests/components/ComponentWithInput.vue index eb67cf1ce..832263dd6 100644 --- a/tests/components/ComponentWithInput.vue +++ b/tests/components/ComponentWithInput.vue @@ -14,6 +14,7 @@ value="radioBarResult" /> + element` + const wrapper = mount(ComponentWithInput) + const radioFoo = wrapper.find('#radioFoo') + + const fn = radioFoo.setValue(false) + await expect(fn).rejects.toThrowError(message) + }) + }) + + it('throws error if element is not valid', () => { + const message = 'wrapper.setValue() cannot be called on LABEL' + const wrapper = mount(ComponentWithInput) + const input = wrapper.find('#label-el') + + const fn = () => input.setValue('') + expect(fn).toThrowError(message) + }) +})