import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount, flushPromises } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import AuditView from '@/views/audit/index.vue' import { wrapPageResponse, wrapResponse } from '../../../fixtures' // Mock element-plus vi.mock('element-plus', () => ({ ElMessage: { success: vi.fn(), error: vi.fn(), info: vi.fn() } })) // Mock audit logs const mockAuditLogs = [ { id: '1', created_at: Math.floor(Date.now() / 1000), user_id: 'user-1', username: 'admin', action: 'create', resource: 'camera', resource_id: 'cam-001', ip_address: '192.168.1.1', user_agent: 'Mozilla/5.0', parsedDetails: { message: '创建了摄像头' } }, { id: '2', created_at: Math.floor(Date.now() / 1000) - 3600, user_id: 'user-1', username: 'admin', action: 'update', resource: 'user', resource_id: 'user-2', ip_address: '192.168.1.1', user_agent: 'Mozilla/5.0', parsedDetails: { message: '更新了用户信息' } }, { id: '3', created_at: Math.floor(Date.now() / 1000) - 7200, user_id: 'user-1', username: 'admin', action: 'login', resource: 'auth', resource_id: null, ip_address: '192.168.1.1', user_agent: 'Mozilla/5.0', parsedDetails: { message: '用户登录' } } ] // Mock audit API const mockGetAuditLogs = vi.fn() vi.mock('@/api/audit', () => ({ getAuditLogs: (...args: any[]) => mockGetAuditLogs(...args) })) describe('Audit View', () => { beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() mockGetAuditLogs.mockResolvedValue(wrapPageResponse(mockAuditLogs, 3)) }) const mountAudit = () => { return mount(AuditView, { global: { plugins: [createPinia()], stubs: { 'el-card': { template: '
', props: ['shadow'] }, 'el-form': { template: '
' }, 'el-form-item': { template: '
', props: ['label'] }, 'el-select': { template: '', props: ['modelValue', 'placeholder', 'clearable'] }, 'el-option': { template: '', props: ['label', 'value'] }, 'el-date-picker': { template: '', props: ['modelValue', 'type', 'rangeSeparator', 'startPlaceholder', 'endPlaceholder', 'valueFormat'] }, 'el-button': { template: '', props: ['type', 'icon', 'loading', 'link', 'size'] }, 'el-row': { template: '
', props: ['gutter'] }, 'el-col': { template: '
', props: ['xs', 'sm'] }, 'el-statistic': { template: '
{{ title }}{{ value }}
', props: ['title', 'value'] }, 'el-table': { template: '
', props: ['data', 'loading', 'border', 'stripe'] }, 'el-table-column': { template: '', props: ['prop', 'label', 'width', 'align', 'showOverflowTooltip', 'fixed', 'minWidth'] }, 'el-tag': { template: '', props: ['type', 'size'] }, 'el-pagination': { template: '
', props: ['currentPage', 'pageSize', 'pageSizes', 'total', 'layout'] }, 'el-dialog': { template: '
', props: ['modelValue', 'title', 'width'] }, 'el-descriptions': { template: '
', props: ['column', 'border'] }, 'el-descriptions-item': { template: '
', props: ['label'] }, Search: { template: 'Search' }, Refresh: { template: 'Refresh' } } } }) } describe('页面渲染', () => { it('应该正确渲染审计日志页面', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.find('.audit-container').exists()).toBe(true) }) it('应该显示搜索区域', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.find('.search-card').exists()).toBe(true) }) it('应该显示统计卡片', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.find('.stat-row').exists()).toBe(true) }) it('应该显示数据表格', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.find('.el-table').exists()).toBe(true) }) it('应该显示分页组件', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.find('.el-pagination').exists()).toBe(true) }) }) describe('数据加载', () => { it('页面加载时应该获取审计日志', async () => { mountAudit() await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() }) it('应该正确传递分页参数', async () => { mountAudit() await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalledWith( expect.objectContaining({ page: 1, pageSize: 20 }) ) }) }) describe('搜索和过滤', () => { it('点击搜索按钮应该触发查询', async () => { const wrapper = mountAudit() await flushPromises() mockGetAuditLogs.mockClear() const searchBtn = wrapper.findAll('button').find((btn) => btn.text().includes('搜索')) if (searchBtn) { await searchBtn.trigger('click') await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() } }) it('点击重置按钮应该清空筛选条件', async () => { const wrapper = mountAudit() await flushPromises() mockGetAuditLogs.mockClear() const resetBtn = wrapper.findAll('button').find((btn) => btn.text().includes('重置')) if (resetBtn) { await resetBtn.trigger('click') await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() } }) }) describe('刷新功能', () => { it('点击刷新按钮应该重新加载数据', async () => { const wrapper = mountAudit() await flushPromises() mockGetAuditLogs.mockClear() const refreshBtn = wrapper.findAll('button').find((btn) => btn.text().includes('刷新')) if (refreshBtn) { await refreshBtn.trigger('click') await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() } }) }) describe('操作类型标签', () => { it('创建操作应该显示为 success 类型', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) it('更新操作应该显示为 warning 类型', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) it('删除操作应该显示为 danger 类型', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) }) describe('详情弹窗', () => { it('点击详情按钮应该打开弹窗', async () => { const wrapper = mountAudit() await flushPromises() const detailBtn = wrapper.findAll('button').find((btn) => btn.text().includes('详情')) if (detailBtn) { await detailBtn.trigger('click') await flushPromises() expect(wrapper.find('.el-dialog').exists()).toBe(true) } }) }) describe('统计计数', () => { it('应该正确统计创建操作数量', async () => { const wrapper = mountAudit() await flushPromises() const stats = wrapper.findAll('.el-statistic') expect(stats.length).toBeGreaterThan(0) }) it('应该正确统计更新操作数量', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) }) describe('错误处理', () => { it('API 返回错误码应该正确处理', async () => { mockGetAuditLogs.mockResolvedValue(wrapResponse({ rows: [], total: 0 }, 500, '获取审计日志失败')) mountAudit() await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() }) it('API 返回空数据应该正确处理', async () => { mockGetAuditLogs.mockResolvedValue(wrapPageResponse([], 0)) mountAudit() await flushPromises() expect(mockGetAuditLogs).toHaveBeenCalled() }) }) describe('时间格式化', () => { it('应该正确格式化时间戳', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) }) describe('资源类型标签', () => { it('应该正确显示资源类型', async () => { const wrapper = mountAudit() await flushPromises() expect(wrapper.html()).toBeDefined() }) }) })