import type { FormulaBindingCandidate } from '../../src/domain/formula-mapping';
|
|
import { DOMWrapper, mount } from '@vue/test-utils';
|
|
import Antd from 'ant-design-vue';
|
import { describe, expect, it } from 'vitest';
|
|
import FormulaBindingPanel from '../../src/components/FormulaBindingPanel.vue';
|
|
const candidates: Array<FormulaBindingCandidate & { label: string }> = [
|
{
|
id: 'amount',
|
label: '样品量',
|
controlRole: 'PRIMARY',
|
status: 'ACTIVE',
|
fieldDataType: 'DECIMAL',
|
readSource: 'NONE',
|
writeTarget: 'ELN_RECORD',
|
batchMode: 'RECORD_PRIVATE',
|
},
|
{
|
id: 'result',
|
label: '浓度',
|
controlRole: 'PRIMARY',
|
status: 'ACTIVE',
|
fieldDataType: 'DECIMAL',
|
readSource: 'NONE',
|
writeTarget: 'ELN_RECORD',
|
batchMode: 'RECORD_PRIVATE',
|
},
|
{
|
id: 'reference',
|
label: '引用',
|
controlRole: 'REFERENCE',
|
status: 'ACTIVE',
|
fieldDataType: 'DECIMAL',
|
readSource: 'NONE',
|
writeTarget: 'ELN_RECORD',
|
batchMode: 'RECORD_PRIVATE',
|
},
|
];
|
|
function mountPanel() {
|
return mount(FormulaBindingPanel, {
|
props: {
|
candidates,
|
versions: [
|
{
|
id: 'current',
|
formulaCode: 'density',
|
formulaName: '浓度',
|
formulaEnabled: true,
|
isCurrent: true,
|
status: 'PUBLISHED',
|
resultType: 'DECIMAL',
|
slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
|
},
|
{
|
id: 'pre',
|
formulaCode: 'density',
|
formulaName: '浓度预发布',
|
formulaEnabled: true,
|
isCurrent: false,
|
status: 'PRE_RELEASE',
|
resultType: 'DECIMAL',
|
slots: [],
|
},
|
{
|
id: 'historic',
|
formulaCode: 'density',
|
formulaName: '浓度旧版',
|
formulaEnabled: true,
|
isCurrent: false,
|
status: 'PUBLISHED',
|
resultType: 'DECIMAL',
|
slots: [],
|
},
|
],
|
},
|
global: { plugins: [Antd] },
|
});
|
}
|
|
describe('formulaBindingPanel', () => {
|
it('已有映射分段位于前面并默认选中,仅在映射大于 0 时显示数量徽标', async () => {
|
const wrapper = mountPanel();
|
const segmented = wrapper.getComponent({ name: 'ASegmented' });
|
expect(segmented.props('options').map((option: { value: string }) => option.value)).toEqual(['existing', 'create']);
|
expect(segmented.props('value')).toBe('existing');
|
expect(wrapper.find('[data-test="formula-existing"]').exists()).toBe(true);
|
expect(wrapper.getComponent({ name: 'AEmpty' }).classes()).toContain('content-empty');
|
expect(segmented.text()).toContain('已有映射');
|
expect(wrapper.find('[data-test="existing-mapping-count"]').exists()).toBe(false);
|
|
await wrapper.setProps({
|
mappings: [
|
{
|
formulaVersionId: 'current',
|
id: 'mapping',
|
operationCode: 'mapping-op',
|
parameterBindings: { amount: 'amount' },
|
resultBindingId: 'result',
|
status: 'ACTIVE',
|
version: 1,
|
},
|
],
|
});
|
expect(wrapper.get('[data-test="existing-mapping-count"]').text()).toBe('1');
|
|
segmented.vm.$emit('update:value', 'create');
|
await wrapper.vm.$nextTick();
|
|
const versionSelect = wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' });
|
expect(versionSelect.props('options')).toEqual([
|
expect.objectContaining({ label: '浓度', value: 'current' }),
|
expect.objectContaining({ label: expect.stringContaining('预发布'), value: 'pre' }),
|
]);
|
expect(versionSelect.props('options').map((item: { value: string }) => item.value)).not.toContain('historic');
|
});
|
|
it('按槽位和结果规则过滤候选,缺少必填绑定时禁用保存', async () => {
|
const wrapper = mountPanel();
|
wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'create');
|
await wrapper.vm.$nextTick();
|
wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'current');
|
await wrapper.vm.$nextTick();
|
expect(wrapper.get('[data-test="formula-slot-amount"]').text()).toContain('样品量');
|
expect(wrapper.get('[data-test="formula-save"]').attributes('disabled')).toBeDefined();
|
expect(
|
wrapper
|
.get('[data-test="formula-slot-amount"]')
|
.getComponent({ name: 'ASelect' })
|
.props('options')
|
.map((option: { value: string }) => option.value),
|
).toContain('amount');
|
expect(
|
wrapper
|
.get('[data-test="formula-result"]')
|
.getComponent({ name: 'ASelect' })
|
.props('options')
|
.map((option: { value: string }) => option.value),
|
).toEqual(expect.arrayContaining(['amount', 'result']));
|
expect(wrapper.text()).not.toContain('引用');
|
});
|
|
it('升级已有映射时允许沿用该映射的当前结果字段', async () => {
|
const wrapper = mount(FormulaBindingPanel, {
|
props: {
|
candidates,
|
mappings: [
|
{
|
formulaVersionId: 'current',
|
id: 'mapping',
|
operationCode: 'mapping-op',
|
parameterBindings: { amount: 'amount' },
|
resultBindingId: 'result',
|
status: 'ACTIVE',
|
version: 1,
|
},
|
],
|
usedResultBindingIds: ['result'],
|
versions: [
|
{
|
id: 'current',
|
formulaCode: 'density',
|
formulaName: '浓度',
|
formulaEnabled: true,
|
isCurrent: true,
|
status: 'PUBLISHED',
|
resultType: 'DECIMAL',
|
slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
|
},
|
],
|
},
|
global: { plugins: [Antd] },
|
});
|
wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'create');
|
await wrapper.vm.$nextTick();
|
wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'current');
|
await wrapper.vm.$nextTick();
|
expect(
|
wrapper
|
.get('[data-test="formula-result"]')
|
.getComponent({ name: 'ASelect' })
|
.props('options')
|
.map((option: { value: string }) => option.value),
|
).not.toContain('result');
|
|
wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'existing');
|
await wrapper.vm.$nextTick();
|
expect(wrapper.get('[data-test="formula-existing"]').text()).toContain('浓度');
|
expect(wrapper.get('[data-test="formula-existing"]').text()).not.toContain('mapping-op');
|
await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
|
await wrapper.vm.$nextTick();
|
const upgradeAction = document.body.querySelector('[data-test="formula-upgrade"]');
|
expect(upgradeAction).not.toBeNull();
|
await new DOMWrapper(upgradeAction as Element).trigger('click');
|
|
expect(
|
wrapper
|
.get('[data-test="formula-result"]')
|
.getComponent({ name: 'ASelect' })
|
.props('options')
|
.map((option: { value: string }) => option.value),
|
).toContain('result');
|
expect(wrapper.get('[data-test="formula-save"]').text()).toContain('升级映射');
|
});
|
|
it('升级映射切换公式版本时只提交新版本的参数槽', async () => {
|
const wrapper = mount(FormulaBindingPanel, {
|
props: {
|
candidates,
|
mappings: [
|
{
|
formulaVersionId: 'current',
|
id: 'mapping',
|
operationCode: 'mapping-op',
|
parameterBindings: { amount: 'amount' },
|
resultBindingId: 'result',
|
status: 'ACTIVE',
|
version: 1,
|
},
|
],
|
versions: [
|
{
|
id: 'current',
|
formulaCode: 'density',
|
formulaName: '浓度',
|
formulaEnabled: true,
|
isCurrent: true,
|
status: 'PUBLISHED',
|
resultType: 'DECIMAL',
|
slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
|
},
|
{
|
id: 'pre',
|
formulaCode: 'density',
|
formulaName: '浓度预发布',
|
formulaEnabled: true,
|
isCurrent: false,
|
status: 'PRE_RELEASE',
|
resultType: 'DECIMAL',
|
slots: [{ code: 'volume', name: '体积', required: true, type: 'DECIMAL' }],
|
},
|
],
|
},
|
global: { plugins: [Antd] },
|
});
|
wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'existing');
|
await wrapper.vm.$nextTick();
|
await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
|
await wrapper.vm.$nextTick();
|
await new DOMWrapper(document.body.querySelector('[data-test="formula-upgrade"]') as Element).trigger('click');
|
|
wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'pre');
|
await wrapper.vm.$nextTick();
|
wrapper.get('[data-test="formula-slot-volume"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'amount');
|
await wrapper.vm.$nextTick();
|
await wrapper.get('[data-test="formula-save"]').trigger('click');
|
|
expect(wrapper.emitted('upgrade')).toEqual([['mapping', { formulaVersionId: 'pre', parameterBindings: { volume: 'amount' }, resultBindingId: 'result' }]]);
|
});
|
|
it('离开升级流程后再进入新建映射时清空升级状态', async () => {
|
const wrapper = mount(FormulaBindingPanel, {
|
props: {
|
candidates,
|
mappings: [
|
{
|
formulaVersionId: 'current',
|
id: 'mapping',
|
operationCode: 'mapping-op',
|
parameterBindings: { amount: 'amount' },
|
resultBindingId: 'result',
|
status: 'ACTIVE',
|
version: 1,
|
},
|
],
|
versions: [
|
{
|
id: 'current',
|
formulaCode: 'density',
|
formulaName: '浓度',
|
formulaEnabled: true,
|
isCurrent: true,
|
status: 'PUBLISHED',
|
resultType: 'DECIMAL',
|
slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
|
},
|
],
|
},
|
global: { plugins: [Antd] },
|
});
|
const segmented = wrapper.getComponent({ name: 'ASegmented' });
|
segmented.vm.$emit('update:value', 'existing');
|
await wrapper.vm.$nextTick();
|
await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
|
await wrapper.vm.$nextTick();
|
const upgradeActions = document.body.querySelectorAll('[data-test="formula-upgrade"]');
|
await new DOMWrapper(upgradeActions[upgradeActions.length - 1] as Element).trigger('click');
|
expect(wrapper.get('[data-test="formula-save"]').text()).toContain('升级映射');
|
|
segmented.vm.$emit('update:value', 'existing');
|
await wrapper.vm.$nextTick();
|
segmented.vm.$emit('update:value', 'create');
|
await wrapper.vm.$nextTick();
|
|
expect(wrapper.text()).not.toContain('正在升级');
|
expect(wrapper.get('[data-test="formula-save"]').text()).toContain('保存映射');
|
expect(wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).props('value')).toBeUndefined();
|
});
|
});
|