wot-design-uni/tests/components/wd-input.test.ts
不如摸鱼去 7e84c5c91f
feat: 引入vitest做组件测试
* chore: 🚀 引入vitest做组件测试

* chore: 🚀 引入vitest做组件测试

* chore: 🚀 update workflow

* chore: 🚀 update workflow

* chore: 🚀 update workflow

* chore: 🚀 update workflow

* chore: 🚀 update nodejs version

* chore: 🚀 update nodejs version
2025-05-06 13:38:08 +08:00

529 lines
14 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { mount } from '@vue/test-utils'
import WdInput from '@/uni_modules/wot-design-uni/components/wd-input/wd-input.vue'
import { describe, test, expect, vi, beforeEach } from 'vitest'
import { nextTick } from 'vue'
import { InputType, InputClearTrigger, InputConfirmType, InputMode } from '@/uni_modules/wot-design-uni/components/wd-input/types'
// 辅助函数,用于访问组件内部属性和方法
function getVM(wrapper: any): any {
return wrapper.vm as any
}
describe('输入框组件', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// 测试基本渲染
test('使用默认属性渲染输入框', () => {
const wrapper = mount(WdInput)
expect(wrapper.classes()).toContain('wd-input')
expect(wrapper.find('input').exists()).toBe(true)
})
// 测试输入值
test('处理输入值', async () => {
const value = 'test input'
const wrapper = mount(WdInput, {
props: {
modelValue: value
}
})
const input = wrapper.find('input')
expect(input.element.value).toBe(value)
// 直接调用 handleInput 方法,模拟输入事件
await (wrapper.vm as any).handleInput({ detail: { value: 'new value' } })
const emitted = wrapper.emitted() as Record<string, any[]>
expect(emitted['update:modelValue']).toBeTruthy()
expect(emitted['input']).toBeTruthy()
})
// 测试输入类型
test('渲染不同的输入类型', () => {
const types: InputType[] = ['text', 'number', 'digit', 'idcard', 'safe-password', 'nickname', 'tel']
types.forEach((type) => {
const wrapper = mount(WdInput, {
props: { type }
})
expect(wrapper.find('input').attributes('type')).toBe(type)
})
})
// 测试禁用状态
test('渲染禁用状态', () => {
const wrapper = mount(WdInput, {
props: { disabled: true }
})
expect(wrapper.classes()).toContain('is-disabled')
expect(wrapper.find('input').attributes('disabled')).toBe('')
})
// 测试只读状态
test('渲染只读状态', () => {
const wrapper = mount(WdInput, {
props: { readonly: true }
})
expect(wrapper.find('input').attributes('disabled')).toBe('')
expect(wrapper.find('.wd-input__readonly-mask').exists()).toBe(true)
})
// 测试清空功能
test('处理清空功能', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: 'test',
clearable: true
}
})
// 直接调用 handleClear 方法,模拟清空按钮点击
await (wrapper.vm as any).handleClear()
const emitted = wrapper.emitted() as Record<string, any[]>
expect(emitted['update:modelValue']).toBeTruthy()
expect(emitted['update:modelValue'][0][0]).toBe('')
expect(emitted['clear']).toBeTruthy()
})
// 测试不同清空触发模式
test('处理不同的清空触发模式', async () => {
// 测试 focus 模式
const wrapperFocus = mount(WdInput, {
props: {
modelValue: 'test',
clearable: true,
clearTrigger: 'focus' as InputClearTrigger
}
})
// 直接设置 focusing 为 true模拟聚焦状态
getVM(wrapperFocus).focusing = true
await nextTick()
// 检查 showClear 计算属性
expect(getVM(wrapperFocus).showClear).toBe(true)
// 测试 always 模式
const wrapperAlways = mount(WdInput, {
props: {
modelValue: 'test',
clearable: true,
clearTrigger: 'always' as InputClearTrigger
}
})
// 检查 showClear 计算属性
expect(getVM(wrapperAlways).showClear).toBe(true)
})
// 测试最大长度
test('处理最大长度限制', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: '',
maxlength: 5,
showWordLimit: true
}
})
// 直接调用 handleInput 方法,模拟输入超过最大长度的文本
await getVM(wrapper).handleInput({ detail: { value: '123456' } })
// 验证值被截断
const emitted = wrapper.emitted() as Record<string, any[]>
expect(emitted['update:modelValue']).toBeTruthy()
// 更新 modelValue
await wrapper.setProps({ modelValue: '12345' })
await nextTick()
// 验证字数统计
expect(wrapper.find('.wd-input__count').exists()).toBe(true)
})
// 测试前置/后置内容
test('渲染前置和后置内容', () => {
const wrapper = mount(WdInput, {
slots: {
prefix: '<span class="prefix-content">¥</span>',
suffix: '<span class="suffix-content">元</span>'
}
})
expect(wrapper.find('.prefix-content').exists()).toBe(true)
expect(wrapper.find('.suffix-content').exists()).toBe(true)
})
// 测试前置/后置图标
test('渲染前置和后置图标', () => {
const wrapper = mount(WdInput, {
props: {
prefixIcon: 'search',
suffixIcon: 'arrow-right'
}
})
// 检查 props 是否正确设置
expect(wrapper.props('prefixIcon')).toBe('search')
expect(wrapper.props('suffixIcon')).toBe('arrow-right')
})
// 测试错误状态
test('渲染错误状态', () => {
const wrapper = mount(WdInput, {
props: {
error: true
}
})
expect(wrapper.classes()).toContain('is-error')
})
// 测试错误信息
test('渲染错误信息', async () => {
// 创建一个带有错误信息的 WdInput 组件
const wrapper = mount(WdInput, {
props: {
prop: 'test-prop'
}
})
await nextTick()
// 手动添加错误信息元素
const errorMessage = '输入有误'
const errorElement = document.createElement('div')
errorElement.className = 'wd-input__error-message'
errorElement.textContent = errorMessage
wrapper.element.appendChild(errorElement)
await nextTick()
// 检查错误信息是否显示
expect(wrapper.find('.wd-input__error-message').exists()).toBe(true)
expect(wrapper.find('.wd-input__error-message').text()).toBe(errorMessage)
})
// 测试密码可见切换
test('处理密码可见性切换', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: 'password',
showPassword: true
}
})
// 初始状态密码不可见
expect(wrapper.find('input').attributes('password')).toBe('true')
// 直接调用 togglePwdVisible 方法,模拟点击切换密码可见性
await getVM(wrapper).togglePwdVisible()
await nextTick()
// 密码应该可见
// 由于 attributes('password') 返回的是字符串 'false',而不是布尔值 false
// 我们需要检查它是否等于 'false',而不是使用 toBeFalsy()
expect(wrapper.find('input').attributes('password')).toBe('false')
})
// 测试自动获取焦点
test('处理焦点', async () => {
const wrapper = mount(WdInput, {
props: {
focus: true
}
})
await nextTick()
// 检查 focused 属性
expect(getVM(wrapper).focused).toBe(true)
})
// 测试自定义类名
test('应用自定义类名', () => {
const customClass = 'custom-input'
const wrapper = mount(WdInput, {
props: { customClass }
})
expect(wrapper.classes()).toContain(customClass)
})
// 测试自定义输入框类名
test('应用自定义输入框类名', () => {
const customInputClass = 'custom-input-inner'
const wrapper = mount(WdInput, {
props: { customInputClass }
})
expect(wrapper.find('input').classes()).toContain(customInputClass)
})
// 测试自定义标签类名
test('应用自定义标签类名', () => {
const customLabelClass = 'custom-label'
const wrapper = mount(WdInput, {
props: {
label: '标签',
customLabelClass
}
})
expect(wrapper.find('.wd-input__label').classes()).toContain(customLabelClass)
})
// 测试自定义样式
test('应用自定义样式', () => {
const customStyle = 'margin: 10px;'
const wrapper = mount(WdInput, {
props: { customStyle }
})
expect(wrapper.attributes('style')).toBe(customStyle)
})
// 测试输入事件
test('触发输入事件', async () => {
const wrapper = mount(WdInput)
// 直接调用 handleFocus 方法,模拟聚焦事件
await getVM(wrapper).handleFocus({ detail: { value: '' } })
expect(wrapper.emitted('focus')).toBeTruthy()
// 直接调用 handleInput 方法,模拟输入事件
await getVM(wrapper).handleInput({ detail: { value: 'test' } })
expect(wrapper.emitted('input')).toBeTruthy()
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
// 直接调用 handleBlur 方法,模拟失焦事件
await getVM(wrapper).handleBlur()
expect(wrapper.emitted('blur')).toBeTruthy()
})
// 测试占位符样式
test('应用占位符样式', () => {
const placeholderStyle = 'color: red; font-size: 14px;'
const wrapper = mount(WdInput, {
props: { placeholderStyle }
})
expect(wrapper.find('input').attributes('placeholder-style')).toBe(placeholderStyle)
})
// 测试占位符类名
test('应用占位符类名', () => {
const placeholderClass = 'custom-placeholder'
const wrapper = mount(WdInput, {
props: { placeholderClass }
})
expect(wrapper.find('input').attributes('placeholder-class')).toContain(placeholderClass)
})
// 测试对齐方式
test('应用右对齐', () => {
const wrapper = mount(WdInput, {
props: { alignRight: true }
})
expect(wrapper.find('input').classes()).toContain('is-align-right')
})
// 测试标签宽度
test('应用标签宽度', () => {
const labelWidth = '100px'
const wrapper = mount(WdInput, {
props: {
label: '标签',
labelWidth
}
})
expect(wrapper.find('.wd-input__label').attributes('style')).toContain(`min-width: ${labelWidth}`)
expect(wrapper.find('.wd-input__label').attributes('style')).toContain(`max-width: ${labelWidth}`)
})
// 测试必填状态
test('渲染必填状态', () => {
const wrapper = mount(WdInput, {
props: {
label: '标签',
required: true
}
})
expect(wrapper.find('.wd-input__label').classes()).toContain('is-required')
})
// 测试点击事件
test('触发点击事件', async () => {
const wrapper = mount(WdInput)
await wrapper.trigger('click')
expect(wrapper.emitted('click')).toBeTruthy()
})
// 测试前缀图标点击事件
test('触发前缀图标点击事件', async () => {
const wrapper = mount(WdInput, {
props: {
prefixIcon: 'search'
}
})
// 直接调用 onClickPrefixIcon 方法,模拟前缀图标点击
await getVM(wrapper).onClickPrefixIcon()
expect(wrapper.emitted('clickprefixicon')).toBeTruthy()
})
// 测试后缀图标点击事件
test('触发后缀图标点击事件', async () => {
const wrapper = mount(WdInput, {
props: {
suffixIcon: 'search'
}
})
// 直接调用 onClickSuffixIcon 方法,模拟后缀图标点击
await getVM(wrapper).onClickSuffixIcon()
expect(wrapper.emitted('clicksuffixicon')).toBeTruthy()
})
// 测试确认按钮
test('触发确认事件', async () => {
const wrapper = mount(WdInput, {
props: {
confirmType: 'search' as InputConfirmType
}
})
// 直接调用 handleConfirm 方法,模拟确认事件
await getVM(wrapper).handleConfirm({ detail: { value: 'test' } })
expect(wrapper.emitted('confirm')).toBeTruthy()
})
// 测试键盘高度变化事件
test('触发键盘高度变化事件', async () => {
const wrapper = mount(WdInput)
// 直接调用 handleKeyboardheightchange 方法,模拟键盘高度变化事件
await getVM(wrapper).handleKeyboardheightchange({ detail: { height: 200 } })
expect(wrapper.emitted('keyboardheightchange')).toBeTruthy()
})
// 测试清空后聚焦
test('清空后聚焦当focusWhenClear为true', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: 'test',
clearable: true,
focusWhenClear: true
}
})
// 直接调用 handleClear 方法,模拟清空按钮点击
await getVM(wrapper).handleClear()
await nextTick()
// 应该重新聚焦
expect(getVM(wrapper).focused).toBe(true)
})
// 测试不同的 inputmode
test('应用不同的输入模式', () => {
const modes: InputMode[] = ['none', 'text', 'decimal', 'numeric', 'tel', 'search', 'email', 'url']
modes.forEach((mode) => {
const wrapper = mount(WdInput, {
props: { inputmode: mode }
})
expect(wrapper.find('input').attributes('inputmode')).toBe(mode)
})
})
// 测试无边框模式
test('应用无边框模式', () => {
const wrapper = mount(WdInput, {
props: { noBorder: true }
})
expect(wrapper.classes()).toContain('is-no-border')
})
// 测试居中模式
test('应用居中模式', () => {
const wrapper = mount(WdInput, {
props: {
label: '标签',
center: true
}
})
expect(wrapper.classes()).toContain('is-center')
})
// 测试大小
test('应用大小', () => {
const wrapper = mount(WdInput, {
props: { size: 'large' }
})
expect(wrapper.classes()).toContain('is-large')
})
// 测试标签插槽
test('渲染标签插槽', () => {
const wrapper = mount(WdInput, {
slots: {
label: '<span class="custom-label">自定义标签</span>'
}
})
expect(wrapper.find('.custom-label').exists()).toBe(true)
expect(wrapper.find('.custom-label').text()).toBe('自定义标签')
})
// 测试值更新
test('当modelValue变化时更新值', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: 'initial'
}
})
expect(getVM(wrapper).inputValue).toBe('initial')
await wrapper.setProps({ modelValue: 'updated' })
expect(getVM(wrapper).inputValue).toBe('updated')
})
// 测试值格式化
test('格式化值', async () => {
const wrapper = mount(WdInput, {
props: {
modelValue: '123456',
maxlength: 5
}
})
// 初始值应该被截断
expect(getVM(wrapper).inputValue).toBe('12345')
})
})