import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount, flushPromises } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import UserView from '@/views/user/index.vue' import { wrapResponse, wrapPageResponse, wrapErrorResponse } from '../../../fixtures' // Mock vue-router const mockPush = vi.fn() vi.mock('vue-router', () => ({ useRouter: () => ({ push: mockPush }), useRoute: () => ({ query: {} }) })) // 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 user API const mockListUsers = vi.fn() const mockCreateUser = vi.fn() const mockUpdateUser = vi.fn() const mockDeleteUser = vi.fn() const mockResetPassword = vi.fn() vi.mock('@/api/user', () => ({ listUsers: (...args: any[]) => mockListUsers(...args), createUser: (...args: any[]) => mockCreateUser(...args), updateUser: (...args: any[]) => mockUpdateUser(...args), deleteUser: (...args: any[]) => mockDeleteUser(...args), resetPassword: (...args: any[]) => mockResetPassword(...args) })) // Mock user data const mockUsers = [ { id: '1', username: 'admin', role: 'admin', createdAt: '2024-01-01T00:00:00Z', updatedAt: '2024-01-01T00:00:00Z' }, { id: '2', username: 'operator1', role: 'operator', createdAt: '2024-01-02T00:00:00Z', updatedAt: '2024-01-02T00:00:00Z' }, { id: '3', username: 'viewer1', role: 'viewer', createdAt: '2024-01-03T00:00:00Z', updatedAt: '2024-01-03T00:00:00Z' } ] describe('User View', () => { beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() mockListUsers.mockResolvedValue(wrapPageResponse(mockUsers, 3)) }) const mountUser = () => { return mount(UserView, { global: { plugins: [createPinia()], stubs: { 'el-form': { template: '
' }, 'el-form-item': { template: '
' }, 'el-input': { template: '', props: ['modelValue', 'placeholder', 'disabled', 'type'] }, 'el-select': { template: '', props: ['modelValue', 'placeholder', 'clearable'] }, 'el-option': { template: '', props: ['label', 'value'] }, 'el-button': { template: '', props: ['type', 'icon', 'loading', 'link'], computed: { htmlType() { return this.type === 'submit' ? 'submit' : 'button' } } }, 'el-table': { template: '
', props: ['data', 'loading', 'border'] }, 'el-table-column': { template: '', props: ['prop', 'label', 'width', 'align', 'type', 'fixed', 'minWidth'] }, 'el-tag': { template: '', props: ['type'] }, 'el-pagination': { template: '
', props: ['currentPage', 'pageSize', 'pageSizes', 'total', 'layout'] }, 'el-dialog': { template: '
', props: ['modelValue', 'title', 'width', 'destroyOnClose'] } } } }) } describe('页面渲染', () => { it('应该正确渲染用户管理页面', async () => { const wrapper = mountUser() await flushPromises() expect(wrapper.find('.page-container').exists()).toBe(true) expect(wrapper.find('.search-form').exists()).toBe(true) expect(wrapper.find('.table-actions').exists()).toBe(true) }) it('应该显示新增用户按钮', async () => { const wrapper = mountUser() await flushPromises() const addButton = wrapper.find('.table-actions button') expect(addButton.exists()).toBe(true) expect(addButton.text()).toContain('新增用户') }) it('页面加载时应该调用获取用户列表 API', async () => { mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) }) describe('用户列表', () => { it('应该正确显示用户数据', async () => { const wrapper = mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) it('搜索应该触发列表刷新', async () => { const wrapper = mountUser() await flushPromises() mockListUsers.mockClear() const searchBtn = wrapper.findAll('button').find((btn) => btn.text().includes('搜索')) if (searchBtn) { await searchBtn.trigger('click') await flushPromises() expect(mockListUsers).toHaveBeenCalled() } }) it('重置应该清空搜索条件', async () => { const wrapper = mountUser() await flushPromises() mockListUsers.mockClear() const resetBtn = wrapper.findAll('button').find((btn) => btn.text().includes('重置')) if (resetBtn) { await resetBtn.trigger('click') await flushPromises() expect(mockListUsers).toHaveBeenCalled() } }) }) describe('新增用户', () => { it('点击新增按钮应该打开弹窗', async () => { const wrapper = mountUser() await flushPromises() const addBtn = wrapper.findAll('button').find((btn) => btn.text().includes('新增用户')) expect(addBtn).toBeDefined() if (addBtn) { await addBtn.trigger('click') await flushPromises() expect(wrapper.find('.el-dialog').exists()).toBe(true) } }) it('新增用户成功应该刷新列表', async () => { mockCreateUser.mockResolvedValue(wrapResponse({ id: '4', username: 'newuser', role: 'viewer' })) const wrapper = mountUser() 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) } }) }) describe('编辑用户', () => { it('编辑用户成功应该刷新列表', async () => { mockUpdateUser.mockResolvedValue(wrapResponse({ id: '1', username: 'admin', role: 'admin' })) const wrapper = mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) }) describe('删除用户', () => { it('删除用户成功应该刷新列表', async () => { const { ElMessageBox, ElMessage } = await import('element-plus') mockDeleteUser.mockResolvedValue(wrapResponse(null)) const wrapper = mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) }) describe('重置密码', () => { it('重置密码成功应该显示成功消息', async () => { mockResetPassword.mockResolvedValue(wrapResponse(null)) const wrapper = mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) }) describe('角色显示', () => { it('应该正确转换角色标签', async () => { const wrapper = mountUser() await flushPromises() // 角色标签转换测试 expect(wrapper.html()).toBeDefined() }) }) describe('API 错误处理', () => { it('API 返回错误码应该正确处理', async () => { mockListUsers.mockResolvedValue(wrapErrorResponse('获取失败', 500)) const wrapper = mountUser() await flushPromises() expect(mockListUsers).toHaveBeenCalled() }) it('创建用户返回错误应该处理', async () => { mockCreateUser.mockResolvedValue(wrapErrorResponse('用户名已存在', 400)) const wrapper = mountUser() await flushPromises() expect(wrapper.html()).toBeDefined() }) }) })