刘光辉
3 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* @vitest-environment happy-dom */
 
import { flushPromises, mount } from '@vue/test-utils';
 
import { beforeEach, describe, expect, it, vi } from 'vitest';
 
import { ElnRecordBatchParamError, resolveTestWorkItemIds } from '../batchView';
import BatchView from '../index.vue';
 
const apiMocks = vi.hoisted(() => ({ createRecordsBatch: vi.fn() }));
const onlineMocks = vi.hoisted(() => ({
  getViewParam: vi.fn(),
  openCustomView: vi.fn(),
}));
 
vi.mock('#/api/x/eln/records', () => ({ createRecordsBatch: apiMocks.createRecordsBatch }));
vi.mock('#/utils/jnpf', () => ({ onlineUtils: onlineMocks }));
 
const DOCUMENT = { fileId: 'file-1', name: 'ELN-001.docx' };
 
function created(testWorkItemId: string, existing = false) {
  return {
    created: {
      document: DOCUMENT,
      existing,
      recordId: `record-${testWorkItemId}`,
      revisionId: `revision-${testWorkItemId}`,
    },
    testWorkItemId,
    status: existing ? 'EXISTING' : 'CREATED',
  };
}
 
describe('eLN batch record view', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    onlineMocks.getViewParam.mockReturnValue(['item-1']);
    apiMocks.createRecordsBatch.mockResolvedValue({ data: { items: [created('item-1')] } });
  });
 
  it('normalizes the custom-view selection and rejects an empty selection', () => {
    expect(resolveTestWorkItemIds([' item-1 ', 'item-2', 'item-1'])).toEqual(['item-1', 'item-2']);
    expect(() => resolveTestWorkItemIds([])).toThrow(ElnRecordBatchParamError);
    expect(() => resolveTestWorkItemIds(['item-1', ' '])).toThrow(ElnRecordBatchParamError);
  });
 
  it('creates one selected item and opens its editor directly', async () => {
    const randomUUID = vi.spyOn(globalThis.crypto, 'randomUUID').mockReturnValue('00000000-0000-4000-8000-000000000001');
    const wrapper = mount(BatchView);
    await flushPromises();
 
    expect(apiMocks.createRecordsBatch).toHaveBeenCalledWith({
      testWorkItemIds: ['item-1'],
      operationCode: 'record-batch-00000000-0000-4000-8000-000000000001',
    });
    expect(onlineMocks.openCustomView).toHaveBeenCalledWith({
      page: 'x/eln/records/editor',
      params: { document: DOCUMENT, recordId: 'record-item-1', revisionId: 'revision-item-1' },
      title: '填写电子记录',
    });
    expect(wrapper.find('[data-test="batch-results"]').exists()).toBe(true);
    randomUUID.mockRestore();
  });
 
  it('shows multiple results without automatically opening any editor', async () => {
    onlineMocks.getViewParam.mockReturnValue(['item-1', 'item-2']);
    apiMocks.createRecordsBatch.mockResolvedValue({
      data: {
        items: [created('item-1'), { errorCode: 'BUSINESS_ERROR', errorMessage: '未配置模板', status: 'FAILED', testWorkItemId: 'item-2' }],
      },
    });
    const wrapper = mount(BatchView);
    await flushPromises();
 
    expect(onlineMocks.openCustomView).not.toHaveBeenCalled();
    expect(wrapper.find('[data-test="batch-results"]').text()).toContain('未配置模板');
    expect(wrapper.find('[data-test="batch-failure"]').text()).toContain('未配置模板');
  });
 
  it('opens only the selected successful result from a multi-item batch', async () => {
    onlineMocks.getViewParam.mockReturnValue(['item-1', 'item-2']);
    apiMocks.createRecordsBatch.mockResolvedValue({ data: { items: [created('item-1'), created('item-2', true)] } });
    const wrapper = mount(BatchView);
    await flushPromises();
 
    const buttons = wrapper.findAll('button');
    expect(buttons).toHaveLength(2);
    await buttons[1]!.trigger('click');
 
    expect(onlineMocks.openCustomView).toHaveBeenCalledTimes(1);
    expect(onlineMocks.openCustomView).toHaveBeenCalledWith({
      page: 'x/eln/records/editor',
      params: { document: DOCUMENT, recordId: 'record-item-2', revisionId: 'revision-item-2' },
      title: '填写电子记录',
    });
  });
 
  it('shows a clear request error without opening an editor', async () => {
    apiMocks.createRecordsBatch.mockRejectedValue(new Error('网络不可用'));
    const wrapper = mount(BatchView);
    await flushPromises();
 
    expect(wrapper.find('[data-test="batch-error"]').text()).toContain('网络不可用');
    expect(onlineMocks.openCustomView).not.toHaveBeenCalled();
  });
 
  it('shows a clear empty-selection state without sending a batch request', async () => {
    onlineMocks.getViewParam.mockReturnValue([]);
    const wrapper = mount(BatchView);
    await flushPromises();
 
    expect(wrapper.find('[data-test="batch-error"]').text()).toContain('请选择至少一个检验项');
    expect(apiMocks.createRecordsBatch).not.toHaveBeenCalled();
  });
});