Files
workspace/code/fms/fms-vue/tests/components/basic.spec.js
T
2026-09-21 23:13:14 +08:00

155 lines
6.0 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('danger-outline 描边危险变体映射 class', () => {
const wrapper = mount(Button, { props: { type: 'danger-outline' } })
expect(wrapper.find('button').classes()).toContain('button-danger-outline')
})
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('加载中...')
})
})