@elisra-devops/docgen-skins 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.github/workflows/ci.yml +18 -9
  2. package/.github/workflows/release.yml +22 -6
  3. package/Readme.md +11 -0
  4. package/bin/index.d.ts +12 -1
  5. package/bin/index.js +201 -16
  6. package/bin/index.js.map +1 -1
  7. package/bin/models/json/JSONRun.js +2 -0
  8. package/bin/models/json/JSONRun.js.map +1 -1
  9. package/bin/models/json/file/JSONFile.js.map +1 -1
  10. package/bin/models/json/paragraph/JSONParagraph.js.map +1 -1
  11. package/bin/models/json/paragraph/JSONRichTextParagraph.js.map +1 -1
  12. package/bin/models/json/paragraph/JSONTestSuiteHeaderParagraph.js +3 -0
  13. package/bin/models/json/paragraph/JSONTestSuiteHeaderParagraph.js.map +1 -1
  14. package/bin/models/json/table/JSONTable.d.ts +2 -1
  15. package/bin/models/json/table/JSONTable.js +20 -6
  16. package/bin/models/json/table/JSONTable.js.map +1 -1
  17. package/bin/models/json/table/JSONTableCell.js +2 -0
  18. package/bin/models/json/table/JSONTableCell.js.map +1 -1
  19. package/bin/models/json/table/JSONTableRow.js.map +1 -1
  20. package/bin/models/json/wordJsonModels.d.ts +5 -0
  21. package/bin/services/logger.js +17 -7
  22. package/bin/services/logger.js.map +1 -1
  23. package/bin/test/JSONFile.test.js +48 -0
  24. package/bin/test/JSONFile.test.js.map +1 -0
  25. package/bin/test/JSONRun.test.d.ts +1 -0
  26. package/bin/test/JSONRun.test.js +93 -0
  27. package/bin/test/JSONRun.test.js.map +1 -0
  28. package/bin/test/JSONTable.test.d.ts +1 -0
  29. package/bin/test/JSONTable.test.js +79 -0
  30. package/bin/test/JSONTable.test.js.map +1 -0
  31. package/bin/test/JSONTableCell.test.d.ts +1 -0
  32. package/bin/test/JSONTableCell.test.js +154 -0
  33. package/bin/test/JSONTableCell.test.js.map +1 -0
  34. package/bin/test/JSONTableRow.test.d.ts +1 -0
  35. package/bin/test/JSONTableRow.test.js +40 -0
  36. package/bin/test/JSONTableRow.test.js.map +1 -0
  37. package/bin/test/JSONTestSuiteHeaderParagraph.test.d.ts +1 -0
  38. package/bin/test/JSONTestSuiteHeaderParagraph.test.js +57 -0
  39. package/bin/test/JSONTestSuiteHeaderParagraph.test.js.map +1 -0
  40. package/bin/test/SkinsEdgeCases.test.d.ts +1 -0
  41. package/bin/test/SkinsEdgeCases.test.js +399 -0
  42. package/bin/test/SkinsEdgeCases.test.js.map +1 -0
  43. package/bin/test/integration/skins.integration.test.d.ts +1 -0
  44. package/bin/test/integration/skins.integration.test.js +533 -0
  45. package/bin/test/integration/skins.integration.test.js.map +1 -0
  46. package/package.json +5 -5
  47. package/src/index.ts +247 -10
  48. package/src/models/json/JSONRun.ts +2 -0
  49. package/src/models/json/paragraph/JSONTestSuiteHeaderParagraph.ts +4 -0
  50. package/src/models/json/table/JSONTable.ts +19 -3
  51. package/src/models/json/table/JSONTableCell.ts +1 -0
  52. package/src/models/json/wordJsonModels.ts +5 -0
  53. package/src/test/JSONFile.test.ts +59 -0
  54. package/src/test/JSONRun.test.ts +118 -0
  55. package/src/test/JSONTable.test.ts +126 -0
  56. package/src/test/JSONTableCell.test.ts +181 -0
  57. package/src/test/JSONTableRow.test.ts +42 -0
  58. package/src/test/JSONTestSuiteHeaderParagraph.test.ts +64 -0
  59. package/src/test/SkinsEdgeCases.test.ts +530 -0
  60. package/src/test/integration/skins.integration.test.ts +660 -0
  61. package/tsconfig.json +2 -2
  62. package/bin/test/skins.test.js +0 -126
  63. package/bin/test/skins.test.js.map +0 -1
  64. package/src/test/skins.test.ts +0 -189
  65. /package/bin/test/{skins.test.d.ts → JSONFile.test.d.ts} +0 -0
