162 lines
5.3 KiB
JavaScript
162 lines
5.3 KiB
JavaScript
import { afterEach, describe, expect, it } from 'vitest';
|
||
import { getDefaultQueryOption, resetConfig, setConfig } from '../src/config.js';
|
||
import {
|
||
applyFilters,
|
||
buildFilters,
|
||
createFieldState,
|
||
groupRows,
|
||
resolveQueryOption,
|
||
} from '../src/composables/useFilters.js';
|
||
|
||
// 每个用例后恢复全局配置,避免 setConfig 污染其它用例
|
||
afterEach(() => {
|
||
resetConfig();
|
||
});
|
||
|
||
const schema = [
|
||
{
|
||
row: 6,
|
||
field: 'name',
|
||
'field-name': '名称',
|
||
'query-option': [{ value: 'EQ', label: '=' }],
|
||
},
|
||
{
|
||
row: 6,
|
||
logic: 'OR',
|
||
field: 'status',
|
||
'query-option': [{ value: 'NE', label: '≠' }],
|
||
},
|
||
];
|
||
|
||
describe('createFieldState', () => {
|
||
it('initializes default query from first option', () => {
|
||
const state = createFieldState(schema);
|
||
expect(state.name.query).toBe('EQ');
|
||
expect(state.status.logic).toBe('OR');
|
||
});
|
||
});
|
||
|
||
describe('buildFilters', () => {
|
||
it('emits logic from second item onward', () => {
|
||
const state = createFieldState(schema);
|
||
state.name.value = 'alice';
|
||
state.status.value = 'active';
|
||
const filters = buildFilters(schema, state);
|
||
expect(filters[0].logic).toBeUndefined();
|
||
expect(filters[1].logic).toBe('OR');
|
||
});
|
||
|
||
it('marks empty values', () => {
|
||
const state = createFieldState(schema);
|
||
const filters = buildFilters(schema, state);
|
||
expect(filters[0].empty).toBe(true);
|
||
expect(filters[0].value).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe('applyFilters', () => {
|
||
it('loads filters back into state', () => {
|
||
const loaded = applyFilters(schema, [
|
||
{ field: 'name', value: 'bob', query: 'EQ' },
|
||
]);
|
||
expect(loaded.name.value).toBe('bob');
|
||
});
|
||
});
|
||
|
||
describe('groupRows', () => {
|
||
it('wraps when row spans exceed 12', () => {
|
||
const groups = groupRows([
|
||
{ row: 2, field: 'a' },
|
||
{ row: 9, field: 'b' },
|
||
{ row: 4, field: 'c' },
|
||
]);
|
||
expect(groups).toHaveLength(2);
|
||
expect(groups[0]).toHaveLength(2);
|
||
expect(groups[1]).toHaveLength(1);
|
||
});
|
||
});
|
||
|
||
describe('resolveQueryOption(默认 query-option 解析)', () => {
|
||
it('无 query-option 且无 query-component 时返回默认操作符列表', () => {
|
||
const opts = resolveQueryOption({ field: 'name' });
|
||
expect(opts).toHaveLength(12);
|
||
expect(opts[0]).toEqual({ value: 'EQ', label: '=' });
|
||
expect(opts.map((o) => o.value)).toEqual([
|
||
'EQ', 'NE', 'GT', 'GTE', 'LT', 'LTE',
|
||
'LIKE', 'IN', 'NOT_IN', 'BETWEEN', 'IS_NULL', 'IS_NOT_NULL',
|
||
]);
|
||
});
|
||
|
||
it('有 query-option 的字段仍用 schema 自己的(不被默认覆盖)', () => {
|
||
const fieldDef = { field: 'name', 'query-option': [{ value: 'NE', label: '≠' }] };
|
||
expect(resolveQueryOption(fieldDef)).toEqual([{ value: 'NE', label: '≠' }]);
|
||
});
|
||
|
||
it('有 query-component 但无 query-option 时返回空数组(组件自己管理)', () => {
|
||
const fieldDef = { field: 'name', 'query-component': 'CustomQuery' };
|
||
expect(resolveQueryOption(fieldDef)).toEqual([]);
|
||
});
|
||
|
||
it('getDefaultQueryOption() 返回深拷贝:修改返回值不影响后续调用', () => {
|
||
const first = getDefaultQueryOption();
|
||
first.push({ value: 'X', label: 'x' });
|
||
first[0].label = '被改坏了';
|
||
first.splice(1, 1);
|
||
|
||
const second = getDefaultQueryOption();
|
||
expect(second).toHaveLength(12);
|
||
expect(second[0]).toEqual({ value: 'EQ', label: '=' });
|
||
expect(second[1]).toEqual({ value: 'NE', label: '≠' });
|
||
});
|
||
|
||
it('setConfig({ queryOption }) 后 getDefaultQueryOption() 返回新列表', () => {
|
||
setConfig({
|
||
queryOption: [
|
||
{ value: 'EQ', label: '=' },
|
||
{ value: 'GT', label: '>' },
|
||
],
|
||
});
|
||
expect(getDefaultQueryOption()).toEqual([
|
||
{ value: 'EQ', label: '=' },
|
||
{ value: 'GT', label: '>' },
|
||
]);
|
||
});
|
||
|
||
it('resetConfig() 恢复默认操作符列表', () => {
|
||
setConfig({ queryOption: [{ value: 'ONLY_EQ', label: '=' }] });
|
||
resetConfig();
|
||
expect(getDefaultQueryOption()).toHaveLength(12);
|
||
expect(getDefaultQueryOption()[0]).toEqual({ value: 'EQ', label: '=' });
|
||
});
|
||
});
|
||
|
||
describe('默认 query fallback(无 query-option 时取默认列表第一项)', () => {
|
||
it('createFieldState:无 query-option 且无 query-component 默认取默认列表第一项(EQ)', () => {
|
||
const state = createFieldState([{ field: 'name' }]);
|
||
expect(state.name.query).toBe('EQ');
|
||
});
|
||
|
||
it('buildFilters:无 query-option 且无 query-component 默认取默认列表第一项(EQ)', () => {
|
||
const state = createFieldState([{ field: 'name' }]);
|
||
const filters = buildFilters([{ field: 'name' }], state);
|
||
expect(filters[0].query).toBe('EQ');
|
||
});
|
||
|
||
it('setConfig 自定义 queryOption 后,默认 query 取新列表第一项', () => {
|
||
setConfig({ queryOption: [{ value: 'GT', label: '>' }] });
|
||
const state = createFieldState([{ field: 'age' }]);
|
||
expect(state.age.query).toBe('GT');
|
||
expect(buildFilters([{ field: 'age' }], state)[0].query).toBe('GT');
|
||
});
|
||
|
||
it('有 query-component 但无 query-option 时,默认 query 仍为 EQ', () => {
|
||
const state = createFieldState([{ field: 'custom', 'query-component': 'CustomQuery' }]);
|
||
expect(state.custom.query).toBe('EQ');
|
||
});
|
||
|
||
it('显式 default-query 优先级最高,覆盖默认列表第一项', () => {
|
||
const state = createFieldState([{ field: 'name', 'default-query': 'LIKE' }]);
|
||
expect(state.name.query).toBe('LIKE');
|
||
});
|
||
});
|