import { createPinia, setActivePinia } from 'pinia';
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
import { useFillerStore } from '../../src/stores/record-filler';
|
|
describe('filler store', () => {
|
beforeEach(() => setActivePinia(createPinia()));
|
|
it('keeps failed drafts and commits successful fields', () => {
|
const store = useFillerStore();
|
store.fields = [
|
{ alias: 'A', tag: 'eln.field.a', internalId: 'a', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: 'new' },
|
{ alias: 'B', tag: 'eln.field.b', internalId: 'b', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: 'bad' },
|
];
|
store.applyResults([
|
{ tag: 'eln.field.a', ok: true },
|
{ tag: 'eln.field.b', ok: false, error: '失败' },
|
]);
|
expect(store.fields[0]?.documentValue).toBe('new');
|
expect(store.fields[1]?.documentValue).toBe('');
|
expect(store.fieldErrors).toEqual({ 'eln.field.b': '失败' });
|
});
|
|
it('synchronizes primary changes to matching reference controls but rejects direct reference edits', () => {
|
const store = useFillerStore();
|
store.fields = [
|
{ alias: '主字段', tag: 'eln.field.name', internalId: 'a', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: '' },
|
{ alias: '引用字段', tag: 'eln.ref.name.instance_1', internalId: 'b', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: '' },
|
];
|
|
store.setDraft('eln.field.name', '新值');
|
store.setDraft('eln.ref.name.instance_1', '越权值');
|
|
expect(store.fields.map((field) => field.draftValue)).toEqual(['新值', '新值']);
|
});
|
|
it('rejects ordinary drafts for readonly cross-template primary fields', () => {
|
const store = useFillerStore();
|
store.fields = [{
|
alias: '源检验结果', currentValue: '合格', documentValue: '合格', draftValue: '合格',
|
internalId: 'cross-1', options: [], readOnly: true, tag: 'eln.field.source_result',
|
type: 'text', valueSource: 'CROSS_TEMPLATE',
|
}];
|
|
store.setDraft('eln.field.source_result', '人工覆盖');
|
|
expect(store.fields[0]?.draftValue).toBe('合格');
|
expect(store.formulaResultsStale).toBe(false);
|
});
|
|
it('synchronizes dotted primary field codes to matching references', () => {
|
const store = useFillerStore();
|
store.fields = [
|
{ alias: '检验结果', tag: 'eln.field.inspection.result', internalId: 'a', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: '' },
|
{ alias: '检验结果引用', tag: 'eln.ref.inspection.result.instance_1', internalId: 'b', type: 'text', options: [], currentValue: '', documentValue: '', draftValue: '' },
|
];
|
|
store.setDraft('eln.field.inspection.result', '合格');
|
|
expect(store.fields.map((field) => field.draftValue)).toEqual(['合格', '合格']);
|
});
|
|
it('tracks three-way document conflicts and resolves the primary field with its references', () => {
|
const store = useFillerStore();
|
store.fields = [
|
{ alias: '主字段', tag: 'eln.field.name', internalId: 'a', type: 'text', options: [], currentValue: '原值', documentValue: '原值', draftValue: '侧栏值' },
|
{ alias: '引用字段', tag: 'eln.ref.name.instance_1', internalId: 'b', type: 'text', options: [], currentValue: '原值', documentValue: '原值', draftValue: '侧栏值' },
|
];
|
|
store.syncDocumentField('eln.field.name', '文档值');
|
|
expect(store.conflicts['eln.field.name']).toEqual({
|
baseValue: '原值', documentValue: '文档值', draftValue: '侧栏值',
|
});
|
store.resolveConflict('eln.field.name', 'document');
|
expect(store.conflicts).toEqual({});
|
expect(store.fields.map((field) => field.draftValue)).toEqual(['文档值', '文档值']);
|
expect(store.fields.map((field) => field.documentValue)).toEqual(['文档值', '原值']);
|
});
|
|
it('automatically absorbs uncontested document edits and can keep a conflicting draft', () => {
|
const store = useFillerStore();
|
store.fields = [
|
{ alias: '结果', tag: 'eln.field.result', internalId: 'a', type: 'text', options: [], currentValue: '原值', documentValue: '原值', draftValue: '原值' },
|
];
|
|
store.syncDocumentField('eln.field.result', '文档第一次修改');
|
expect(store.fields[0]).toMatchObject({ documentValue: '文档第一次修改', draftValue: '文档第一次修改' });
|
store.setDraft('eln.field.result', '侧栏草稿');
|
store.syncDocumentField('eln.field.result', '文档第二次修改');
|
store.resolveConflict('eln.field.result', 'draft');
|
|
expect(store.conflicts).toEqual({});
|
expect(store.fields[0]).toMatchObject({ documentValue: '文档第二次修改', draftValue: '侧栏草稿' });
|
});
|
|
it('enforces checkbox groups within one step and allows the whole group to be empty', () => {
|
const store = useFillerStore();
|
store.setStepStructure({
|
configuration: {
|
singleStep: false,
|
steps: [
|
{ id: 'step-1', name: '检验', order: 1 },
|
{ id: 'step-2', name: '复核', order: 2 },
|
],
|
},
|
controlSteps: {
|
'eln.field.failed': 'step-1',
|
'eln.field.other': 'step-1',
|
'eln.field.passed': 'step-1',
|
'eln.field.review': 'step-2',
|
'eln.field.standalone': 'step-1',
|
},
|
repeatGroupSteps: {},
|
});
|
store.fields = [
|
checkbox('eln.field.passed', false, 'inspection_result'),
|
checkbox('eln.field.failed', true, 'inspection_result'),
|
checkbox('eln.field.other', true, 'other_result'),
|
checkbox('eln.field.review', true, 'inspection_result'),
|
checkbox('eln.field.standalone', true),
|
];
|
|
store.setDraft('eln.field.passed', true);
|
expect(store.fields.map((field) => field.draftValue)).toEqual([true, false, true, true, true]);
|
expect(store.formulaResultsStale).toBe(true);
|
|
store.selectStep('step-2');
|
store.selectStep('step-1');
|
store.setDraft('eln.field.passed', false);
|
expect(store.fields.slice(0, 2).map((field) => field.draftValue)).toEqual([false, false]);
|
});
|
|
it('isolates repeated checkbox groups by runtime row', () => {
|
const store = useFillerStore();
|
store.fields = [
|
checkbox('eln.repeat.results.row-1.passed', false, 'row_result'),
|
checkbox('eln.repeat.results.row-1.failed', true, 'row_result'),
|
checkbox('eln.repeat.results.row-2.passed', false, 'row_result'),
|
checkbox('eln.repeat.results.row-2.failed', true, 'row_result'),
|
];
|
|
store.setDraft('eln.repeat.results.row-1.passed', true);
|
|
expect(store.fields.map((field) => field.draftValue)).toEqual([true, false, false, true]);
|
});
|
|
it('rejects the N+1 selection without changing existing values', () => {
|
const store = useFillerStore();
|
store.fields = [
|
checkbox('eln.field.passed', true, 'inspection_result', 0, 2),
|
checkbox('eln.field.failed', true, 'inspection_result', 0, 2),
|
checkbox('eln.field.reviewed', false, 'inspection_result', 0, 2),
|
];
|
|
store.setDraft('eln.field.reviewed', true);
|
|
expect(store.fields.map((field) => field.draftValue)).toEqual([true, true, false]);
|
expect(store.checkboxGroupNotice).toBe('选择组“inspection_result”最多选择 2 项');
|
expect(store.checkboxGroupError).toBe('');
|
});
|
|
it('allows deselection below minimum but blocks apply with a group error', () => {
|
const store = useFillerStore();
|
store.fields = [
|
checkbox('eln.field.passed', true, 'inspection_result', 1, null),
|
checkbox('eln.field.failed', false, 'inspection_result', 1, null),
|
];
|
|
store.setDraft('eln.field.passed', false);
|
|
expect(store.fields.map((field) => field.draftValue)).toEqual([false, false]);
|
expect(store.checkboxGroupError).toBe('选择组“inspection_result”至少选择 1 项');
|
});
|
|
it('refreshes checkbox group errors after accepting a conflicting document value', () => {
|
const store = useFillerStore();
|
store.fields = [
|
checkbox('eln.field.passed', true, 'inspection_result'),
|
checkbox('eln.field.failed', false, 'inspection_result'),
|
];
|
store.conflicts['eln.field.failed'] = {
|
baseValue: false,
|
documentValue: true,
|
draftValue: false,
|
};
|
|
store.resolveConflict('eln.field.failed', 'document');
|
|
expect(store.checkboxGroupError).toBe('选择组“inspection_result”最多选择 1 项');
|
});
|
});
|
|
function checkbox(
|
tag: string,
|
value: boolean,
|
checkboxGroupCode?: string,
|
checkboxGroupMinSelected = 0,
|
checkboxGroupMaxSelected: null | number = 1,
|
) {
|
return {
|
alias: tag,
|
...(checkboxGroupCode
|
? { checkboxGroupCode, checkboxGroupMaxSelected, checkboxGroupMinSelected }
|
: {}),
|
currentValue: value,
|
documentValue: value,
|
draftValue: value,
|
internalId: tag,
|
options: [],
|
tag,
|
type: 'checkbox' as const,
|
};
|
}
|