@@ -0,0 +1,660 @@
1
+ import { writeFileSync } from 'fs';
2
+ import Skins from '../../index';
3
+
4
+ jest.mock('../../services/logger', () => ({
5
+ __esModule: true,
6
+ default: {
7
+ debug: jest.fn(),
8
+ info: jest.fn(),
9
+ warn: jest.fn(),
10
+ error: jest.fn(),
11
+ silly: jest.fn(),
12
+ },
13
+ }));
14
+
15
+ jest.setTimeout(300000);
16
+ const styles = {
17
+ isBold: false,
18
+ IsItalic: false,
19
+ IsUnderline: false,
20
+ Size: 10,
21
+ Uri: null,
22
+ Font: 'New Times Roman',
23
+ InsertLineBreak: true,
24
+ InsertSpace: true,
25
+ };
26
+
27
+ const headerStyles = {
28
+ isBold: true,
29
+ IsItalic: false,
30
+ IsUnderline: false,
31
+ Size: 12,
32
+ Uri: null,
33
+ Font: 'Arial',
34
+ InsertLineBreak: false,
35
+ InsertSpace: true,
36
+ };
37
+
38
+ // Minimal inline fixtures to replace removed JSON mock-data and snapshot files
39
+ const flatQueryData = [
40
+ {
41
+ url: 'http://example.com/wi/1',
42
+ level: 0,
43
+ Source: 1,
44
+ fields: [
45
+ { name: 'ID', value: 1, width: '50%' },
46
+ { name: 'Title', value: 'First item', width: '50%' },
47
+ ],
48
+ },
49
+ {
50
+ url: 'http://example.com/wi/2',
51
+ level: 0,
52
+ Source: 2,
53
+ fields: [
54
+ { name: 'ID', value: 2, width: '50%' },
55
+ { name: 'Title', value: 'Second item', width: '50%' },
56
+ ],
57
+ },
58
+ ];
59
+
60
+ const treeQueryData = [
61
+ {
62
+ url: 'http://example.com/wi/10',
63
+ level: 0,
64
+ Source: 10,
65
+ fields: [
66
+ { name: 'ID', value: 10 },
67
+ { name: 'Title', value: 'Parent item' },
68
+ ],
69
+ },
70
+ {
71
+ url: 'http://example.com/wi/11',
72
+ level: 1,
73
+ Source: 11,
74
+ fields: [
75
+ { name: 'ID', value: 11 },
76
+ { name: 'Title', value: 'Child item' },
77
+ ],
78
+ },
79
+ ];
80
+
81
+ const simpleTestSuites = [
82
+ {
83
+ suiteSkinData: {
84
+ fields: [
85
+ { name: 'Title', value: 'Suite 1' },
86
+ { name: 'ID', value: 1 },
87
+ ],
88
+ level: 1,
89
+ },
90
+ testCases: [
91
+ {
92
+ id: 101,
93
+ testCaseHeaderSkinData: {
94
+ fields: [
95
+ { name: 'Title', value: 'TC-1' },
96
+ { name: 'ID', value: 101 },
97
+ { name: 'Description: ', value: '<p>Simple description</p>' },
98
+ ],
99
+ level: 1,
100
+ },
101
+ testCaseRequirements: [],
102
+ testCaseLinkedMom: [],
103
+ testCaseBugs: [],
104
+ testCaseStepsSkinData: [],
105
+ testCaseAttachments: [],
106
+ },
107
+ ],
108
+ },
109
+ ];
110
+
111
+ const complexTestSuites = [
112
+ {
113
+ suiteSkinData: {
114
+ fields: [
115
+ { name: 'Title', value: 'Complex Suite' },
116
+ { name: 'ID', value: 200 },
117
+ ],
118
+ level: 1,
119
+ },
120
+ testCases: [
121
+ {
122
+ id: 201,
123
+ testCaseHeaderSkinData: {
124
+ fields: [
125
+ { name: 'Title', value: 'TC-Complex' },
126
+ { name: 'ID', value: 201 },
127
+ { name: 'Description: ', value: '<p>Complex <b>HTML</b> description</p>' },
128
+ ],
129
+ level: 1,
130
+ },
131
+ testCaseRequirements: [
132
+ {
133
+ url: 'http://example.com/req/1',
134
+ level: 0,
135
+ Source: 1,
136
+ fields: [
137
+ { name: 'Requirement', value: 'REQ-1' },
138
+ { name: 'Title', value: 'First requirement' },
139
+ ],
140
+ },
141
+ ],
142
+ testCaseLinkedMom: [
143
+ {
144
+ url: 'http://example.com/mom/1',
145
+ level: 0,
146
+ Source: 2,
147
+ fields: [
148
+ { name: 'MOM', value: 'MOM-1' },
149
+ { name: 'Title', value: 'First MOM' },
150
+ ],
151
+ },
152
+ ],
153
+ testCaseBugs: [
154
+ {
155
+ url: 'http://example.com/bug/1',
156
+ level: 0,
157
+ Source: 3,
158
+ fields: [
159
+ { name: 'Bug', value: 'BUG-1' },
160
+ { name: 'Title', value: 'First bug' },
161
+ ],
162
+ },
163
+ ],
164
+ testCaseStepsSkinData: [
165
+ {
166
+ url: 'http://example.com/step/1',
167
+ level: 0,
168
+ Source: 4,
169
+ fields: [
170
+ { name: 'Step', value: 'Do something' },
171
+ { name: 'Expected', value: 'It works' },
172
+ ],
173
+ },
174
+ ],
175
+ testCaseAttachments: [
176
+ {
177
+ url: 'http://example.com/attach/1',
178
+ level: 0,
179
+ Source: 5,
180
+ fields: [{ name: 'Attachment', value: 'log.txt' }],
181
+ },
182
+ ],
183
+ testCaseDocAttachmentsAdoptedData: {
184
+ stepLevel: [
185
+ {
186
+ type: 'SubHeader',
187
+ field: { name: 'Title', value: 'Step Attachments' },
188
+ },
189
+ {
190
+ type: 'File',
191
+ attachmentLink: 'http://example.com/doc1.pdf',
192
+ attachmentFileName: 'doc1.pdf',
193
+ attachmentType: 'asEmbedded',
194
+ includeAttachmentContent: true,
195
+ },
196
+ ],
197
+ testCaseLevel: [
198
+ {
199
+ type: 'SubHeader',
200
+ field: { name: 'Title', value: 'Case Attachments' },
201
+ },
202
+ {
203
+ type: 'File',
204
+ attachmentLink: 'http://example.com/doc2.pdf',
205
+ attachmentFileName: 'doc2.pdf',
206
+ attachmentType: 'asEmbedded',
207
+ includeAttachmentContent: true,
208
+ },
209
+ ],
210
+ },
211
+ insertPageBreak: true,
212
+ },
213
+ ],
214
+ },
215
+ ];
216
+
217
+ const changesData = [
218
+ {
219
+ artifact: [
220
+ {
221
+ url: 'http://example.com/artifact/1',
222
+ level: 0,
223
+ Source: 1,
224
+ fields: [
225
+ { name: 'Title', value: 'Artifact 1' },
226
+ { name: 'Description: ', value: '<p>Artifact description</p>' },
227
+ ],
228
+ },
229
+ ],
230
+ artifactChanges: [
231
+ {
232
+ url: 'http://example.com/change/1',
233
+ level: 0,
234
+ Source: 2,
235
+ fields: [
236
+ { name: 'Field', value: 'Status' },
237
+ { name: 'Old', value: 'Open' },
238
+ { name: 'New', value: 'Closed' },
239
+ ],
240
+ },
241
+ ],
242
+ },
243
+ ];
244
+
245
+ const richTextTestSuites = [
246
+ {
247
+ suiteSkinData: {
248
+ fields: [
249
+ { name: 'Title', value: 'Rich Suite' },
250
+ { name: 'ID', value: 300 },
251
+ ],
252
+ level: 1,
253
+ },
254
+ testCases: [
255
+ {
256
+ id: 301,
257
+ testCaseHeaderSkinData: {
258
+ fields: [
259
+ { name: 'Title', value: 'TC-Rich' },
260
+ { name: 'ID', value: 301 },
261
+ { name: 'Description: ', value: '<p><b>Rich</b> text description</p>' },
262
+ ],
263
+ level: 1,
264
+ },
265
+ testCaseRequirements: [],
266
+ testCaseLinkedMom: [],
267
+ testCaseBugs: [],
268
+ testCaseStepsSkinData: [],
269
+ testCaseAttachments: [],
270
+ },
271
+ ],
272
+ },
273
+ ];
274
+
275
+ describe('Generate json skins from queries - tests', () => {
276
+ test('generate table skin - flat query', async () => {
277
+ let skins = new Skins('json', 'c:\test.dotx');
278
+ const result = await skins.addNewContentToDocumentSkin(
279
+ 'test',
280
+ skins.SKIN_TYPE_TABLE,
281
+ flatQueryData as any,
282
+ headerStyles,
283
+ styles,
284
+ 4
285
+ );
286
+
287
+ expect(Array.isArray(result)).toBe(true);
288
+ expect(result.length).toBeGreaterThan(0);
289
+ const table = result[0] as any;
290
+ expect(table.type).toBe('table');
291
+ expect(Array.isArray(table.Rows)).toBe(true);
292
+ expect(table.Rows.length).toBeGreaterThanOrEqual(3); // grouped/header + header + data
293
+ });
294
+ test('generate table skin - tree query', async () => {
295
+ let skins = new Skins('json', 'c:\test.dotx');
296
+ const result = await skins.addNewContentToDocumentSkin(
297
+ 'test',
298
+ skins.SKIN_TYPE_TABLE,
299
+ treeQueryData as any,
300
+ headerStyles,
301
+ styles,
302
+ 4
303
+ );
304
+
305
+ const table = result[0] as any;
306
+ expect(table.type).toBe('table');
307
+ expect(table.headingLevel).toBe(4);
308
+ expect(table.Rows.length).toBeGreaterThanOrEqual(3);
309
+ });
310
+ test('generate paragraph skin - flat query', async () => {
311
+ let skins = new Skins('json', 'c:\test.dotx');
312
+ const result = await skins.addNewContentToDocumentSkin(
313
+ 'test',
314
+ skins.SKIN_TYPE_PARAGRAPH,
315
+ flatQueryData as any,
316
+ headerStyles,
317
+ styles,
318
+ 4
319
+ );
320
+ // writeFileSync(
321
+ // "flat-query-paragraph-snapshot.json",
322
+ // JSON.stringify(documentSkin)
323
+ // );
324
+
325
+ expect(Array.isArray(result)).toBe(true);
326
+ expect(result.length).toBeGreaterThan(0);
327
+ result.forEach((p: any) => {
328
+ expect(p.type).toBe('paragraph');
329
+ });
330
+ });
331
+ test('generate paragraph skin - tree query', async () => {
332
+ let skins = new Skins('json', 'c:\test.dotx');
333
+ const result = await skins.addNewContentToDocumentSkin(
334
+ 'test',
335
+ skins.SKIN_TYPE_PARAGRAPH,
336
+ treeQueryData as any,
337
+ headerStyles,
338
+ styles,
339
+ 4
340
+ );
341
+ // writeFileSync("tree-query-data.json", JSON.stringify(documentSkin));
342
+
343
+ expect(Array.isArray(result)).toBe(true);
344
+ expect(result.length).toBeGreaterThan(0);
345
+ result.forEach((p: any) => {
346
+ expect(p.type).toBe('paragraph');
347
+ });
348
+ });
349
+ });
350
+ describe('Generate json skins from testData - tests', () => {
351
+ test('generate std skin - testData', async () => {
352
+ let skins = new Skins('json', 'c\\test\\test.dotx');
353
+ const result = await skins.addNewContentToDocumentSkin(
354
+ 'system-capabilities',
355
+ skins.SKIN_TYPE_TEST_PLAN,
356
+ simpleTestSuites as any,
357
+ headerStyles,
358
+ styles,
359
+ 4
360
+ );
361
+
362
+ expect(Array.isArray(result)).toBe(true);
363
+ expect(result.length).toBeGreaterThan(0);
364
+ // Expect suite header + test case header + description title + rich text/html
365
+ const hasParagraph = result.some((x: any) => x.type === 'paragraph');
366
+ expect(hasParagraph).toBe(true);
367
+ });
368
+ test('generate std skin - complex testData', async () => {
369
+ let skins = new Skins('json', 'C\\docgen\\documents\\181020205911\\test.dotx');
370
+ const result = await skins.addNewContentToDocumentSkin(
371
+ 'system-capabilities',
372
+ skins.SKIN_TYPE_TEST_PLAN,
373
+ complexTestSuites as any,
374
+ headerStyles,
375
+ styles,
376
+ 4
377
+ );
378
+
379
+ expect(Array.isArray(result)).toBe(true);
380
+ expect(result.length).toBeGreaterThan(0);
381
+ const hasPageBreak = result.some(
382
+ (x: any) => x.type === 'paragraph' && x.runs?.some((r: any) => r.InsertPageBreak)
383
+ );
384
+ expect(hasPageBreak).toBe(true);
385
+ });
386
+ test('generate test-std skin alias', async () => {
387
+ let skins = new Skins('json', 'c\\test\\test.dotx');
388
+ const result = await skins.addNewContentToDocumentSkin(
389
+ 'system-capabilities',
390
+ skins.SKIN_TYPE_TEST_STD,
391
+ simpleTestSuites as any,
392
+ headerStyles,
393
+ styles,
394
+ 4
395
+ );
396
+
397
+ expect(Array.isArray(result)).toBe(true);
398
+ expect(result.length).toBeGreaterThan(0);
399
+ });
400
+ test('generate test-stp skin alias', async () => {
401
+ let skins = new Skins('json', 'c\\test\\test.dotx');
402
+ const stpSuitesWithPhase = [
403
+ {
404
+ suiteSkinData: {
405
+ fields: [
406
+ { name: 'Title', value: 'Suite 1' },
407
+ { name: 'ID', value: 1 },
408
+ ],
409
+ level: 1,
410
+ },
411
+ testCases: [
412
+ {
413
+ id: 101,
414
+ testCaseHeaderSkinData: {
415
+ fields: [
416
+ { name: 'Title', value: 'TC-1' },
417
+ { name: 'ID', value: 101 },
418
+ { name: 'Description: ', value: '<p>Simple description</p>' },
419
+ { name: 'Test Phase', value: 'Qualification' },
420
+ ],
421
+ level: 1,
422
+ },
423
+ testCaseRequirements: [],
424
+ testCaseLinkedMom: [],
425
+ testCaseBugs: [],
426
+ testCaseStepsSkinData: [],
427
+ testCaseAttachments: [],
428
+ },
429
+ ],
430
+ },
431
+ ];
432
+ const result = await skins.addNewContentToDocumentSkin(
433
+ 'system-capabilities',
434
+ skins.SKIN_TYPE_TEST_STP,
435
+ stpSuitesWithPhase as any,
436
+ headerStyles,
437
+ styles,
438
+ 4
439
+ );
440
+
441
+ expect(Array.isArray(result)).toBe(true);
442
+ expect(result.length).toBeGreaterThan(0);
443
+ const hasPhaseParagraph = result.some((paragraph: any) => {
444
+ if (paragraph?.type !== 'paragraph' || !Array.isArray(paragraph?.runs)) return false;
445
+ const text = paragraph.runs.map((run: any) => run?.text || '').join('');
446
+ return text.includes('Test Phase: Qualification');
447
+ });
448
+ expect(hasPhaseParagraph).toBe(true);
449
+ });
450
+ test('generate test-stp skin alias with +1 heading depth vs std', async () => {
451
+ let skins = new Skins('json', 'c\\test\\test.dotx');
452
+ const suites = [
453
+ {
454
+ suiteSkinData: {
455
+ fields: [
456
+ { name: 'Title', value: 'Suite H' },
457
+ { name: 'ID', value: 11 },
458
+ ],
459
+ level: 1,
460
+ },
461
+ testCases: [
462
+ {
463
+ id: 111,
464
+ testCaseHeaderSkinData: {
465
+ fields: [
466
+ { name: 'Title', value: 'TC-H' },
467
+ { name: 'ID', value: 111 },
468
+ { name: 'Description: ', value: '<p>Simple description</p>' },
469
+ ],
470
+ level: 2,
471
+ },
472
+ testCaseRequirements: [],
473
+ testCaseLinkedMom: [],
474
+ testCaseBugs: [],
475
+ testCaseStepsSkinData: [],
476
+ testCaseAttachments: [],
477
+ },
478
+ ],
479
+ },
480
+ ];
481
+
482
+ const stdResult = await skins.addNewContentToDocumentSkin(
483
+ 'system-capabilities',
484
+ skins.SKIN_TYPE_TEST_STD,
485
+ suites as any,
486
+ headerStyles,
487
+ styles,
488
+ 4
489
+ );
490
+ const stpResult = await skins.addNewContentToDocumentSkin(
491
+ 'system-capabilities',
492
+ skins.SKIN_TYPE_TEST_STP,
493
+ suites as any,
494
+ headerStyles,
495
+ styles,
496
+ 4
497
+ );
498
+
499
+ const getHeadingLevelByText = (items: any[], text: string) => {
500
+ const paragraph = items.find((item) => {
501
+ if (item?.type !== 'paragraph' || !Array.isArray(item?.runs)) return false;
502
+ const runText = item.runs.map((run: any) => String(run?.text || '')).join('');
503
+ return runText.includes(text) && Number.isInteger(item?.headingLevel) && item.headingLevel > 0;
504
+ });
505
+ return paragraph?.headingLevel;
506
+ };
507
+
508
+ const stdSuiteHeading = getHeadingLevelByText(stdResult as any[], 'Suite H');
509
+ const stpSuiteHeading = getHeadingLevelByText(stpResult as any[], 'Suite H');
510
+ const stdCaseHeading = getHeadingLevelByText(stdResult as any[], 'TC-H');
511
+ const stpCaseHeading = getHeadingLevelByText(stpResult as any[], 'TC-H');
512
+
513
+ expect(stpSuiteHeading).toBe(stdSuiteHeading + 1);
514
+ expect(stpCaseHeading).toBe(stdCaseHeading + 1);
515
+ });
516
+ test('generate test-str skin alias', async () => {
517
+ let skins = new Skins('json', 'c\\test\\test.dotx');
518
+ const result = await skins.addNewContentToDocumentSkin(
519
+ 'appendix-a-content-control',
520
+ skins.SKIN_TYPE_TEST_STR,
521
+ [
522
+ {
523
+ type: 'Header',
524
+ field: { name: 'Title', value: 'Section A' },
525
+ level: 1,
526
+ },
527
+ {
528
+ field: { name: 'Description', value: 'Row 1' },
529
+ },
530
+ ] as any,
531
+ headerStyles,
532
+ styles,
533
+ 4
534
+ );
535
+
536
+ expect(Array.isArray(result)).toBe(true);
537
+ expect(result.length).toBeGreaterThan(0);
538
+ });
539
+ test('generate trace table skin', async () => {
540
+ let skins = new Skins('json', 'c\\test\\test.dotx');
541
+ const traceData = {
542
+ title: {
543
+ fields: [{ name: 'Title', value: 'Trace Table' }],
544
+ level: 1,
545
+ },
546
+ adoptedData: flatQueryData,
547
+ errorMessage: null,
548
+ groupedHeader: {
549
+ leftLabel: 'Left',
550
+ rightLabel: 'Right',
551
+ },
552
+ };
553
+
554
+ const result = await skins.addNewContentToDocumentSkin(
555
+ 'system-capabilities',
556
+ skins.SKIN_TYPE_TRACE,
557
+ traceData as any,
558
+ headerStyles,
559
+ styles,
560
+ 4
561
+ );
562
+ expect(result.length).toBe(2);
563
+ expect(result[0]).toMatchObject({ type: 'paragraph' });
564
+ expect(result[1]).toMatchObject({ type: 'table' });
565
+ });
566
+ });
567
+ describe('Generate json skins svd - tests', () => {
568
+ test('generate changes between releases skin', async () => {
569
+ let skins = new Skins('json', 'c\\test\\test.dotx');
570
+ for (let i = 0; i < changesData.length; i++) {
571
+ let artifactChangesData = changesData[i];
572
+ const paragraphSkin = await skins.addNewContentToDocumentSkin(
573
+ 'change-description-content-control',
574
+ skins.SKIN_TYPE_PARAGRAPH,
575
+ artifactChangesData.artifact,
576
+ headerStyles,
577
+ styles,
578
+ 4
579
+ );
580
+
581
+ const tableSkin = await skins.addNewContentToDocumentSkin(
582
+ 'change-description-content-control',
583
+ skins.SKIN_TYPE_TABLE,
584
+ artifactChangesData.artifactChanges,
585
+ headerStyles,
586
+ styles,
587
+ 4
588
+ );
589
+ expect(paragraphSkin.length).toBeGreaterThan(0);
590
+ expect(tableSkin[0]).toMatchObject({ type: 'table' });
591
+ }
592
+ });
593
+ });
594
+ describe('Common functions - tests', () => {
595
+ test('generate richText skin', async () => {
596
+ let skins = new Skins('json', 'c\\test\\test.dotx');
597
+ const result = await skins.addNewContentToDocumentSkin(
598
+ 'system-capabilities',
599
+ skins.SKIN_TYPE_TEST_PLAN,
600
+ richTextTestSuites as any,
601
+ headerStyles,
602
+ styles,
603
+ 4
604
+ );
605
+ const hasHtml = result.some((x: any) => x.type === 'html');
606
+ expect(hasHtml).toBe(true);
607
+ });
608
+ });
609
+
610
+ describe('Time machine report skin - tests', () => {
611
+ test('generate time-machine-report skin with compare summary and differences', async () => {
612
+ const skins = new Skins('json', 'c\\test\\test.dotx');
613
+ const result = await skins.addNewContentToDocumentSkin(
614
+ 'historical-compare-report-content-control',
615
+ skins.SKIN_TYPE_TIME_MACHINE,
616
+ {
617
+ teamProjectName: 'MEWP',
618
+ queryName: 'Shared Query',
619
+ compareResult: {
620
+ baseline: { asOf: '2025-12-22T17:08:00.000Z', total: 4 },
621
+ compareTo: { asOf: '2025-12-28T08:57:00.000Z', total: 4 },
622
+ summary: { updatedCount: 1 },
623
+ rows: [
624
+ {
625
+ id: 11,
626
+ workItemType: 'Requirement',
627
+ title: 'Req-11',
628
+ workItemUrl: 'https://dev.azure.com/org/project/_workitems/edit/11',
629
+ baselineRevisionId: 2,
630
+ compareToRevisionId: 20,
631
+ compareStatus: 'Changed',
632
+ differences: [{ field: 'Test Phase', baseline: 'FAT', compareTo: 'FAT; ATP' }],
633
+ },
634
+ ],
635
+ },
636
+ },
637
+ headerStyles,
638
+ styles,
639
+ 1,
640
+ );
641
+
642
+ expect(Array.isArray(result)).toBe(true);
643
+ expect(result.length).toBeGreaterThan(0);
644
+ expect(result.some((item: any) => item.type === 'table')).toBe(true);
645
+ expect(
646
+ result.some((item: any) => {
647
+ if (item?.type !== 'paragraph') return false;
648
+ const text = (item?.runs || []).map((run: any) => run?.text || '').join('');
649
+ return text.includes('Difference');
650
+ }),
651
+ ).toBe(true);
652
+ expect(
653
+ result.some((item: any) => {
654
+ if (item?.type !== 'paragraph') return false;
655
+ const text = (item?.runs || []).map((run: any) => run?.text || '').join('');
656
+ return text.includes('Work Item Differences');
657
+ }),
658
+ ).toBe(true);
659
+ });
660
+ });
package/tsconfig.json CHANGED
@@ -3,7 +3,7 @@
3
3
  /* Basic Options */
4
4
  "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
5
5
  "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
6
- // "lib": [], /* Specify library files to be included in the compilation. */
6
+ "lib": ["ES2020"] /* Compile against Node/server JS libs only (exclude DOM globals). */,
7
7
  // "allowJs": true, /* Allow javascript files to be compiled. */
8
8
  // "checkJs": true, /* Report errors in .js files. */
9
9
  // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
@@ -43,7 +43,7 @@
43
43
  // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
44
44
  // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
45
45
  // "typeRoots": [], /* List of folders to include type definitions from. */
46
- // "types": [], /* Type declaration files to be included in compilation. */
46
+ "types": ["node", "jest"] /* Use Node typings explicitly (plus Jest for test files compiled in this project). */,
47
47
  // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
48
48
  "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
49
49
  // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */