tmagic-editor/packages/editor/tests/unit/fields/DisplayConds.spec.ts
2026-05-14 15:26:22 +08:00

169 lines
5.7 KiB
TypeScript

/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent.
*/
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';
import DisplayConds from '@editor/fields/DisplayConds.vue';
const dataSourceService = {
getDataSourceById: vi.fn(),
};
vi.mock('@editor/hooks/use-services', () => ({
useServices: () => ({ dataSourceService }),
}));
const { fieldTypeMock } = vi.hoisted(() => ({
fieldTypeMock: vi.fn((_ds: any, names: string[]) => {
const key = names?.[0];
if (key === 'numField') return 'number';
if (key === 'boolField') return 'boolean';
if (key === 'nullField') return 'null';
return 'string';
}),
}));
vi.mock('@editor/utils', async () => {
const actual = await vi.importActual<any>('@editor/utils');
return {
...actual,
getCascaderOptionsFromFields: vi.fn(() => [{ label: 'f1', value: 'f1' }]),
getFieldType: fieldTypeMock,
};
});
let capturedConfig: any = null;
vi.mock('@tmagic/form', async () => {
const actual = await vi.importActual<any>('@tmagic/form');
return {
...actual,
filterFunction: vi.fn((_m: any, v: any) => (typeof v === 'function' ? v() : v)),
MGroupList: defineComponent({
name: 'MGroupList',
props: ['config', 'name', 'disabled', 'model', 'lastValues', 'prop', 'size'],
emits: ['change'],
setup(props, { emit }) {
capturedConfig = props.config;
return () =>
h('div', {
class: 'fake-group-list',
onClick: () => emit('change', [{ field: ['fa'], op: 'eq', value: 'a' }]),
});
},
}),
};
});
beforeEach(() => {
vi.clearAllMocks();
capturedConfig = null;
dataSourceService.getDataSourceById.mockReturnValue({ fields: [{ name: 'a', type: 'string' }] });
});
describe('DisplayConds', () => {
test('change 事件初始化数组', async () => {
const model: any = {};
const wrapper = mount(DisplayConds, {
props: { config: { titlePrefix: 't', parentFields: [] }, model, name: 'conds' } as any,
});
await wrapper.find('.fake-group-list').trigger('click');
expect(model.conds).toEqual([]);
expect(wrapper.emitted('change')).toBeTruthy();
});
test('parentFields 不为空时使用 cascader', () => {
mount(DisplayConds, {
props: {
config: { titlePrefix: 't', parentFields: ['ds1'] },
model: {},
name: 'conds',
} as any,
});
const item = capturedConfig.items[0].items[0];
expect(item.type).toBe('cascader');
expect(item.options()).toEqual([{ label: 'f1', value: 'f1' }]);
});
test('parentFields 为空时使用 data-source-field-select', () => {
mount(DisplayConds, {
props: {
config: { titlePrefix: 't', parentFields: [] },
model: {},
name: 'conds',
} as any,
});
const item = capturedConfig.items[0].items[0];
expect(item.type).toBe('data-source-field-select');
});
test('value 字段类型 - number', () => {
mount(DisplayConds, {
props: { config: { titlePrefix: 't', parentFields: ['ds1'] }, model: {}, name: 'conds' } as any,
});
const valueItem = capturedConfig.items[0].items[2].items[0];
expect(valueItem.type(undefined, { model: { field: ['numField'] } })).toBe('number');
expect(valueItem.type(undefined, { model: { field: ['boolField'] } })).toBe('select');
expect(valueItem.type(undefined, { model: { field: ['nullField'] } })).toBe('display');
expect(valueItem.type(undefined, { model: { field: ['anyField'] } })).toBe('text');
});
test('value display 函数', () => {
mount(DisplayConds, {
props: { config: { titlePrefix: 't', parentFields: [] }, model: {}, name: 'conds' } as any,
});
const valueItem = capturedConfig.items[0].items[2].items[0];
expect(valueItem.display(undefined, { model: { op: 'eq' } })).toBe(true);
expect(valueItem.display(undefined, { model: { op: 'between' } })).toBe(false);
expect(valueItem.displayText(undefined, { model: { value: null } })).toBe('null');
expect(valueItem.displayText(undefined, { model: { value: 'a' } })).toBe('a');
});
test('range display 函数', () => {
mount(DisplayConds, {
props: { config: { titlePrefix: 't', parentFields: [] }, model: {}, name: 'conds' } as any,
});
const rangeItem = capturedConfig.items[0].items[2].items[1];
expect(rangeItem.display(undefined, { model: { op: 'between' } })).toBe(true);
expect(rangeItem.display(undefined, { model: { op: 'eq' } })).toBe(false);
});
test('field onChange 转换 model.value 类型', () => {
mount(DisplayConds, {
props: { config: { titlePrefix: 't', parentFields: ['ds1'] }, model: {}, name: 'conds' } as any,
});
const item = capturedConfig.items[0].items[0];
const m1: any = { value: '5' };
item.onChange(undefined, ['numField'], { model: m1 });
expect(m1.value).toBe(5);
const m2: any = { value: '' };
item.onChange(undefined, ['boolField'], { model: m2 });
expect(m2.value).toBe(false);
const m3: any = { value: 'x' };
item.onChange(undefined, ['nullField'], { model: m3 });
expect(m3.value).toBe(null);
const m4: any = { value: 1 };
item.onChange(undefined, ['strField'], { model: m4 });
expect(m4.value).toBe('1');
});
test('cascader options 没有 ds 时返回空', () => {
dataSourceService.getDataSourceById.mockReturnValue(null);
mount(DisplayConds, {
props: {
config: { titlePrefix: 't', parentFields: ['ds1'] },
model: {},
name: 'conds',
} as any,
});
const item = capturedConfig.items[0].items[0];
expect(item.options()).toEqual([]);
});
});