20260917165839
This commit is contained in:
1 parent
182ed86966
commit
38e1e66c3b
108 files changed
+2497
-1215
No files matched your search
@@ -62,6 +62,36 @@ describe('FmsExportDialog 批量导出', () => {
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
||||
it('全部列已勾选但顺序不同仍可恢复列表顺序', async () => {
|
||||
countExportApi.mockResolvedValue({ data: { total: 8 } })
|
||||
const wrapper = await openDialog({ savedColumns: ['b_amount', 'b_name', 'b_bz'] })
|
||||
expect(buttonByText('全选').disabled).toBe(false)
|
||||
buttonByText('全选').click()
|
||||
await nextTick()
|
||||
await download()
|
||||
expect(exportListApi.mock.calls.at(-1)[0].columns).toEqual(['b_name', 'b_bz', 'b_amount'])
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('重新打开后忽略上次未完成的计数响应', async () => {
|
||||
let finishFirst
|
||||
countExportApi.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
finishFirst = resolve
|
||||
}),
|
||||
)
|
||||
const wrapper = await openDialog()
|
||||
await wrapper.setProps({ open: false })
|
||||
countExportApi.mockResolvedValueOnce({ data: { total: 7 } })
|
||||
await wrapper.setProps({ open: true, searchCondition: 'b_canuse = 1' })
|
||||
await flushPromises()
|
||||
finishFirst({ data: { total: 100 } })
|
||||
await flushPromises()
|
||||
expect(document.querySelector('.export-dialog__total').textContent).toContain('共 7 条数据')
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('打开后渲染全部候选列且默认全选,并显示后端统计的条数', async () => {
|
||||
countExportApi.mockResolvedValue({ data: { total: 8 } })
|
||||
exportListApi.mockResolvedValue('x.xlsx')
|
||||
@@ -104,7 +134,9 @@ describe('FmsExportDialog 批量导出', () => {
|
||||
await openDialog({ savedColumns: ['b_amount', 'b_name'] })
|
||||
|
||||
// 显示顺序 = 已保存顺序 + 未保存的列(未勾选)
|
||||
const names = [...document.querySelectorAll('.export-dialog__field-name')].map((n) => n.textContent)
|
||||
const names = [...document.querySelectorAll('.export-dialog__field-name')].map(
|
||||
(n) => n.textContent,
|
||||
)
|
||||
expect(names).toEqual(['金额', '名称', '备注'])
|
||||
expect(checkboxes().filter((input) => input.checked)).toHaveLength(2)
|
||||
|
||||
@@ -137,7 +169,7 @@ describe('FmsExportDialog 批量导出', () => {
|
||||
expect(params.volumeSize).toBeUndefined()
|
||||
})
|
||||
|
||||
it('分页拆分导出带 volumeSize 且不输出合计', async () => {
|
||||
it('分卷导出带 volumeSize 并沿用默认合计', async () => {
|
||||
countExportApi.mockResolvedValue({ data: { total: 800 } })
|
||||
exportListApi.mockResolvedValue('x.zip')
|
||||
await openDialog()
|
||||
@@ -215,16 +247,18 @@ describe('FmsExportDialog 批量导出', () => {
|
||||
|
||||
it('保存配置上抛字段;全选等于回到列表列并清掉个人覆盖', async () => {
|
||||
countExportApi.mockResolvedValue({ data: { total: 8 } })
|
||||
const wrapper = await openDialog({ savedColumns: ['b_name'] })
|
||||
const wrapper = await openDialog({ savedColumns: ['b_amount'] })
|
||||
|
||||
buttonByText('保存配置').click()
|
||||
await nextTick()
|
||||
expect(wrapper.emitted('save-columns')?.at(-1)).toEqual([['b_name']])
|
||||
expect(wrapper.emitted('save-columns')?.at(-1)).toEqual([['b_amount']])
|
||||
|
||||
buttonByText('全选').click()
|
||||
await nextTick()
|
||||
// 全选 = 回到列表列,顺手清掉个人覆盖(空数组)
|
||||
expect(wrapper.emitted('save-columns')?.at(-1)).toEqual([[]])
|
||||
expect(checkboxes().every((input) => input.checked)).toBe(true)
|
||||
await download()
|
||||
expect(exportListApi.mock.calls.at(-1)[0].columns).toEqual(['b_name', 'b_bz', 'b_amount'])
|
||||
})
|
||||
})
|
||||
@@ -2,7 +2,7 @@
|
||||
* FmsModuleListPage 冒烟测试(V2:元数据来自 s_field + s_module_schema JSON)。
|
||||
* 验证:按模块编码加载字段与 view/query 界面配置后,能正常渲染数据列、无配置错误。
|
||||
*/
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { nextTick } from 'vue'
|
||||
@@ -20,6 +20,13 @@ const querySchema = {
|
||||
quick: ['b_name'],
|
||||
groups: [{ logic: 'and', conditions: [{ field: 'b_name', operator: 'like' }] }],
|
||||
}
|
||||
let withSummary = false
|
||||
|
||||
vi.mock('@/services/exportService', () => ({
|
||||
exportListApi: vi.fn(async () => 'data.xlsx'),
|
||||
loadTotalsApi: vi.fn(async () => ({ data: { b_amount: 120.5 } })),
|
||||
countExportApi: vi.fn(async () => ({ data: { total: 5 } })),
|
||||
}))
|
||||
|
||||
vi.mock('@/services/api', () => ({
|
||||
loadDataApi: vi.fn(async (viewName) => {
|
||||
@@ -42,6 +49,7 @@ vi.mock('@/services/api', () => ({
|
||||
data: [
|
||||
{ b_field: 'b_id', b_name: '语言编码', b_type: 'input', b_canuse: 1, b_i18n: null },
|
||||
{ b_field: 'b_name', b_name: '语言名称', b_type: 'input', b_canuse: 1, b_i18n: null },
|
||||
{ b_field: 'b_amount', b_name: '金额', b_type: 'money', b_canuse: 1 },
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -56,6 +64,7 @@ vi.mock('@/services/api', () => ({
|
||||
columns: [
|
||||
{ field: 'b_id', width: 120 },
|
||||
{ field: 'b_name', width: 180 },
|
||||
...(withSummary ? [{ field: 'b_amount', width: 120, summary: 'sum' }] : []),
|
||||
],
|
||||
}),
|
||||
},
|
||||
@@ -79,10 +88,15 @@ vi.mock('@/services/api', () => ({
|
||||
|
||||
import FmsModuleListPage from '@/components/fms-module-list/FmsModuleListPage.vue'
|
||||
import { pageDataApi } from '@/services/api'
|
||||
import { exportListApi, loadTotalsApi } from '@/services/exportService'
|
||||
import { Pagination } from '@/components/ui'
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
pageDataApi.mockClear()
|
||||
exportListApi.mockClear()
|
||||
loadTotalsApi.mockClear()
|
||||
withSummary = false
|
||||
Object.defineProperty(HTMLElement.prototype, 'clientWidth', {
|
||||
configurable: true,
|
||||
get() {
|
||||
@@ -101,6 +115,79 @@ const lastCondition = () =>
|
||||
pageDataApi.mock.calls[pageDataApi.mock.calls.length - 1][0].searchCondition
|
||||
|
||||
describe('FmsModuleListPage 冒烟', () => {
|
||||
it('配置合计后底层表格显示当页及总合计,翻页导出使用当前区间', async () => {
|
||||
withSummary = true
|
||||
pageDataApi.mockResolvedValueOnce({
|
||||
data: {
|
||||
rows: [
|
||||
{ b_id: '1', b_amount: 10.2 },
|
||||
{ b_id: '2', b_amount: 20.3 },
|
||||
],
|
||||
total: 5,
|
||||
},
|
||||
})
|
||||
const wrapper = mount(FmsModuleListPage, {
|
||||
props: { dataCode: 's_i18n_type', pageSize: 2, fixedSearchCondition: 'b_canuse = 1' },
|
||||
attachTo: document.body,
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.stk-footer').text()).toContain('该页合计')
|
||||
expect(wrapper.find('.stk-footer').text()).toContain('30.50')
|
||||
expect(wrapper.find('.stk-footer').text()).toContain('总合计')
|
||||
expect(wrapper.find('.stk-footer').text()).toContain('120.50')
|
||||
expect(loadTotalsApi).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ searchCondition: '(b_canuse = 1)' }),
|
||||
)
|
||||
|
||||
pageDataApi.mockResolvedValueOnce({
|
||||
data: {
|
||||
rows: [
|
||||
{ b_id: '3', b_amount: 40 },
|
||||
{ b_id: '4', b_amount: 25 },
|
||||
],
|
||||
total: 5,
|
||||
},
|
||||
})
|
||||
wrapper.findComponent(Pagination).vm.$emit('change', 2, 2)
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.stk-footer').text()).toContain('65.00')
|
||||
await wrapper.find('button[title="导出当页数据;勾选行则只导出勾选"]').trigger('click')
|
||||
await flushPromises()
|
||||
expect(exportListApi).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
rangeStart: 3,
|
||||
rangeEnd: 4,
|
||||
columns: ['b_id', 'b_name', 'b_amount'],
|
||||
searchCondition: '(b_canuse = 1)',
|
||||
orderBy: 'b_id DESC',
|
||||
}),
|
||||
)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('勾选导出不叠加当前页范围,空页不发送非法导出区间', async () => {
|
||||
const wrapper = mount(FmsModuleListPage, {
|
||||
props: { dataCode: 's_i18n_type', rowSelection: { selectedRowKeys: ['a', 'b'] } },
|
||||
attachTo: document.body,
|
||||
})
|
||||
await flushPromises()
|
||||
const button = () => wrapper.find('button[title="导出当页数据;勾选行则只导出勾选"]')
|
||||
await button().trigger('click')
|
||||
await flushPromises()
|
||||
expect(exportListApi).toHaveBeenLastCalledWith(expect.objectContaining({ rowKeys: ['a', 'b'] }))
|
||||
expect(exportListApi.mock.calls.at(-1)[0]).not.toHaveProperty('rangeStart')
|
||||
await wrapper.setProps({ rowSelection: null })
|
||||
pageDataApi.mockResolvedValueOnce({ data: { rows: [], total: 0 } })
|
||||
await wrapper.vm.reload()
|
||||
await flushPromises()
|
||||
exportListApi.mockClear()
|
||||
await button().trigger('click')
|
||||
await flushPromises()
|
||||
expect(exportListApi).not.toHaveBeenCalled()
|
||||
expect(loadTotalsApi).not.toHaveBeenCalled()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('按 data-code 加载字段与界面配置后渲染列,无配置错误', async () => {
|
||||
const wrapper = mount(FmsModuleListPage, {
|
||||
props: { dataCode: 's_i18n_type' },
|
||||
|
||||
@@ -46,26 +46,49 @@ describe('collectManagedI18nItems 受管键收集', () => {
|
||||
expect(items[1].defaultValue).toBe('姓名')
|
||||
})
|
||||
|
||||
it('收集界面配置分组标题的受管键', () => {
|
||||
it('收集界面配置分组标题的受管键:手填键优先,未填按 group.{模块}.{schema}.{编号} 派生', () => {
|
||||
const items = collectManagedI18nItems({
|
||||
module: demoModule(),
|
||||
fields: [],
|
||||
schemas: [
|
||||
{
|
||||
schemaVersion: 1,
|
||||
children: [
|
||||
{
|
||||
type: 'group',
|
||||
title: '基础信息',
|
||||
i18n: 'group.demo.basic',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
schemaType: 'view',
|
||||
schema: {
|
||||
schemaVersion: 1,
|
||||
children: [
|
||||
{
|
||||
type: 'group',
|
||||
id: 'group1',
|
||||
title: '基础信息',
|
||||
i18n: 'group.demo.basic',
|
||||
children: [],
|
||||
},
|
||||
{ type: 'group', id: 'group2', title: '费用信息', children: [] },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(items.map((i) => i.key)).toContain('group.demo.basic')
|
||||
expect(items.find((i) => i.key === 'group.demo.basic').defaultValue).toBe('基础信息')
|
||||
// 未手填键的分组:按 schema 类型 + 分组编号派生,标题原文作为默认语言值
|
||||
const derived = items.find((i) => i.key === 'group.demo.view.group2')
|
||||
expect(derived.defaultValue).toBe('费用信息')
|
||||
expect(derived.id).toBe('group:group.demo.view.group2')
|
||||
})
|
||||
|
||||
it('分组缺失编号(老数据未归一化)时不派生病造键', () => {
|
||||
const items = collectManagedI18nItems({
|
||||
module: demoModule(),
|
||||
fields: [],
|
||||
schemas: [
|
||||
{
|
||||
schemaType: 'edit',
|
||||
schema: { schemaVersion: 1, children: [{ type: 'group', title: '基础信息' }] },
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(items.filter((i) => i.key.startsWith('group.'))).toEqual([])
|
||||
})
|
||||
|
||||
it('模块编码为空时不产出受管键(新建未填编码)', () => {
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* 查询配置面板回写语义(module-management):
|
||||
* - query 行草稿与 query JSON 不是一一映射(缺省 component/quick/groups、运行时写入的
|
||||
* area 等),只加载(含保存后同模块重载、schema ref 换新对象)不得回写,
|
||||
* 否则草稿与库中基线文本不一致 → 切树节点误报「未保存」,并静默改写未建模属性;
|
||||
* - 用户真实编辑(改操作符/组件/默认值、增删行)必须回写;
|
||||
* - 回写保留编辑器未建模的条件属性(如 area)。
|
||||
*/
|
||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { nextTick } from 'vue'
|
||||
import ModuleQueryConfigPanel from '@/views/module/module-management/ModuleQueryConfigPanel.vue'
|
||||
|
||||
// jsdom 无布局:StkTable 在 clientWidth 为 0 时启用虚拟列裁剪,补成宽容器
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(HTMLElement.prototype, 'clientWidth', {
|
||||
configurable: true,
|
||||
get() {
|
||||
return 5000
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
/** 库中历史查询配置:缺 quick 键、条件未显式写 component,且带运行时写入的 area */
|
||||
const legacySchema = {
|
||||
schemaVersion: 1,
|
||||
groups: [
|
||||
{
|
||||
logic: 'and',
|
||||
conditions: [
|
||||
{ field: 'b_name', operator: 'like', area: 'hidden' },
|
||||
{ field: 'b_amount', operator: 'eq', component: 'number' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{ b_field: 'b_name', b_name: '名称', b_type: 'input', b_canuse: 1 },
|
||||
{ b_field: 'b_amount', b_name: '金额', b_type: 'money', b_canuse: 1 },
|
||||
]
|
||||
|
||||
async function mountPanel(modelValue) {
|
||||
const pinia = createPinia()
|
||||
pinia.install({ provide() {}, config: { globalProperties: {} } })
|
||||
setActivePinia(pinia)
|
||||
const wrapper = mount(ModuleQueryConfigPanel, {
|
||||
props: { moduleId: 'demo', fields, modelValue, loading: false },
|
||||
global: { plugins: [pinia] },
|
||||
attachTo: document.body,
|
||||
})
|
||||
await nextTick()
|
||||
return wrapper
|
||||
}
|
||||
|
||||
const lastSchema = (wrapper) => {
|
||||
const events = wrapper.emitted('update:modelValue') || []
|
||||
return events.length ? events[events.length - 1][0] : null
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
||||
describe('查询配置面板:加载不回写、编辑才回写', () => {
|
||||
it('仅加载(schema 换新对象)不回写草稿', async () => {
|
||||
const wrapper = await mountPanel(legacySchema)
|
||||
expect(lastSchema(wrapper)).toBe(null)
|
||||
|
||||
// 模拟父级重载:同一份历史 JSON 以新引用下发(与 parseSchema 后的重载一致)
|
||||
await wrapper.setProps({ modelValue: JSON.parse(JSON.stringify(legacySchema)) })
|
||||
await nextTick()
|
||||
expect(lastSchema(wrapper)).toBe(null)
|
||||
|
||||
// 再模拟一次:父级下发的已是规范化 JSON,同样不得回写
|
||||
await wrapper.setProps({
|
||||
modelValue: {
|
||||
schemaVersion: 1,
|
||||
quick: [],
|
||||
groups: [
|
||||
{
|
||||
logic: 'and',
|
||||
conditions: [
|
||||
{ field: 'b_name', operator: 'like', component: 'input', area: 'hidden' },
|
||||
{ field: 'b_amount', operator: 'eq', component: 'number' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
await nextTick()
|
||||
expect(lastSchema(wrapper)).toBe(null)
|
||||
})
|
||||
|
||||
it('用户编辑操作符时回写,并保留未建模的 area 属性与 quick', async () => {
|
||||
const wrapper = await mountPanel({ ...legacySchema, quick: ['b_name'] })
|
||||
wrapper.vm.queryConfig = wrapper.vm.queryConfig.map((row, index) =>
|
||||
index === 0 ? { ...row, b_operator: 'eq' } : row,
|
||||
)
|
||||
await nextTick()
|
||||
|
||||
const next = lastSchema(wrapper)
|
||||
expect(next).not.toBe(null)
|
||||
expect(next.quick).toEqual(['b_name'])
|
||||
expect(next.groups[0].conditions[0]).toEqual({
|
||||
field: 'b_name',
|
||||
operator: 'eq',
|
||||
component: 'input',
|
||||
area: 'hidden',
|
||||
})
|
||||
})
|
||||
|
||||
it('改字段后不复用原字段的扩展属性', async () => {
|
||||
const wrapper = await mountPanel(legacySchema)
|
||||
wrapper.vm.queryConfig = wrapper.vm.queryConfig.map((row, index) =>
|
||||
index === 0 ? { ...row, b_field: 'b_amount', b_component: 'number', b_operator: 'eq' } : row,
|
||||
)
|
||||
await nextTick()
|
||||
|
||||
const next = lastSchema(wrapper)
|
||||
expect(next.groups[0].conditions[0]).toEqual({
|
||||
field: 'b_amount',
|
||||
operator: 'eq',
|
||||
component: 'number',
|
||||
})
|
||||
})
|
||||
|
||||
it('删除行后回写(条件为空 → groups 置空)', async () => {
|
||||
const wrapper = await mountPanel(legacySchema)
|
||||
wrapper.vm.queryConfig = []
|
||||
await nextTick()
|
||||
|
||||
const next = lastSchema(wrapper)
|
||||
expect(next.groups).toEqual([])
|
||||
expect(next.quick).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -46,10 +46,15 @@ describe('schemaModel:view/edit 配置 ↔ 编辑器草稿', () => {
|
||||
expect(rows[1].b_group_id).toBe(outer.b_id)
|
||||
expect(rows[2].b_group_id).toBe(inner.b_id)
|
||||
expect(inner.b_parent_id).toBe(outer.b_id)
|
||||
// 分组 id 即 JSON 节点 id(原数据缺 id 时按先序补齐)
|
||||
expect(outer.b_id).toBe('group1')
|
||||
expect(inner.b_id).toBe('group2')
|
||||
|
||||
const back = editorToSchema('view', rows, groups, schema)
|
||||
const outerNode = back.columns.find((n) => n.type === 'group')
|
||||
expect(outerNode.title).toBe('基本信息')
|
||||
expect(outerNode.id).toBe('group1')
|
||||
expect(outerNode.children[1].id).toBe('group2')
|
||||
expect(outerNode.children.map((n) => n.field ?? n.title)).toEqual(['age', '扩展'])
|
||||
// 列宽等已知属性保留
|
||||
expect(back.columns.find((n) => n.field === 'name').width).toBe(120)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 界面配置 JSON 公共工具测试(schemaJson)。
|
||||
* 覆盖分组节点 id 的收集、取号与归一化:归一化必须是确定性纯函数(同一份 JSON 每次结果一致、
|
||||
* 可重复执行),否则加载时的「归一化后与基线比较」会把补号误判成用户改动。
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
collectGroupIds,
|
||||
nextGroupId,
|
||||
normalizeGroupIds,
|
||||
parseSchema,
|
||||
schemaToJsonText,
|
||||
} from '@/utils/schemaJson'
|
||||
|
||||
const group = (over = {}) => ({ type: 'group', title: '分组', children: [], ...over })
|
||||
|
||||
describe('collectGroupIds / nextGroupId', () => {
|
||||
it('收集分组 id 并去重(view 取 columns,edit 取 children)', () => {
|
||||
const schema = {
|
||||
schemaVersion: 1,
|
||||
columns: [group({ id: 'group1' }), group({ id: 'group1' }), group({ id: 'basic' })],
|
||||
}
|
||||
expect([...collectGroupIds('view', schema)].toSorted()).toEqual(['basic', 'group1'])
|
||||
expect(collectGroupIds('edit', schema).size).toBe(0)
|
||||
})
|
||||
|
||||
it('nextGroupId 取已用编号里最小的未用正整数', () => {
|
||||
expect(nextGroupId([])).toBe('group1')
|
||||
expect(nextGroupId(['group1', 'group3'])).toBe('group2')
|
||||
expect(nextGroupId(['group1', 'group2'])).toBe('group3')
|
||||
// 非 group{n} 的自定义 id 不占编号
|
||||
expect(nextGroupId(['basic'])).toBe('group1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('normalizeGroupIds', () => {
|
||||
it('缺 id 的分组按先序补号,嵌套分组一并补齐', () => {
|
||||
const schema = {
|
||||
schemaVersion: 1,
|
||||
children: [
|
||||
{ field: 'a' },
|
||||
group({ title: '外层', children: [group({ title: '内层' }), { field: 'b' }] }),
|
||||
group({ title: '另一个' }),
|
||||
],
|
||||
}
|
||||
const next = normalizeGroupIds('edit', schema)
|
||||
expect(next.children[0]).toEqual({ field: 'a' })
|
||||
expect(next.children[1].id).toBe('group1')
|
||||
expect(next.children[1].children[0].id).toBe('group2')
|
||||
expect(next.children[2].id).toBe('group3')
|
||||
// 原对象不被修改
|
||||
expect(schema.children[1].id).toBeUndefined()
|
||||
})
|
||||
|
||||
it('已有 id 保留、不重排:删除产生的空洞不回收', () => {
|
||||
const schema = {
|
||||
schemaVersion: 1,
|
||||
columns: [group({ id: 'group2' }), group({})],
|
||||
}
|
||||
const next = normalizeGroupIds('view', schema)
|
||||
expect(next.columns.map((n) => n.id)).toEqual(['group2', 'group1'])
|
||||
})
|
||||
|
||||
it('重复 id 的后来者重新发号,自定义 id 原样保留', () => {
|
||||
const schema = {
|
||||
schemaVersion: 1,
|
||||
columns: [group({ id: 'group1' }), group({ id: 'group1' }), group({ id: 'basic' })],
|
||||
}
|
||||
const next = normalizeGroupIds('view', schema)
|
||||
expect(next.columns.map((n) => n.id)).toEqual(['group1', 'group2', 'basic'])
|
||||
})
|
||||
|
||||
it('确定性且幂等:重复归一化结果一致,无改动时返回原对象', () => {
|
||||
const schema = { schemaVersion: 1, columns: [group({}), group({})] }
|
||||
const once = normalizeGroupIds('view', schema)
|
||||
const twice = normalizeGroupIds('view', once)
|
||||
expect(schemaToJsonText('view', once)).toBe(schemaToJsonText('view', twice))
|
||||
expect(twice).toBe(once)
|
||||
})
|
||||
|
||||
it('无分组节点时返回原对象,query 配置不受影响', () => {
|
||||
const view = { schemaVersion: 1, columns: [{ field: 'a' }] }
|
||||
expect(normalizeGroupIds('view', view)).toBe(view)
|
||||
const query = { schemaVersion: 1, quick: [], groups: [{ logic: 'and', conditions: [] }] }
|
||||
expect(normalizeGroupIds('query', query)).toBe(query)
|
||||
})
|
||||
|
||||
it('解析库中 JSON 后可归一化(缺 columns 的畸形数据不报错)', () => {
|
||||
expect(() => normalizeGroupIds('view', parseSchema('view', '{bad json'))).not.toThrow()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user