import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { defineComponent, h } from 'vue'; import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'; import Platform from '../src/views/collection/video/platform.vue'; const api = vi.hoisted(() => ({ status: vi.fn(), logs: vi.fn(), open: vi.fn(), sync: vi.fn() })); vi.mock('/@/api/collection/videoPlatform', () => ({ getStatus: api.status, syncPlatform: api.sync })); vi.mock('/@/api/com/comDhLog', () => ({ fetchList: api.logs })); vi.mock('/@/api/com/comDhSetting', () => ({ testConnection: vi.fn() })); vi.mock('/@/hooks/message', () => ({ useMessage: () => ({ success: vi.fn(), warning: vi.fn(), error: vi.fn() }) })); vi.mock('/@/views/alarm/setting/dhIccSetting/dh-icc-setting.vue', () => ({ default: { render: () => null } })); vi.mock('/@/views/collection/video/components/platform-resource-dialog.vue', () => ({ default: { setup: (_: unknown, { expose }: any) => { expose({ open: api.open }); return () => null; } }, })); const slotStub = defineComponent({ setup: (_, { slots }) => () => h('div', slots.default?.()) }); const mounted: VueWrapper[] = []; const status = () => ({ connected: true, version: 'test', releaseDate: '', message: '', checkedAt: '', remoteDeviceCount: 1, localDeviceCount: 1, deviceDifference: 0, remoteChannelCount: 2, localChannelCount: 2, channelDifference: 0, onlineDeviceCount: 1, remotePersonCount: 3, localPersonCount: 2, personDifference: 1, remoteCarCount: 4, localCarCount: 5, carDifference: -1, }); async function setupPage() { const wrapper = mount(Platform, { global: { directives: { loading: () => {}, auth: () => {} }, stubs: { ElTag: slotStub, ElIcon: slotStub, ElDivider: slotStub, ElTable: slotStub, ElTableColumn: true, ElAlert: true, ElFormItem: slotStub, DictSelect: true, ElButton: defineComponent({ setup: (_, { slots }) => () => h('button', slots.default?.()) }), }, }, }); mounted.push(wrapper); await flushPromises(); return wrapper; } beforeEach(() => { vi.resetAllMocks(); api.status.mockResolvedValue({ data: status() }); api.logs.mockResolvedValue({ data: { records: [] } }); }); afterEach(() => mounted.splice(0).forEach(wrapper => wrapper.unmount())); describe('ICC 平台人员车辆状态', () => { it('总体状态及最近结果包含人员和车辆差异', async () => { const wrapper = await setupPage(); expect(wrapper.text()).toContain('存在差异'); expect(wrapper.text()).toContain('人员差异 +1,车辆差异 -1'); expect(wrapper.get('[aria-label="查看 ICC 人员明细"]').text()).toContain('3'); expect(wrapper.get('[aria-label="查看本地同步车辆明细"]').text()).toContain('5'); }); it('人员车辆的 ICC、本地、差异数量均可打开对应弹窗', async () => { const wrapper = await setupPage(); for (const [type, label] of [['PERSON', '人员'], ['CAR', '车辆']]) { for (const [view, aria] of [ ['REMOTE', `查看 ICC ${label}明细`], ['LOCAL', `查看本地同步${label}明细`], ['DIFFERENCE', `查看${label}差异明细`], ]) { await wrapper.get(`[aria-label="${aria}"]`).trigger('click'); expect(api.open).toHaveBeenLastCalledWith(type, view, expect.any(String)); } } }); it('四类数量均一致时才显示数量一致', async () => { api.status.mockResolvedValue({ data: { ...status(), personDifference: 0, carDifference: 0 } }); const wrapper = await setupPage(); expect(wrapper.text()).toContain('ICC 与本地设备、通道、人员和车辆数量一致'); }); it('部分档案读取失败时保留成功数量并展示异常', async () => { api.status.mockResolvedValue({ data: { ...status(), connected: false, remoteCarCount: null, carDifference: null, message: '车辆数量读取失败', } }); const wrapper = await setupPage(); expect(wrapper.text()).toContain('状态异常'); expect(wrapper.text()).toContain('车辆数量读取失败'); expect(wrapper.get('[aria-label="查看 ICC 人员明细"]').text()).toContain('3'); expect(wrapper.get('[aria-label="查看车辆差异明细"]').text()).toContain('等待 ICC 数据'); }); });