import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import MachineView from '@/views/machine/index.vue'
import { wrapResponse, mockMachines } from '../../../fixtures'
// Mock element-plus
vi.mock('element-plus', () => ({
ElMessage: {
success: vi.fn(),
error: vi.fn(),
info: vi.fn(),
warning: vi.fn()
},
ElMessageBox: {
confirm: vi.fn().mockResolvedValue(true)
}
}))
// Mock machine API
const mockListMachines = vi.fn()
const mockAddMachine = vi.fn()
const mockUpdateMachine = vi.fn()
const mockDeleteMachine = vi.fn()
vi.mock('@/api/machine', () => ({
listMachines: () => mockListMachines(),
addMachine: (...args: any[]) => mockAddMachine(...args),
updateMachine: (...args: any[]) => mockUpdateMachine(...args),
deleteMachine: (...args: any[]) => mockDeleteMachine(...args)
}))
describe('Machine View', () => {
beforeEach(() => {
setActivePinia(createPinia())
vi.clearAllMocks()
mockListMachines.mockResolvedValue(wrapResponse(mockMachines))
})
const mountMachine = () => {
return mount(MachineView, {
global: {
plugins: [createPinia()],
stubs: {
'el-button': {
template: '',
props: ['type', 'icon', 'loading', 'plain', 'link', 'disabled']
},
'el-table': {
template: '
',
props: ['data', 'loading', 'border']
},
'el-table-column': {
template: ' | ',
props: ['prop', 'label', 'width', 'align', 'type', 'fixed', 'minWidth', 'showOverflowTooltip']
},
'el-tag': { template: '', props: ['type'] },
'el-link': {
template: '',
props: ['type']
},
'el-pagination': {
template: '',
props: ['currentPage', 'pageSize', 'pageSizes', 'total', 'layout', 'background']
},
'el-dialog': {
template:
'
',
props: ['modelValue', 'title', 'width', 'destroyOnClose']
},
'el-form': {
template: '',
props: ['model', 'rules', 'labelWidth'],
methods: {
validate(callback: Function) {
callback(false)
return Promise.resolve(false)
},
resetFields() {}
}
},
'el-form-item': { template: '
', props: ['label', 'prop'] },
'el-input': {
template:
'',
props: ['modelValue', 'placeholder', 'disabled', 'type', 'rows']
},
'el-switch': {
template:
'',
props: ['modelValue']
},
Plus: { template: 'Plus' },
Refresh: { template: 'Refresh' },
Edit: { template: 'Edit' },
Delete: { template: 'Delete' }
}
}
})
}
describe('页面渲染', () => {
it('应该正确渲染机器管理页面', async () => {
const wrapper = mountMachine()
await flushPromises()
expect(wrapper.find('.page-container').exists()).toBe(true)
expect(wrapper.find('.table-actions').exists()).toBe(true)
})
it('应该显示新增机器按钮', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
expect(addBtn).toBeDefined()
})
it('应该显示刷新列表按钮', async () => {
const wrapper = mountMachine()
await flushPromises()
const refreshBtn = wrapper.findAll('button').find((btn) => btn.text().includes('刷新列表'))
expect(refreshBtn).toBeDefined()
})
it('应该显示数据表格', async () => {
const wrapper = mountMachine()
await flushPromises()
expect(wrapper.find('.el-table').exists()).toBe(true)
})
it('应该显示分页组件', async () => {
const wrapper = mountMachine()
await flushPromises()
expect(wrapper.find('.pagination-container').exists()).toBe(true)
})
})
describe('数据加载', () => {
it('页面加载时应该获取机器列表', async () => {
mountMachine()
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
})
it('点击刷新按钮应该重新加载数据', async () => {
const wrapper = mountMachine()
await flushPromises()
mockListMachines.mockClear()
const refreshBtn = wrapper.findAll('button').find((btn) => btn.text().includes('刷新列表'))
if (refreshBtn) {
await refreshBtn.trigger('click')
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
}
})
})
describe('新增机器', () => {
it('点击新增按钮应该打开弹窗', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
if (addBtn) {
await addBtn.trigger('click')
await flushPromises()
expect(wrapper.find('.el-dialog').exists()).toBe(true)
}
})
it('新增机器成功应该刷新列表并关闭弹窗', async () => {
mockAddMachine.mockResolvedValue(wrapResponse({ id: 4, machineId: 'machine-004' }))
const wrapper = mountMachine()
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
})
it('新增机器时应该显示正确的弹窗标题', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
if (addBtn) {
await addBtn.trigger('click')
await flushPromises()
expect(wrapper.html()).toBeDefined()
}
})
})
describe('编辑机器', () => {
it('编辑机器成功应该刷新列表', async () => {
mockUpdateMachine.mockResolvedValue(wrapResponse(mockMachines[0]))
const wrapper = mountMachine()
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
})
it('编辑时机器ID应该被禁用', async () => {
const wrapper = mountMachine()
await flushPromises()
// 模拟点击编辑
const editBtn = wrapper.findAll('button').find((btn) => btn.text().includes('编辑'))
if (editBtn) {
await editBtn.trigger('click')
await flushPromises()
expect(wrapper.html()).toBeDefined()
}
})
})
describe('删除机器', () => {
it('删除机器成功应该刷新列表', async () => {
const { ElMessage } = await import('element-plus')
mockDeleteMachine.mockResolvedValue(wrapResponse(null))
const wrapper = mountMachine()
await flushPromises()
const deleteBtn = wrapper.findAll('button').find((btn) => btn.text().includes('删除'))
if (deleteBtn) {
await deleteBtn.trigger('click')
await flushPromises()
expect(mockDeleteMachine).toHaveBeenCalled()
}
})
it('删除确认取消时不应该调用删除 API', async () => {
const { ElMessageBox } = await import('element-plus')
;(ElMessageBox.confirm as any).mockRejectedValue('cancel')
const wrapper = mountMachine()
await flushPromises()
mockDeleteMachine.mockClear()
const deleteBtn = wrapper.findAll('button').find((btn) => btn.text().includes('删除'))
if (deleteBtn) {
await deleteBtn.trigger('click')
await flushPromises()
}
})
})
describe('分页功能', () => {
it('应该正确计算总数', async () => {
const wrapper = mountMachine()
await flushPromises()
expect(wrapper.find('.el-pagination').exists()).toBe(true)
})
it('切换每页条数应该重置页码为1', async () => {
const wrapper = mountMachine()
await flushPromises()
expect(wrapper.html()).toBeDefined()
})
})
describe('表单验证', () => {
it('机器ID为空时不应该提交', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
if (addBtn) {
await addBtn.trigger('click')
await flushPromises()
// 直接点击提交按钮
const submitBtn = wrapper.findAll('button').find((btn) => btn.text().includes('确定'))
if (submitBtn) {
await submitBtn.trigger('click')
await flushPromises()
// 验证没有调用新增 API
expect(mockAddMachine).not.toHaveBeenCalled()
}
}
})
})
describe('弹窗交互', () => {
it('点击取消按钮应该关闭弹窗', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
if (addBtn) {
await addBtn.trigger('click')
await flushPromises()
expect(wrapper.find('.el-dialog').exists()).toBe(true)
const cancelBtn = wrapper.findAll('button').find((btn) => btn.text().includes('取消'))
if (cancelBtn) {
await cancelBtn.trigger('click')
await flushPromises()
expect(wrapper.find('.el-dialog').exists()).toBe(false)
}
}
})
})
describe('错误处理', () => {
it('API 返回错误码应该正确处理', async () => {
mockListMachines.mockResolvedValue(wrapResponse([], 500, '获取失败'))
const wrapper = mountMachine()
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
})
it('新增返回错误应该处理', async () => {
mockAddMachine.mockResolvedValue(wrapResponse(null, 400, '新增失败'))
const wrapper = mountMachine()
await flushPromises()
expect(mockListMachines).toHaveBeenCalled()
})
})
describe('启用状态', () => {
it('编辑时应该显示启用状态开关', async () => {
const wrapper = mountMachine()
await flushPromises()
const editBtn = wrapper.findAll('button').find((btn) => btn.text().includes('编辑'))
if (editBtn) {
await editBtn.trigger('click')
await flushPromises()
expect(wrapper.html()).toBeDefined()
}
})
it('新增时不应该显示启用状态开关', async () => {
const wrapper = mountMachine()
await flushPromises()
const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增机器'))
if (addBtn) {
await addBtn.trigger('click')
await flushPromises()
expect(wrapper.html()).toBeDefined()
}
})
})
})