import { readFileSync } from 'node:fs';
|
import { resolve } from 'node:path';
|
|
import { mount } from '@vue/test-utils';
|
import Antd, { DatePicker, Select, Tooltip } from 'ant-design-vue';
|
import { describe, expect, it, vi } from 'vitest';
|
|
import FieldDraftList from '../../src/components/FieldDraftList.vue';
|
|
const styles = readFileSync(resolve(process.cwd(), 'src/styles.css'), 'utf8');
|
|
describe('fieldDraftList', () => {
|
it('filters fields by name or code from the parent toolbar after input settles', async () => {
|
vi.useFakeTimers();
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
disabled: false,
|
errors: {},
|
fields: [
|
{
|
alias: '供试品名称',
|
tag: 'eln.field.sample_name',
|
type: 'text',
|
options: [],
|
draftValue: '',
|
documentValue: '',
|
currentValue: '',
|
internalId: '1',
|
},
|
{ alias: '批号', tag: 'eln.field.batch_number', type: 'text', options: [], draftValue: '', documentValue: '', currentValue: '', internalId: '2' },
|
{
|
alias: '生产日期',
|
tag: 'eln.field.production_date',
|
type: 'date',
|
options: [],
|
draftValue: '',
|
documentValue: '',
|
currentValue: '',
|
internalId: '3',
|
},
|
],
|
},
|
});
|
|
expect(wrapper.find('[data-test="field-toolbar"]').exists()).toBe(false);
|
expect(styles).toMatch(/\.field-list\s*\{[^}]*margin:\s*0;/s);
|
expect(styles).toMatch(/\.field-list-compact\s*\{[^}]*margin:\s*0;/s);
|
await vi.advanceTimersByTimeAsync(300);
|
await wrapper.setProps({ filterInput: '批号' });
|
await vi.advanceTimersByTimeAsync(299);
|
expect(wrapper.findAll('.field-row')).toHaveLength(3);
|
await vi.advanceTimersByTimeAsync(1);
|
expect(wrapper.findAll('.field-row')).toHaveLength(1);
|
expect(wrapper.text()).toContain('批号');
|
|
await wrapper.setProps({ filterInput: 'production_date' });
|
await vi.advanceTimersByTimeAsync(300);
|
expect(wrapper.findAll('.field-row')).toHaveLength(1);
|
expect(wrapper.text()).toContain('生产日期');
|
|
await wrapper.setProps({ filterInput: '' });
|
await vi.advanceTimersByTimeAsync(300);
|
expect(wrapper.findAll('.field-row')).toHaveLength(3);
|
vi.useRealTimers();
|
});
|
|
it('renders five field editors and emits draft updates', async () => {
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
disabled: false,
|
errors: {},
|
fields: [
|
{ alias: '文本', tag: 'eln.field.text', type: 'text', options: [], draftValue: '', documentValue: '', currentValue: '', internalId: '1' },
|
{ alias: '多行', tag: 'eln.field.multi', type: 'multiline', options: [], draftValue: '', documentValue: '', currentValue: '', internalId: '2' },
|
{
|
alias: '选择',
|
tag: 'eln.field.select',
|
type: 'select',
|
options: [{ display: '合格', value: 'ok' }],
|
draftValue: '',
|
documentValue: '',
|
currentValue: '',
|
internalId: '3',
|
},
|
{
|
alias: '复选',
|
tag: 'eln.field.check',
|
type: 'checkbox',
|
options: [],
|
draftValue: false,
|
documentValue: false,
|
currentValue: false,
|
internalId: '4',
|
},
|
{ alias: '日期', tag: 'eln.field.date', type: 'date', options: [], draftValue: '', documentValue: '', currentValue: '', internalId: '5' },
|
],
|
},
|
});
|
const rows = wrapper.findAll('.field-row');
|
expect(rows).toHaveLength(5);
|
expect(rows[0]?.get('input').attributes('placeholder')).toBe('请输入');
|
expect(rows[1]?.get('textarea').attributes('placeholder')).toBe('请输入');
|
expect(rows[2]?.getComponent(Select).props('placeholder')).toBe('请选择');
|
expect(rows[2]?.getComponent(Select).props('value')).toBeUndefined();
|
expect(rows[4]?.getComponent(DatePicker).props('placeholder')).toBe('请选择日期');
|
expect(wrapper.text()).toContain('复选');
|
});
|
|
it('renders reference controls as readonly even when the document is editable', () => {
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
disabled: false,
|
errors: {},
|
fields: [
|
{
|
alias: '主字段',
|
tag: 'eln.field.name',
|
type: 'text',
|
options: [],
|
draftValue: 'main',
|
documentValue: 'main',
|
currentValue: 'main',
|
internalId: '1',
|
},
|
{
|
alias: '引用字段',
|
tag: 'eln.ref.name.instance_1',
|
type: 'text',
|
options: [],
|
draftValue: 'reference',
|
documentValue: 'reference',
|
currentValue: 'reference',
|
internalId: '2',
|
},
|
],
|
},
|
});
|
|
const fieldInputs = wrapper.findAll('.field-row input');
|
expect(fieldInputs.at(0)?.attributes('disabled')).toBeUndefined();
|
expect(fieldInputs.at(1)?.attributes('disabled')).toBeDefined();
|
});
|
|
it('labels and disables a readonly cross-template primary field', () => {
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
disabled: false,
|
errors: {},
|
fields: [{
|
alias: '源检验结果', currentValue: '合格', documentValue: '合格', draftValue: '合格',
|
internalId: 'cross-1', options: [], readOnly: true, tag: 'eln.field.source_result',
|
type: 'text', valueSource: 'CROSS_TEMPLATE',
|
}],
|
},
|
});
|
|
expect(wrapper.get('[data-test="cross-template-value-source"]').text()).toBe('跨模板字段值');
|
expect(wrapper.get('input').attributes('disabled')).toBeDefined();
|
});
|
|
it('keeps datetime fields distinct from date-only fields', () => {
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
disabled: false,
|
errors: {},
|
fields: [
|
{
|
alias: '日期',
|
tag: 'eln.field.date',
|
type: 'date',
|
options: [],
|
draftValue: '2026-08-13',
|
documentValue: '2026-08-13',
|
currentValue: '2026-08-13',
|
internalId: '1',
|
dateFormat: 'yyyy-MM-dd',
|
},
|
{
|
alias: '检验时间',
|
tag: 'eln.field.tested_at',
|
type: 'date',
|
options: [],
|
draftValue: '2026-08-13 09:10:11',
|
documentValue: '2026-08-13 09:10:11',
|
currentValue: '2026-08-13 09:10:11',
|
internalId: '2',
|
dateFormat: 'yyyy年MM月dd日 HH:mm:ss',
|
},
|
],
|
},
|
});
|
|
const pickers = wrapper.findAllComponents(DatePicker);
|
expect(pickers).toHaveLength(2);
|
expect(pickers[0]?.props('valueFormat')).toBe('YYYY-MM-DD');
|
expect(pickers[0]?.props('showTime')).toBe(false);
|
expect(pickers[0]?.props('placeholder')).toBe('请选择日期');
|
expect(pickers[1]?.props('valueFormat')).toBe('YYYY-MM-DD HH:mm:ss');
|
expect(pickers[1]?.props('showTime')).toEqual({ format: 'HH:mm:ss' });
|
expect(pickers[1]?.props('placeholder')).toBe('请选择日期时间');
|
});
|
|
it('locates a focused field and emits either conflict resolution', async () => {
|
const wrapper = mount(FieldDraftList, {
|
global: { plugins: [Antd] },
|
props: {
|
conflicts: {
|
'eln.field.result': { baseValue: '原值', documentValue: '文档值', draftValue: '草稿值' },
|
},
|
disabled: false,
|
errors: {},
|
fields: [
|
{
|
alias: '结果',
|
tag: 'eln.field.result',
|
type: 'text',
|
options: [],
|
draftValue: '草稿值',
|
documentValue: '文档值',
|
currentValue: '文档值',
|
internalId: '1_2',
|
},
|
],
|
focusedTag: 'eln.field.result',
|
},
|
});
|
|
expect(wrapper.get('[data-field-tag="eln.field.result"]').classes()).toContain('field-row-focused');
|
expect(styles).toMatch(/\.field-list\s*\{[^}]*width:\s*100%;[^}]*padding-inline:\s*0;/s);
|
expect(styles).toMatch(/\.plugin-scroll-region\s*\{[^}]*padding:\s*12px 0;/s);
|
expect(styles).toMatch(/\.field-row\s*\{[^}]*width:\s*100%;[^}]*padding:\s*8px 12px;[^}]*margin:\s*0;/s);
|
expect(styles).toMatch(/\.field-row:hover\s*\{[^}]*background:\s*#f5f9ff;/s);
|
expect(styles).toMatch(/\.field-row\.field-row-focused\s*\{[^}]*background:\s*#e8f3ff;/s);
|
expect(styles).not.toMatch(/\.field-row(?:\:hover|-focused)\s*\{[^}]*border-radius:/s);
|
expect(styles).not.toMatch(/\.field-row-focused\s*\{[^}]*border-left/s);
|
expect(styles).toMatch(/\.field-label \.ant-btn\s*\{[^}]*color:\s*#d9d9d9;/s);
|
expect(styles).toMatch(/\.field-row:hover \.field-label \.ant-btn\s*\{[^}]*color:\s*#1f1f1f;/s);
|
expect(wrapper.getComponent(Tooltip).props('placement')).toBe('topRight');
|
expect(wrapper.findAll('.field-conflict-value')).toHaveLength(2);
|
expect(wrapper.get('.field-conflict .ant-space').classes()).not.toContain('field-conflict-value');
|
expect(wrapper.text()).toContain('文档值');
|
expect(wrapper.text()).toContain('草稿值');
|
await wrapper.get('[aria-label="在文档中定位 结果"]').trigger('click');
|
await wrapper.get('[data-resolution="document"]').trigger('click');
|
await wrapper.get('[data-resolution="draft"]').trigger('click');
|
|
expect(wrapper.emitted('locate')).toEqual([['eln.field.result']]);
|
expect(wrapper.emitted('resolve')).toEqual([
|
['eln.field.result', 'document'],
|
['eln.field.result', 'draft'],
|
]);
|
});
|
});
|