import { nextTick, ref } from 'vue' import { mount } from '@vue/test-utils' import { sleep, defineGetter } from '@element-plus/test-utils' import Input from '../src/index.vue' const _mount = (options) => mount({ components: { 'el-input': Input, }, ...options, }) describe('Input.vue', () => { test('create', async () => { const handleFocus = jest.fn() const wrapper = _mount({ template: ` `, setup() { const input = ref('input') return { input, handleFocus, } }, }) const inputElm = wrapper.find('input') const vm = wrapper.vm as any const nativeInput = inputElm.element await inputElm.trigger('focus') expect(inputElm.exists()).toBe(true) expect(handleFocus).toHaveBeenCalled() expect(nativeInput.placeholder).toBe('请输入内容') expect(nativeInput.value).toBe('input') expect(nativeInput.minLength).toBe(3) // expect(nativeInput.maxLength).toBe(5) // The maxlength attribute is no longer a native attribute vm.input = 'text' await sleep() expect(inputElm.element.value).toBe('text') }) test('default to empty', () => { const wrapper = _mount({ template: '', }) const inputElm = wrapper.find('input') expect(inputElm.element.value).toBe('') }) test('disabled', () => { const wrapper = _mount({ template: ``, }) const inputElm = wrapper.find('input') expect(inputElm.element.disabled).not.toBeNull() }) describe('test emoji', () => { test('el-input should minimize value between emoji length and maxLength', async () => { const wrapper = _mount({ template: ``, setup() { const inputVal = ref('12🌚') return { inputVal } }, }) const vm = wrapper.vm const inputElm = wrapper.find('input') const nativeInput = inputElm.element expect(nativeInput.value).toBe('12🌚') const elCount = wrapper.find('.el-input__count-inner') expect(elCount.exists()).toBe(true) expect(elCount.text()).toBe('3/4') vm.inputVal = '1👌3😄' await sleep() expect(nativeInput.value).toBe('1👌3😄') expect(elCount.text()).toBe('4/4') vm.inputVal = '哈哈1👌3😄' await sleep() expect(nativeInput.value).toBe('哈哈1👌3😄') expect(elCount.text()).toBe('6/4') expect(vm.$el.classList.contains('is-exceed')).toBe(true) }) test('textarea should minimize value between emoji length and maxLength', async () => { const wrapper = _mount({ template: ``, setup() { const inputVal = ref('啊好😄') return { inputVal } }, }) const vm = wrapper.vm const inputElm = wrapper.find('textarea') const nativeInput = inputElm.element expect(nativeInput.value).toBe('啊好😄') const elCount = wrapper.find('.el-input__count') expect(elCount.exists()).toBe(true) expect(elCount.text()).toBe('3/4') vm.inputVal = '哈哈1👌3😄' await sleep() expect(nativeInput.value).toBe('哈哈1👌3😄') expect(elCount.text()).toBe('6/4') expect(vm.$el.classList.contains('is-exceed')).toBe(true) }) }) test('suffixIcon', () => { const wrapper = _mount({ template: ``, }) const icon = wrapper.find('.el-input__icon') expect(icon.exists()).toBe(true) }) test('prefixIcon', () => { const wrapper = _mount({ template: ``, }) const icon = wrapper.find('.el-input__icon') expect(icon.exists()).toBe(true) }) test('size', () => { const wrapper = _mount({ template: ``, }) expect(wrapper.classes('el-input--large')).toBe(true) }) test('type', () => { const wrapper = _mount({ template: ``, }) expect(wrapper.classes('el-textarea')).toBe(true) }) test('rows', () => { const wrapper = _mount({ template: ``, }) expect(wrapper.find('textarea').element.rows).toEqual(3) }) test('resize', async () => { const wrapper = _mount({ template: `
`, data() { return { resize: 'none', } }, }) const vm = wrapper.vm as any const textarea = wrapper.find('textarea').element await sleep() expect(textarea.style.resize).toEqual(vm.resize) vm.resize = 'horizontal' await sleep() expect(textarea.style.resize).toEqual(vm.resize) }) // TODO: Due to jsdom's reason this case cannot run well, may be fixed later using headlesschrome or puppeteer // test('autosize', async() => { // const wrapper = _mount({ // template: `
// //
`, // data() { // return { // textareaValue: 'sda\ndasd\nddasdsda\ndasd\nddasdsda\ndasd\nddasdsda\ndasd\nddasd', // } // }, // }) // const limitSizeInput = wrapper.vm.$refs.limitSize // const limitlessSizeInput = wrapper.vm.$refs.limitlessSize // await sleep() // expect(limitSizeInput.computedTextareaStyle.height).toEqual('117px') // expect(limitlessSizeInput.computedTextareaStyle.height).toEqual('201px') // wrapper.vm.textareaValue = '' // await sleep() // expect(limitSizeInput.computedTextareaStyle.height).toEqual('75px') // expect(limitlessSizeInput.computedTextareaStyle.height).toEqual('33px') // }) test('sets value on textarea / input type change', async () => { const wrapper = _mount({ template: ``, data() { return { type: 'text', val: '123', } }, }) const vm = wrapper.vm as any expect(vm.$el.querySelector('input').value).toEqual('123') vm.type = 'textarea' await sleep() expect(vm.$el.querySelector('textarea').value).toEqual('123') vm.type = 'password' await sleep() expect(vm.$el.querySelector('input').value).toEqual('123') }) test('limit input and show word count', async () => { const wrapper = _mount({ template: `
`, data() { return { input1: '', input2: '', input3: '', input4: 'exceed', show: false, } }, }) const inputElm1 = wrapper.vm.$el.querySelector('.test-text') const inputElm2 = wrapper.vm.$el.querySelector('.test-textarea') const inputElm3 = wrapper.vm.$el.querySelector('.test-password') const inputElm4 = wrapper.vm.$el.querySelector('.test-initial-exceed') expect(inputElm1.querySelectorAll('.el-input__count').length).toEqual(0) expect(inputElm2.querySelectorAll('.el-input__count').length).toEqual(1) expect(inputElm3.querySelectorAll('.el-input__count').length).toEqual(0) expect(inputElm4.classList.contains('is-exceed')).toBe(true) const vm = wrapper.vm as any vm.show = true await sleep() expect(inputElm1.querySelectorAll('.el-input__count').length).toEqual(1) vm.input4 = '1' await sleep() expect(inputElm4.classList.contains('is-exceed')).toBe(false) }) describe('Input Methods', () => { test('method:select', async () => { const testContent = 'test' const wrapper = _mount({ template: ``, data() { return { text: testContent, } }, }) const input = wrapper.find('input').element // mock selectionRange behaviour, due to jsdom's reason this case cannot run well, may be fixed later using headlesschrome or puppeteer let selected = false defineGetter(input, 'selectionStart', function () { return selected ? 0 : this.value.length }) defineGetter(input, 'selectionEnd', function () { return this.value.length }) expect(input.selectionStart).toEqual(testContent.length) expect(input.selectionEnd).toEqual(testContent.length) input.select() selected = true await sleep() expect(input.selectionStart).toEqual(0) expect(input.selectionEnd).toEqual(testContent.length) }) test('method:resizeTextarea', async () => { const testContent = 'TEXT:resizeTextarea' const wrapper = _mount({ template: ``, data() { return { text: testContent, } }, }) const ref = wrapper.vm.$refs.textarea const originMinHeight = ref.computedTextareaStyle.minHeight ref.autosize.minRows = 5 ref.resizeTextarea() // Atfer this textarea min-height (style) will change const nowMinHeight = ref.computedTextareaStyle.minHeight expect(originMinHeight).not.toEqual(nowMinHeight) }) }) describe('Input Events', () => { const handleFocus = jest.fn() const handleBlur = jest.fn() test('event:focus & blur', async () => { const wrapper = _mount({ template: ``, setup() { const input = ref('') return { input, handleFocus, handleBlur, } }, }) const input = wrapper.find('input') await input.trigger('focus') expect(handleFocus).toBeCalled() await input.trigger('blur') expect(handleBlur).toBeCalled() }) test('event:change', async () => { // NOTE: should be same as native's change behavior const wrapper = _mount({ template: ` `, data() { return { input: 'a', val: '', } }, methods: { handleChange(val) { this.val = val }, }, }) const el = wrapper.find('input').element const vm = wrapper.vm as any const simulateEvent = (text, event) => { el.value = text el.dispatchEvent(new Event(event)) } // simplified test, component should emit change when native does simulateEvent('2', 'change') await sleep() expect(vm.val).toBe('2') simulateEvent('1', 'input') await sleep() expect(vm.val).toBe('2') }) test('event:clear', async () => { const handleClear = jest.fn() const handleInput = jest.fn() const wrapper = _mount({ template: ` `, setup() { const input = ref('a') return { input, handleClear, handleInput, } }, }) const input = wrapper.find('input') const vm = wrapper.vm as any // focus to show clear button await input.trigger('focus') await sleep() vm.$el.querySelector('.el-input__clear').click() await sleep() expect(vm.input).toEqual('') expect(handleClear).toBeCalled() expect(handleInput).toBeCalled() }) test('event:input', async () => { const handleInput = jest.fn() const wrapper = _mount({ template: ` `, setup() { const input = ref('a') return { input, handleInput, } }, }) const vm = wrapper.vm as any const inputWrapper = wrapper.find('input') const nativeInput = inputWrapper.element nativeInput.value = '1' await inputWrapper.trigger('compositionstart') await inputWrapper.trigger('input') nativeInput.value = '2' await inputWrapper.trigger('compositionupdate') await inputWrapper.trigger('input') await inputWrapper.trigger('compositionend') expect(handleInput).toBeCalledTimes(1) // native input value is controlled expect(vm.input).toEqual('a') expect(nativeInput.value).toEqual('a') }) }) test('non-emit event such as keyup should work', async () => { const handleKeyup = jest.fn() const wrapper = mount(Input, { attrs: { onKeyup: handleKeyup, }, }) await wrapper.find('input').trigger('keyup') expect(handleKeyup).toBeCalledTimes(1) }) test('input-style', async () => { const wrapper = _mount({ template: ` `, }) const input = wrapper.find('input') const textarea = wrapper.find('textarea') await nextTick() expect(input.element.style.color === 'red').toBeTruthy() expect(textarea.element.style.color === 'red').toBeTruthy() }) describe('Textarea Events', () => { test('event:keydown', async () => { const handleKeydown = jest.fn() const wrapper = _mount({ template: ``, setup() { const val = ref('') return { val, handleKeydown, } }, }) await wrapper.find('textarea').trigger('keydown') expect(handleKeydown).toBeCalledTimes(1) }) }) // TODO: validateEvent & input containes select cases should be added after the rest components finished // ... })