| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- 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: '<div class="el-card"><slot /><slot name="header" /></div>', props: ['shadow'] },
- 'el-form': { template: '<form class="el-form"><slot /></form>' },
- 'el-form-item': { template: '<div class="el-form-item"><slot /></div>', props: ['label'] },
- 'el-select': {
- template:
- '<select :value="modelValue" @change="$emit(\'update:modelValue\', $event.target.value)"><slot /></select>',
- props: ['modelValue', 'placeholder', 'clearable']
- },
- 'el-option': { template: '<option :value="value">{{ label }}</option>', props: ['label', 'value'] },
- 'el-date-picker': {
- template:
- '<input type="date" :value="modelValue" @input="$emit(\'update:modelValue\', $event.target.value)" />',
- props: ['modelValue', 'type', 'rangeSeparator', 'startPlaceholder', 'endPlaceholder', 'valueFormat']
- },
- 'el-button': {
- template: '<button @click="$emit(\'click\')" :disabled="loading"><slot /></button>',
- props: ['type', 'icon', 'loading', 'link', 'size']
- },
- 'el-row': { template: '<div class="el-row"><slot /></div>', props: ['gutter'] },
- 'el-col': { template: '<div class="el-col"><slot /></div>', props: ['xs', 'sm'] },
- 'el-statistic': {
- template: '<div class="el-statistic"><span>{{ title }}</span><span>{{ value }}</span></div>',
- props: ['title', 'value']
- },
- 'el-table': {
- template: '<table class="el-table"><slot /></table>',
- props: ['data', 'loading', 'border', 'stripe']
- },
- 'el-table-column': {
- template: '<td class="el-table-column"></td>',
- props: ['prop', 'label', 'width', 'align', 'showOverflowTooltip', 'fixed', 'minWidth']
- },
- 'el-tag': { template: '<span class="el-tag" :class="type"><slot /></span>', props: ['type', 'size'] },
- 'el-pagination': {
- template: '<div class="el-pagination"></div>',
- props: ['currentPage', 'pageSize', 'pageSizes', 'total', 'layout']
- },
- 'el-dialog': {
- template: '<div v-if="modelValue" class="el-dialog"><slot /><slot name="footer" /></div>',
- props: ['modelValue', 'title', 'width']
- },
- 'el-descriptions': { template: '<div class="el-descriptions"><slot /></div>', props: ['column', 'border'] },
- 'el-descriptions-item': { template: '<div class="el-descriptions-item"><slot /></div>', props: ['label'] },
- Search: { template: '<span>Search</span>' },
- Refresh: { template: '<span>Refresh</span>' }
- }
- }
- })
- }
- 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()
- })
- })
- })
|