build / task (16.x, npm, macOS-latest) (push) Canceled after 0s
build / task (16.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, npm, windows-latest) (push) Canceled after 0s
build / task (16.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (16.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (16.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (16.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, yarn, windows-latest) (push) Canceled after 0s
build / task (18.x, npm, macOS-latest) (push) Canceled after 0s
build / task (18.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, npm, windows-latest) (push) Canceled after 0s
build / task (18.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (18.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (18.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (18.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, yarn, windows-latest) (push) Canceled after 0s
build / task (20.x, npm, macOS-latest) (push) Canceled after 0s
build / task (20.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, npm, windows-latest) (push) Canceled after 0s
build / task (20.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (20.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (20.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (20.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, yarn, windows-latest) (push) Canceled after 0s
77 lines
4.0 KiB
TypeScript
77 lines
4.0 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { flushPromises, mount, type VueWrapper } from '@vue/test-utils';
|
|
import { defineComponent, h } from 'vue';
|
|
import { ElTree, ElInput, ElButton, ElIcon } from 'element-plus';
|
|
import * as icons from '@element-plus/icons-vue';
|
|
import GroupTree from '../src/components/DraggableDeviceGroupDraggable/index.vue';
|
|
|
|
const api = vi.hoisted(() => ({ query: vi.fn(), editGroupSort: vi.fn(), error: vi.fn() }));
|
|
vi.mock('../src/api/device/deviceGroup', () => ({ getDeviceGroupTree: api.query, editGroupSort: api.editGroupSort }));
|
|
vi.mock('../src/hooks/message', () => ({ useMessage: () => ({ error: api.error }) }));
|
|
const Slot = defineComponent({ setup(_, { slots }) { return () => h('div', slots.default?.()); } });
|
|
const groupData = () => [
|
|
{ id: 'group-a', name: '值班员视图', deep: 1, visible: true, children: [
|
|
{ id: 'a', parentId: 'group-a', name: '南门球机', code: 'channel-a', deep: 2, visible: true },
|
|
{ id: 'b', parentId: 'group-a', name: '西围墙', code: 'channel-b', deep: 2, visible: true },
|
|
] },
|
|
{ id: 'group-b', name: '兵器场', deep: 1, visible: true, children: [
|
|
{ id: 'c', parentId: 'group-b', name: '额外通道', code: 'channel-c', deep: 2, visible: true },
|
|
] },
|
|
];
|
|
let wrapper: VueWrapper;
|
|
const checkedCodes = () => (wrapper.emitted('getSelectNode')!.at(-1)![1] as any[]).filter(item => item.deep === 2).map(item => item.code);
|
|
beforeEach(() => {
|
|
api.query.mockReset().mockResolvedValue({ code: 0, data: groupData() });
|
|
wrapper = mount(GroupTree, { global: {
|
|
components: { ElTree, ElInput, ElButton, ElIcon, ...icons }, stubs: { Splitpanes: Slot, Pane: Slot, 'el-switch': true },
|
|
directives: { loading: () => undefined },
|
|
} });
|
|
});
|
|
afterEach(() => wrapper.unmount());
|
|
|
|
describe('分组树的真实勾选与筛选', () => {
|
|
it('默认勾选第一个分组,按树顺序提交可播放通道', async () => {
|
|
await flushPromises();
|
|
expect(checkedCodes()).toEqual(['channel-a', 'channel-b']);
|
|
expect(wrapper.find('.selection-count').text()).toBe('已选 2');
|
|
});
|
|
|
|
it('搜索只过滤展示,保留当前勾选且不重新请求或触发播放', async () => {
|
|
await flushPromises();
|
|
const count = wrapper.emitted('getSelectNode')!.length;
|
|
await wrapper.find('.sidebar-search input').setValue('额外');
|
|
await flushPromises();
|
|
expect(api.query).toHaveBeenCalledTimes(1);
|
|
expect(wrapper.emitted('getSelectNode')).toHaveLength(count);
|
|
expect(wrapper.findComponent(ElTree).vm.getCheckedNodes(true).map((item: any) => item.code)).toEqual(['channel-a', 'channel-b']);
|
|
const row = wrapper.findAll('.el-tree-node__content').find(item => item.text().includes('额外通道'))!;
|
|
expect(row.isVisible()).toBe(true);
|
|
await row.find('input[type="checkbox"]').setValue(true);
|
|
await flushPromises();
|
|
expect(checkedCodes()).toEqual(['channel-a', 'channel-b', 'channel-c']);
|
|
expect(wrapper.find('.selection-count').text()).toBe('已选 3');
|
|
});
|
|
|
|
it('清空选择会同步树和父页面,半选分组不会算成视频通道', async () => {
|
|
await flushPromises();
|
|
const row = wrapper.findAll('.el-tree-node__content').find(item => item.text().includes('南门球机'))!;
|
|
await row.find('input[type="checkbox"]').setValue(false);
|
|
await flushPromises();
|
|
expect(checkedCodes()).toEqual(['channel-b']);
|
|
expect(wrapper.find('.selection-count').text()).toBe('已选 1');
|
|
await wrapper.findAll('button').find(item => item.text() === '清空选择')!.trigger('click');
|
|
await flushPromises();
|
|
expect(checkedCodes()).toEqual([]);
|
|
expect(wrapper.findComponent(ElTree).vm.getCheckedNodes()).toHaveLength(0);
|
|
expect(wrapper.find('.selection-count').text()).toBe('已选 0');
|
|
});
|
|
|
|
it('空分组响应仍正常显示空树', async () => {
|
|
api.query.mockResolvedValueOnce({ code: 0, data: null });
|
|
await flushPromises();
|
|
await wrapper.vm.getTreeData();
|
|
await flushPromises();
|
|
expect(wrapper.text()).toContain('暂无匹配的分组或通道');
|
|
});
|
|
});
|