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() } }) }) })