刘光辉
14 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
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
116
117
118
119
120
121
122
import { afterEach, describe, expect, it, vi } from 'vitest';
 
import { applyFieldsCommand, inspectFieldsCommand } from '../../src/onlyoffice/commands';
 
function control(tag: string, kind: 'checkbox' | 'date' | 'multiline' | 'select' | 'text', initial: boolean | string) {
  let value = initial;
  const options = [
    { GetText: () => '合格', GetValue: () => 'qualified' },
    { GetText: () => '不合格', GetValue: () => 'unqualified' },
  ];
  return {
    GetTag: () => tag,
    GetAlias: () => '字段',
    GetInternalId: () => `id-${tag}`,
    GetRange: () => ({ GetText: () => (typeof value === 'boolean' ? (value ? '☒' : '☐') : value) }),
    IsCheckBox: () => kind === 'checkbox',
    IsComboBox: () => kind === 'select',
    IsDropDownList: () => false,
    IsDatePicker: () => kind === 'date',
    IsBlockLevel: () => kind === 'multiline',
    GetDropdownList: () => ({ GetElementsCount: () => options.length, GetItem: (index: number) => options[index] }),
    SetCheckBoxChecked(next: boolean) { value = next; return true; },
    SelectListItem(next: string) { value = options.find((item) => item.GetValue() === next)?.GetText() ?? ''; return true; },
    SetDate(next: Date) { value = `${next.getFullYear()}-${String(next.getMonth() + 1).padStart(2, '0')}-${String(next.getDate()).padStart(2, '0')}`; return true; },
    RemoveAllElements() { value = ''; return true; },
    AddElement(item: { text?: string }) {
      const text = item.text ?? '';
      value = kind === 'multiline' && value !== '' ? `${value}\n${text}` : `${value}${text}`;
      return true;
    },
  };
}
 
function install(controls: unknown[], changes: unknown[] = []) {
  const createParagraph = vi.fn(() => ({ text: '', AddElement(item: { text: string }) { this.text += item.text; return true; } }));
  vi.stubGlobal('Asc', { scope: { elnTemplateFillInspect: {}, elnTemplateFillChanges: changes } });
  vi.stubGlobal('Api', {
    GetDocument: () => ({ GetAllContentControls: () => controls }),
    CreateRun: () => ({ text: '', AddText(value: string) { this.text = value; return true; } }),
    CreateParagraph: createParagraph,
  });
  return { createParagraph };
}
 
function serializeCommand(command: () => string): () => string {
  return Function(`"use strict"; return (${command.toString()});`)() as () => string;
}
 
describe('ONLYOFFICE fill commands', () => {
  afterEach(() => vi.unstubAllGlobals());
 
  it('inspects typed ELN controls and ignores other tags', () => {
    install([control('eln.field.name', 'text', 'A'), control('eln.field.ok', 'checkbox', false), control('other', 'text', 'x')]);
    const result = JSON.parse(inspectFieldsCommand());
    expect(result.fields).toHaveLength(2);
    expect(result.fields[1]).toMatchObject({ tag: 'eln.field.ok', type: 'checkbox', currentValue: false });
  });
 
  it('inspects fields after ONLYOFFICE serializes the command without module closures', () => {
    install([control('eln.field.name', 'text', 'A')]);
 
    expect(JSON.parse(serializeCommand(inspectFieldsCommand)())).toMatchObject({
      ok: true,
      fields: [{ tag: 'eln.field.name', type: 'text', currentValue: 'A' }],
    });
  });
 
  it('applies text, checkbox, select and date values', () => {
    const controls = [
      control('eln.field.name', 'text', ''), control('eln.field.ok', 'checkbox', false),
      control('eln.field.result', 'select', '合格'), control('eln.field.date', 'date', '2026-08-12'),
    ];
    install(controls, [
      { tag: 'eln.field.name', type: 'text', value: '样品' }, { tag: 'eln.field.ok', type: 'checkbox', value: true },
      { tag: 'eln.field.result', type: 'select', value: 'unqualified' }, { tag: 'eln.field.date', type: 'date', value: '2026-08-13' },
    ]);
    expect(JSON.parse(applyFieldsCommand()).results).toEqual([
      { tag: 'eln.field.name', ok: true }, { tag: 'eln.field.ok', ok: true },
      { tag: 'eln.field.result', ok: true }, { tag: 'eln.field.date', ok: true },
    ]);
  });
 
  it('applies fields after ONLYOFFICE serializes the command without module closures', () => {
    const item = control('eln.field.name', 'text', '');
    install([item], [{ tag: 'eln.field.name', type: 'text', value: '样品' }]);
 
    expect(JSON.parse(serializeCommand(applyFieldsCommand)()).results).toEqual([{ tag: 'eln.field.name', ok: true }]);
    expect(item.GetRange().GetText()).toBe('样品');
  });
 
  it('rejects unknown select values without changing the field', () => {
    const item = control('eln.field.result', 'select', '合格');
    install([item], [{ tag: 'eln.field.result', type: 'select', value: 'missing' }]);
    const result = JSON.parse(applyFieldsCommand()).results[0];
    expect(result).toMatchObject({ tag: 'eln.field.result', ok: false, error: '下拉值不在文档选项中' });
    expect(item.GetRange().GetText()).toBe('合格');
  });
 
  it('writes multiline values as one paragraph per line', () => {
    const item = control('eln.field.notes', 'multiline', '');
    const { createParagraph } = install([item], [{ tag: 'eln.field.notes', type: 'multiline', value: '第一行\n第二行' }]);
 
    expect(JSON.parse(applyFieldsCommand()).results).toEqual([{ tag: 'eln.field.notes', ok: true }]);
    expect(createParagraph).toHaveBeenCalledTimes(2);
    expect(item.GetRange().GetText()).toBe('第一行\n第二行');
  });
 
  it('continues applying later fields after one field fails', () => {
    const select = control('eln.field.result', 'select', '合格');
    const text = control('eln.field.name', 'text', '');
    install([select, text], [
      { tag: 'eln.field.result', type: 'select', value: 'missing' },
      { tag: 'eln.field.name', type: 'text', value: '样品' },
    ]);
 
    expect(JSON.parse(applyFieldsCommand()).results).toEqual([
      { tag: 'eln.field.result', ok: false, error: '下拉值不在文档选项中' },
      { tag: 'eln.field.name', ok: true },
    ]);
    expect(text.GetRange().GetText()).toBe('样品');
  });
});