150 lines
5.8 KiB
JavaScript
150 lines
5.8 KiB
JavaScript
import { describe, it, expect } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import Button from '@/components/ui/button/button.vue'
|
|
import Tag from '@/components/ui/tag/tag.vue'
|
|
import Switch from '@/components/ui/switch/switch.vue'
|
|
import Radio from '@/components/ui/radio/radio.vue'
|
|
import RadioGroup from '@/components/ui/radio/radio-group.vue'
|
|
import Checkbox from '@/components/ui/checkbox/checkbox.vue'
|
|
import Spin from '@/components/ui/spin/spin.vue'
|
|
|
|
describe('Button 组件', () => {
|
|
it('默认渲染 primary 按钮并显示插槽内容', () => {
|
|
const wrapper = mount(Button, { slots: { default: '提交' } })
|
|
expect(wrapper.find('button').classes()).toContain('button-primary')
|
|
expect(wrapper.text()).toContain('提交')
|
|
})
|
|
|
|
it('type/block/loading 映射 class', () => {
|
|
const wrapper = mount(Button, { props: { type: 'danger', block: true, loading: true } })
|
|
const btn = wrapper.find('button')
|
|
expect(btn.classes()).toContain('button-danger')
|
|
expect(btn.classes()).toContain('button-block')
|
|
expect(btn.classes()).toContain('button-loading')
|
|
})
|
|
|
|
it('loading 或 disabled 时禁用原生按钮', () => {
|
|
const loading = mount(Button, { props: { loading: true } })
|
|
expect(loading.find('button').attributes('disabled')).toBeDefined()
|
|
const disabled = mount(Button, { props: { disabled: true } })
|
|
expect(disabled.find('button').attributes('disabled')).toBeDefined()
|
|
})
|
|
|
|
it('htmlType 透传原生 type', () => {
|
|
const wrapper = mount(Button, { props: { htmlType: 'submit' } })
|
|
expect(wrapper.find('button').attributes('type')).toBe('submit')
|
|
})
|
|
})
|
|
|
|
describe('Tag 组件', () => {
|
|
it('默认渲染 default 变体', () => {
|
|
const wrapper = mount(Tag, { slots: { default: '标签' } })
|
|
expect(wrapper.text()).toContain('标签')
|
|
})
|
|
|
|
it('variant 映射 class', () => {
|
|
const wrapper = mount(Tag, { props: { variant: 'danger' } })
|
|
expect(wrapper.classes()).toContain('tag-danger')
|
|
})
|
|
|
|
it('closable 点击关闭:emit close 并隐藏', async () => {
|
|
const wrapper = mount(Tag, { props: { closable: true } })
|
|
await wrapper.find('[role="button"]').trigger('click')
|
|
expect(wrapper.emitted('close')).toHaveLength(1)
|
|
expect(wrapper.classes()).toContain('tag-hidden')
|
|
})
|
|
|
|
it('disabled 时点击不关闭', async () => {
|
|
const wrapper = mount(Tag, { props: { closable: true, disabled: true } })
|
|
await wrapper.find('[role="button"]').trigger('click')
|
|
expect(wrapper.emitted('close')).toBeUndefined()
|
|
})
|
|
|
|
it('href 渲染为链接', () => {
|
|
const wrapper = mount(Tag, { props: { href: '/x' } })
|
|
expect(wrapper.find('a').exists()).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('Switch 组件', () => {
|
|
it('点击触发 update:modelValue 与 change', async () => {
|
|
const wrapper = mount(Switch, { props: { modelValue: false } })
|
|
await wrapper.find('[role="switch"]').trigger('click')
|
|
expect(wrapper.emitted('update:modelValue')[0]).toEqual([true])
|
|
expect(wrapper.emitted('change')[0][0]).toBe(true)
|
|
})
|
|
|
|
it('checked 状态映射 class 与 aria-checked', () => {
|
|
const wrapper = mount(Switch, { props: { modelValue: true } })
|
|
expect(wrapper.find('[role="switch"]').classes()).toContain('switch-checked')
|
|
expect(wrapper.find('[role="switch"]').attributes('aria-checked')).toBe('true')
|
|
})
|
|
|
|
it('disabled 时点击不触发', async () => {
|
|
const wrapper = mount(Switch, { props: { disabled: true } })
|
|
await wrapper.find('[role="switch"]').trigger('click')
|
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('RadioGroup + Radio 组件', () => {
|
|
it('选中 radio 触发 v-model 更新', async () => {
|
|
const real = mount({
|
|
components: { RadioGroup, Radio },
|
|
template: '<RadioGroup v-model="v"><Radio value="a" /><Radio value="b" /></RadioGroup>',
|
|
data: () => ({ v: 'a' }),
|
|
})
|
|
const radios = real.findAll('input[type="radio"]')
|
|
expect(radios[0].element.checked).toBe(true)
|
|
await radios[1].setValue()
|
|
expect(real.vm.v).toBe('b')
|
|
})
|
|
|
|
it('独立 Radio 未分组时默认不选中', () => {
|
|
const wrapper = mount(Radio, { props: { value: 'x' } })
|
|
expect(wrapper.find('input').element.checked).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('Checkbox 组件', () => {
|
|
it('勾选触发 update:modelValue 与 change', async () => {
|
|
const wrapper = mount(Checkbox, { props: { modelValue: false } })
|
|
await wrapper.find('input[type="checkbox"]').setValue(true)
|
|
expect(wrapper.emitted('update:modelValue')[0]).toEqual([true])
|
|
expect(wrapper.emitted('change')[0][0]).toBe(true)
|
|
})
|
|
|
|
it('checked/indeterminate/disabled 映射 class', () => {
|
|
const checked = mount(Checkbox, { props: { modelValue: true } })
|
|
expect(checked.classes()).toContain('checkbox-checked')
|
|
const semi = mount(Checkbox, { props: { indeterminate: true, modelValue: false } })
|
|
expect(semi.classes()).toContain('checkbox-indeterminate')
|
|
const disabled = mount(Checkbox, { props: { disabled: true } })
|
|
expect(disabled.classes()).toContain('checkbox-disabled')
|
|
})
|
|
})
|
|
|
|
describe('Spin 组件', () => {
|
|
it('默认加载中显示 aria-busy', () => {
|
|
const wrapper = mount(Spin)
|
|
expect(wrapper.attributes('aria-busy')).toBe('true')
|
|
})
|
|
|
|
it('spinning=false 不显示', () => {
|
|
const wrapper = mount(Spin, { props: { spinning: false } })
|
|
expect(wrapper.attributes('aria-busy')).toBe('false')
|
|
})
|
|
|
|
it('delay 延迟生效:立即不 active,延时后 active', async () => {
|
|
const wrapper = mount(Spin, { props: { spinning: true, delay: 50 } })
|
|
expect(wrapper.attributes('aria-busy')).toBe('false')
|
|
await new Promise((r) => setTimeout(r, 80))
|
|
expect(wrapper.attributes('aria-busy')).toBe('true')
|
|
})
|
|
|
|
it('description 渲染加载文案', () => {
|
|
const wrapper = mount(Spin, { props: { description: '加载中...' } })
|
|
expect(wrapper.text()).toContain('加载中...')
|
|
})
|
|
})
|