chore: 版本 0.1.0 更新 between-ui/in-ui 可配项与 query-component 完整支持
Node.js Build / build (push) Successful in 6s

This commit is contained in:
2026-08-10 22:10:57 +08:00
parent e938118594
commit 701cc5026e
4 changed files with 302 additions and 8 deletions
+242 -1
View File
@@ -1,6 +1,11 @@
import { afterEach, describe, expect, it } from 'vitest';
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';
import TransForm from '../src/TransForm.vue';
import HeadlessBetween from '../src/components/HeadlessBetween.vue';
import HeadlessDate from '../src/components/HeadlessDate.vue';
import HeadlessSelect from '../src/components/HeadlessSelect.vue';
import HeadlessTags from '../src/components/HeadlessTags.vue';
import { resetConfig, setConfig } from '../src/config.js';
// 每个用例后恢复全局配置,避免 setConfig 污染其它用例
@@ -55,6 +60,242 @@ describe('TransForm 操作符下拉(默认 query-option)', () => {
schema: [{ row: 12, field: 'custom', 'query-component': 'CustomQuery' }],
},
});
expect(wrapper.find('select').findAll('option')).toHaveLength(0);
// 配置了 query-component 后不再渲染默认 select,未知组件走占位
expect(wrapper.find('select').exists()).toBe(false);
expect(wrapper.find('.tf-unknown').exists()).toBe(true);
});
});
describe('between-ui / in-ui(DESIGN Q32/Q33)', () => {
it('未配置 between-ui 且 query=BETWEEN 时默认渲染双 input(HeadlessBetween)', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'age',
'field-name': '年龄',
'value-component': 'number',
'default-query': 'BETWEEN',
'query-option': [{ value: 'BETWEEN', label: 'BETWEEN' }],
},
],
},
});
expect(wrapper.findComponent(HeadlessBetween).exists()).toBe(true);
expect(wrapper.findAll('.tf-between-input')).toHaveLength(2);
});
it('未配置 in-ui 且 query=IN 时默认渲染 tags(HeadlessTags)', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'tags',
'field-name': '标签',
'value-component': 'input',
'default-query': 'IN',
'query-option': [{ value: 'IN', label: 'IN' }],
},
],
},
});
expect(wrapper.findComponent(HeadlessTags).exists()).toBe(true);
});
it('between-ui 指定 date 时渲染 HeadlessDate', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'age',
'field-name': '年龄',
'value-component': 'between',
'between-ui': 'date',
'default-query': 'BETWEEN',
'query-option': [{ value: 'BETWEEN', label: 'BETWEEN' }],
},
],
},
});
expect(wrapper.findComponent(HeadlessDate).exists()).toBe(true);
expect(wrapper.findComponent(HeadlessBetween).exists()).toBe(false);
expect(wrapper.find('input[type="date"]').exists()).toBe(true);
});
it('in-ui 指定 select 时渲染 HeadlessSelect', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'status',
'field-name': '状态',
'value-component': 'tags',
'in-ui': 'select',
'default-query': 'IN',
options: [
{ value: 'a', label: 'A' },
{ value: 'b', label: 'B' },
],
'query-option': [{ value: 'IN', label: 'IN' }],
},
],
},
});
expect(wrapper.findComponent(HeadlessSelect).exists()).toBe(true);
expect(wrapper.findComponent(HeadlessTags).exists()).toBe(false);
});
it('非 BETWEEN/IN 时仍走 value-component,忽略 between-ui/in-ui', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'age',
'value-component': 'number',
'between-ui': 'date',
'in-ui': 'select',
'default-query': 'EQ',
'query-option': [
{ value: 'EQ', label: '=' },
{ value: 'BETWEEN', label: 'BETWEEN' },
{ value: 'IN', label: 'IN' },
],
},
],
},
});
expect(wrapper.find('input[type="number"]').exists()).toBe(true);
expect(wrapper.findComponent(HeadlessDate).exists()).toBe(false);
expect(wrapper.findComponent(HeadlessSelect).exists()).toBe(false);
});
});
describe('query-component(DESIGN Q17/Q18)', () => {
it('无 query-component 时保持默认操作符下拉', () => {
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'name',
'field-name': '名称',
'query-option': [
{ value: 'EQ', label: '=' },
{ value: 'LIKE', label: 'LIKE' },
],
},
],
},
});
const select = wrapper.find('select');
expect(select.exists()).toBe(true);
expect(select.findAll('option')).toHaveLength(2);
expect(wrapper.vm.getFilters()[0].query).toBe('EQ');
});
it('配置 query-component 时渲染自定义组件且 v-model 绑定 query', async () => {
const CustomQuery = defineComponent({
name: 'CustomQuery',
props: {
modelValue: { type: String, default: '' },
field: { type: String, default: '' },
fieldName: { type: String, default: '' },
queryOption: { type: Array, default: () => [] },
schema: { type: Object, default: () => ({}) },
disabled: { type: Boolean, default: false },
readOnly: { type: Boolean, default: false },
},
emits: ['update:modelValue'],
setup(props, { emit }) {
return () =>
h('button', {
class: 'custom-query-btn',
type: 'button',
disabled: props.disabled,
onClick: () => emit('update:modelValue', 'LIKE'),
}, `query:${props.modelValue}`);
},
});
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'name',
'field-name': '名称',
'value-component': 'input',
'query-component': CustomQuery,
'default-query': 'EQ',
'query-option': [
{ value: 'EQ', label: '=' },
{ value: 'LIKE', label: 'LIKE' },
],
},
],
},
});
expect(wrapper.find('select').exists()).toBe(false);
const btn = wrapper.find('.custom-query-btn');
expect(btn.exists()).toBe(true);
expect(btn.text()).toBe('query:EQ');
expect(btn.attributes('disabled')).toBeUndefined();
await btn.trigger('click');
expect(wrapper.vm.getFilters()[0].query).toBe('LIKE');
expect(wrapper.find('.custom-query-btn').text()).toBe('query:LIKE');
});
it('query-component 字符串名可通过 componentMap 注册', async () => {
const CustomQuery = defineComponent({
name: 'MappedQuery',
inheritAttrs: false,
props: {
modelValue: { type: String, default: '' },
options: { type: Array, default: () => [] },
},
emits: ['update:modelValue'],
setup(props, { emit }) {
return () =>
h('select', {
class: 'mapped-query',
value: props.modelValue,
onChange: (e) => emit('update:modelValue', e.target.value),
}, [
h('option', { value: 'EQ' }, '='),
h('option', { value: 'GT' }, '>'),
]);
},
});
setConfig({ componentMap: { MappedQuery: CustomQuery } });
const wrapper = mount(TransForm, {
props: {
schema: [
{
row: 12,
field: 'age',
'query-component': 'MappedQuery',
'default-query': 'EQ',
'query-option': [
{ value: 'EQ', label: '=' },
{ value: 'GT', label: '>' },
],
},
],
},
});
const mapped = wrapper.find('.mapped-query');
expect(mapped.exists()).toBe(true);
await mapped.setValue('GT');
expect(wrapper.vm.getFilters()[0].query).toBe('GT');
});
});