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