import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount, flushPromises } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import { createI18n } from 'vue-i18n' import DashboardView from '@/views/dashboard/index.vue' import { wrapResponse, mockDashboardStats } 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() } })) // Mock __APP_VERSION__ vi.stubGlobal('__APP_VERSION__', '1.0.0') // Mock stats API const mockGetDashboardStats = vi.fn() vi.mock('@/api/stats', () => ({ getDashboardStats: () => mockGetDashboardStats() })) // Create i18n instance const i18n = createI18n({ legacy: false, locale: 'zh-CN', messages: { 'zh-CN': { 仪表盘: '仪表盘', '欢迎回来,这是您的数据概览': '欢迎回来,这是您的数据概览', 机器总数: '机器总数', 已启用: '已启用', 已禁用: '已禁用', 摄像头总数: '摄像头总数', 在线: '在线', 离线: '离线', 通道总数: '通道总数', 可用通道数量: '可用通道数量', 摄像头在线率: '摄像头在线率', 系统运行正常: '系统运行正常', 快捷操作: '快捷操作', 刷新数据: '刷新数据', 摄像头管理: '摄像头管理', 机器管理: '机器管理', 'Stream 测试': 'Stream 测试', 观看统计: '观看统计', 系统信息: '系统信息', 系统状态: '系统状态', 正常: '正常', 数据更新时间: '数据更新时间', 版本: '版本', 获取统计数据失败: '获取统计数据失败' } } }) describe('Dashboard View', () => { beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() mockGetDashboardStats.mockResolvedValue(wrapResponse(mockDashboardStats)) mockPush.mockClear() }) const mountDashboard = () => { return mount(DashboardView, { global: { plugins: [createPinia(), i18n] } }) } describe('页面渲染', () => { it('应该正确渲染仪表盘页面', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.page-container').exists()).toBe(true) expect(wrapper.find('.dashboard__header').exists()).toBe(true) expect(wrapper.find('.dashboard__title').exists()).toBe(true) }) it('应该显示页面标题', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.dashboard__title').text()).toBe('仪表盘') }) it('应该显示统计卡片', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.dashboard__stats').exists()).toBe(true) expect(wrapper.findAll('.dashboard__card').length).toBe(4) }) it('应该显示快捷操作按钮', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.dashboard__actions').exists()).toBe(true) expect(wrapper.findAll('.dashboard__action').length).toBeGreaterThan(0) }) it('应该显示系统信息', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.dashboard__info').exists()).toBe(true) }) }) describe('数据加载', () => { it('页面加载时应该调用获取统计数据 API', async () => { mountDashboard() await flushPromises() expect(mockGetDashboardStats).toHaveBeenCalled() }) it('应该正确显示机器总数', async () => { const wrapper = mountDashboard() await flushPromises() const cards = wrapper.findAll('.dashboard__card') const machineCard = cards[0] expect(machineCard.find('.dashboard__card-value').text()).toBe(String(mockDashboardStats.machineTotal)) }) it('应该正确显示摄像头总数', async () => { const wrapper = mountDashboard() await flushPromises() const cards = wrapper.findAll('.dashboard__card') const cameraCard = cards[1] expect(cameraCard.find('.dashboard__card-value').text()).toBe(String(mockDashboardStats.cameraTotal)) }) it('应该正确显示通道总数', async () => { const wrapper = mountDashboard() await flushPromises() const cards = wrapper.findAll('.dashboard__card') const channelCard = cards[2] expect(channelCard.find('.dashboard__card-value').text()).toBe(String(mockDashboardStats.channelTotal)) }) it('应该正确计算并显示在线率', async () => { const wrapper = mountDashboard() await flushPromises() const expectedRate = Math.round((mockDashboardStats.cameraOnline / mockDashboardStats.cameraTotal) * 100) const cards = wrapper.findAll('.dashboard__card') const rateCard = cards[3] expect(rateCard.find('.dashboard__card-value').text()).toContain(String(expectedRate)) }) }) describe('快捷操作导航', () => { it('点击摄像头管理应该跳转', async () => { const wrapper = mountDashboard() await flushPromises() const actions = wrapper.findAll('.dashboard__action') const cameraAction = actions.find((a) => a.text().includes('摄像头管理')) if (cameraAction) { await cameraAction.trigger('click') expect(mockPush).toHaveBeenCalledWith('/camera') } }) it('点击机器管理应该跳转', async () => { const wrapper = mountDashboard() await flushPromises() const actions = wrapper.findAll('.dashboard__action') const machineAction = actions.find((a) => a.text().includes('机器管理')) if (machineAction) { await machineAction.trigger('click') expect(mockPush).toHaveBeenCalledWith('/machine') } }) it('点击 Stream 测试应该跳转', async () => { const wrapper = mountDashboard() await flushPromises() const actions = wrapper.findAll('.dashboard__action') const streamAction = actions.find((a) => a.text().includes('Stream 测试')) if (streamAction) { await streamAction.trigger('click') expect(mockPush).toHaveBeenCalledWith('/stream-test') } }) it('点击观看统计应该跳转', async () => { const wrapper = mountDashboard() await flushPromises() const actions = wrapper.findAll('.dashboard__action') const statsAction = actions.find((a) => a.text().includes('观看统计')) if (statsAction) { await statsAction.trigger('click') expect(mockPush).toHaveBeenCalledWith('/stats') } }) }) describe('刷新数据', () => { it('点击刷新按钮应该重新加载数据', async () => { const wrapper = mountDashboard() await flushPromises() mockGetDashboardStats.mockClear() const refreshBtn = wrapper.find('.dashboard__refresh') await refreshBtn.trigger('click') await flushPromises() expect(mockGetDashboardStats).toHaveBeenCalled() }) it('刷新时应该显示加载状态', async () => { let resolvePromise: Function mockGetDashboardStats.mockImplementation( () => new Promise((resolve) => { resolvePromise = resolve }) ) const wrapper = mountDashboard() await flushPromises() mockGetDashboardStats.mockClear() mockGetDashboardStats.mockImplementation( () => new Promise((resolve) => { resolvePromise = () => resolve(wrapResponse(mockDashboardStats)) }) ) const refreshBtn = wrapper.find('.dashboard__refresh') await refreshBtn.trigger('click') // 检查加载状态图标 expect(wrapper.find('.dashboard__refresh-icon').exists()).toBe(true) resolvePromise!() await flushPromises() }) }) describe('错误处理', () => { it('获取数据失败应该显示错误消息', async () => { const { ElMessage } = await import('element-plus') mockGetDashboardStats.mockResolvedValue(wrapResponse(null, false, '服务器错误')) mountDashboard() await flushPromises() // 错误处理逻辑测试 expect(mockGetDashboardStats).toHaveBeenCalled() }) it('网络错误应该显示错误消息', async () => { mockGetDashboardStats.mockResolvedValue(wrapResponse(null, false, '网络错误')) mountDashboard() await flushPromises() expect(mockGetDashboardStats).toHaveBeenCalled() }) }) describe('系统信息', () => { it('应该显示系统状态为正常', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.find('.dashboard__badge--success').text()).toBe('正常') }) it('应该显示版本号', async () => { const wrapper = mountDashboard() await flushPromises() expect(wrapper.text()).toContain('v1.0.0') }) it('数据更新后应该显示更新时间', async () => { const wrapper = mountDashboard() await flushPromises() const infoItems = wrapper.findAll('.dashboard__info-item') const updateTimeItem = infoItems.find((item) => item.text().includes('数据更新时间')) expect(updateTimeItem).toBeDefined() }) }) describe('空数据处理', () => { it('无数据时应该显示默认值', async () => { mockGetDashboardStats.mockResolvedValue(wrapResponse(null)) const wrapper = mountDashboard() await flushPromises() const cards = wrapper.findAll('.dashboard__card') // 默认值为 0 expect(cards[0].find('.dashboard__card-value').text()).toBe('0') }) it('在线率为零时应该显示 0%', async () => { mockGetDashboardStats.mockResolvedValue( wrapResponse({ ...mockDashboardStats, cameraTotal: 0, cameraOnline: 0 }) ) const wrapper = mountDashboard() await flushPromises() const cards = wrapper.findAll('.dashboard__card') const rateCard = cards[3] expect(rateCard.find('.dashboard__card-value').text()).toContain('0') }) }) })