@fsai-flow/core 0.0.1

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 (113) hide show
  1. package/README.md +11 -0
  2. package/dist/README.md +11 -0
  3. package/dist/package.json +44 -0
  4. package/dist/src/index.d.ts +15 -0
  5. package/dist/src/index.js +29 -0
  6. package/dist/src/index.js.map +1 -0
  7. package/dist/src/lib/ActiveWebhooks.d.ts +59 -0
  8. package/dist/src/lib/ActiveWebhooks.js +184 -0
  9. package/dist/src/lib/ActiveWebhooks.js.map +1 -0
  10. package/dist/src/lib/ActiveWorkflows.d.ts +58 -0
  11. package/dist/src/lib/ActiveWorkflows.js +244 -0
  12. package/dist/src/lib/ActiveWorkflows.js.map +1 -0
  13. package/dist/src/lib/BinaryDataManager/FileSystem.d.ts +26 -0
  14. package/dist/src/lib/BinaryDataManager/FileSystem.js +179 -0
  15. package/dist/src/lib/BinaryDataManager/FileSystem.js.map +1 -0
  16. package/dist/src/lib/BinaryDataManager/index.d.ts +21 -0
  17. package/dist/src/lib/BinaryDataManager/index.js +146 -0
  18. package/dist/src/lib/BinaryDataManager/index.js.map +1 -0
  19. package/dist/src/lib/ChangeCase.d.ts +9 -0
  20. package/dist/src/lib/ChangeCase.js +43 -0
  21. package/dist/src/lib/ChangeCase.js.map +1 -0
  22. package/dist/src/lib/Constants.d.ts +14 -0
  23. package/dist/src/lib/Constants.js +19 -0
  24. package/dist/src/lib/Constants.js.map +1 -0
  25. package/dist/src/lib/Credentials.d.ts +27 -0
  26. package/dist/src/lib/Credentials.js +89 -0
  27. package/dist/src/lib/Credentials.js.map +1 -0
  28. package/dist/src/lib/FileSystem.d.ts +26 -0
  29. package/dist/src/lib/FileSystem.js +179 -0
  30. package/dist/src/lib/FileSystem.js.map +1 -0
  31. package/dist/src/lib/InputConnectionDataLegacy.d.ts +2 -0
  32. package/dist/src/lib/InputConnectionDataLegacy.js +79 -0
  33. package/dist/src/lib/InputConnectionDataLegacy.js.map +1 -0
  34. package/dist/src/lib/Interfaces.d.ts +148 -0
  35. package/dist/src/lib/Interfaces.js +3 -0
  36. package/dist/src/lib/Interfaces.js.map +1 -0
  37. package/dist/src/lib/LoadNodeParameterOptions.d.ts +39 -0
  38. package/dist/src/lib/LoadNodeParameterOptions.js +150 -0
  39. package/dist/src/lib/LoadNodeParameterOptions.js.map +1 -0
  40. package/dist/src/lib/NodeExecuteFunctions.d.ts +226 -0
  41. package/dist/src/lib/NodeExecuteFunctions.js +2483 -0
  42. package/dist/src/lib/NodeExecuteFunctions.js.map +1 -0
  43. package/dist/src/lib/NodesLoader/constants.d.ts +5 -0
  44. package/dist/src/lib/NodesLoader/constants.js +106 -0
  45. package/dist/src/lib/NodesLoader/constants.js.map +1 -0
  46. package/dist/src/lib/NodesLoader/custom-directory-loader.d.ts +9 -0
  47. package/dist/src/lib/NodesLoader/custom-directory-loader.js +36 -0
  48. package/dist/src/lib/NodesLoader/custom-directory-loader.js.map +1 -0
  49. package/dist/src/lib/NodesLoader/directory-loader.d.ts +66 -0
  50. package/dist/src/lib/NodesLoader/directory-loader.js +325 -0
  51. package/dist/src/lib/NodesLoader/directory-loader.js.map +1 -0
  52. package/dist/src/lib/NodesLoader/index.d.ts +5 -0
  53. package/dist/src/lib/NodesLoader/index.js +12 -0
  54. package/dist/src/lib/NodesLoader/index.js.map +1 -0
  55. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.d.ts +7 -0
  56. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js +52 -0
  57. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js.map +1 -0
  58. package/dist/src/lib/NodesLoader/load-class-in-isolation.d.ts +1 -0
  59. package/dist/src/lib/NodesLoader/load-class-in-isolation.js +22 -0
  60. package/dist/src/lib/NodesLoader/load-class-in-isolation.js.map +1 -0
  61. package/dist/src/lib/NodesLoader/package-directory-loader.d.ts +17 -0
  62. package/dist/src/lib/NodesLoader/package-directory-loader.js +100 -0
  63. package/dist/src/lib/NodesLoader/package-directory-loader.js.map +1 -0
  64. package/dist/src/lib/NodesLoader/types.d.ts +14 -0
  65. package/dist/src/lib/NodesLoader/types.js +3 -0
  66. package/dist/src/lib/NodesLoader/types.js.map +1 -0
  67. package/dist/src/lib/UserSettings.d.ts +80 -0
  68. package/dist/src/lib/UserSettings.js +261 -0
  69. package/dist/src/lib/UserSettings.js.map +1 -0
  70. package/dist/src/lib/WorkflowExecute.d.ts +53 -0
  71. package/dist/src/lib/WorkflowExecute.js +835 -0
  72. package/dist/src/lib/WorkflowExecute.js.map +1 -0
  73. package/dist/src/lib/index.d.ts +21 -0
  74. package/dist/src/lib/index.js +146 -0
  75. package/dist/src/lib/index.js.map +1 -0
  76. package/dist/src/utils/crypto.d.ts +1 -0
  77. package/dist/src/utils/crypto.js +8 -0
  78. package/dist/src/utils/crypto.js.map +1 -0
  79. package/eslint.config.js +19 -0
  80. package/jest.config.ts +10 -0
  81. package/package.json +44 -0
  82. package/project.json +19 -0
  83. package/src/index.ts +27 -0
  84. package/src/lib/ActiveWebhooks.ts +245 -0
  85. package/src/lib/ActiveWorkflows.ts +304 -0
  86. package/src/lib/BinaryDataManager/FileSystem.ts +214 -0
  87. package/src/lib/BinaryDataManager/index.ts +187 -0
  88. package/src/lib/ChangeCase.ts +45 -0
  89. package/src/lib/Constants.ts +16 -0
  90. package/src/lib/Credentials.ts +108 -0
  91. package/src/lib/FileSystem.ts +214 -0
  92. package/src/lib/InputConnectionDataLegacy.ts +123 -0
  93. package/src/lib/Interfaces.ts +338 -0
  94. package/src/lib/LoadNodeParameterOptions.ts +235 -0
  95. package/src/lib/NodeExecuteFunctions.ts +3704 -0
  96. package/src/lib/NodesLoader/constants.ts +112 -0
  97. package/src/lib/NodesLoader/custom-directory-loader.ts +31 -0
  98. package/src/lib/NodesLoader/directory-loader.ts +458 -0
  99. package/src/lib/NodesLoader/index.ts +5 -0
  100. package/src/lib/NodesLoader/lazy-package-directory-loader.ts +55 -0
  101. package/src/lib/NodesLoader/load-class-in-isolation.ts +19 -0
  102. package/src/lib/NodesLoader/package-directory-loader.ts +107 -0
  103. package/src/lib/NodesLoader/types.ts +14 -0
  104. package/src/lib/UserSettings.ts +292 -0
  105. package/src/lib/WorkflowExecute.ts +1108 -0
  106. package/src/lib/index.ts +187 -0
  107. package/src/utils/crypto.ts +5 -0
  108. package/tests/Credentials.test.ts +88 -0
  109. package/tests/Helpers.ts +808 -0
  110. package/tests/WorkflowExecute.test.ts +1242 -0
  111. package/tsconfig.json +42 -0
  112. package/tsconfig.lib.json +10 -0
  113. package/tsconfig.spec.json +14 -0
@@ -0,0 +1,1242 @@
1
+ /* eslint-disable @typescript-eslint/no-empty-function */
2
+ import {
3
+ createDeferredPromise,
4
+ IConnections,
5
+ ILogger,
6
+ INode,
7
+ IRun,
8
+ LoggerProxy,
9
+ Workflow,
10
+ } from '@fsai-flow/workflow';
11
+
12
+ import { WorkflowExecute } from '../src';
13
+
14
+ import * as Helpers from './Helpers';
15
+
16
+ describe('WorkflowExecute', () => {
17
+ describe('run', () => {
18
+ const tests: Array<{
19
+ description: string;
20
+ input: {
21
+ workflowData: {
22
+ nodes: INode[];
23
+ connections: IConnections;
24
+ };
25
+ };
26
+ output: {
27
+ nodeExecutionOrder: string[];
28
+ nodeData: {
29
+ [key: string]: any[][];
30
+ };
31
+ };
32
+ }> = [
33
+ {
34
+ description: 'should run basic two node workflow',
35
+ input: {
36
+ // Leave the workflowData in regular JSON to be able to easily
37
+ // copy it from/in the UI
38
+ workflowData: {
39
+ nodes: [
40
+ {
41
+ parameters: {},
42
+ name: 'Start',
43
+ type: 'n8n-nodes-base.start',
44
+ typeVersion: 1,
45
+ position: [100, 300],
46
+ },
47
+ {
48
+ parameters: {
49
+ values: {
50
+ number: [
51
+ {
52
+ name: 'value1',
53
+ value: 1,
54
+ },
55
+ ],
56
+ },
57
+ },
58
+ name: 'Set',
59
+ type: 'n8n-nodes-base.set',
60
+ typeVersion: 1,
61
+ position: [280, 300],
62
+ },
63
+ ],
64
+ connections: {
65
+ Start: {
66
+ main: [
67
+ [
68
+ {
69
+ node: 'Set',
70
+ type: 'main',
71
+ index: 0,
72
+ },
73
+ ],
74
+ ],
75
+ },
76
+ },
77
+ },
78
+ },
79
+ output: {
80
+ nodeExecutionOrder: ['Start', 'Set'],
81
+ nodeData: {
82
+ Set: [
83
+ [
84
+ {
85
+ value1: 1,
86
+ },
87
+ ],
88
+ ],
89
+ },
90
+ },
91
+ },
92
+ {
93
+ description: 'should run node twice when it has two input connections',
94
+ input: {
95
+ // Leave the workflowData in regular JSON to be able to easily
96
+ // copy it from/in the UI
97
+ workflowData: {
98
+ nodes: [
99
+ {
100
+ parameters: {},
101
+ name: 'Start',
102
+ type: 'n8n-nodes-base.start',
103
+ typeVersion: 1,
104
+ position: [100, 300],
105
+ },
106
+ {
107
+ parameters: {
108
+ values: {
109
+ number: [
110
+ {
111
+ name: 'value1',
112
+ value: 1,
113
+ },
114
+ ],
115
+ },
116
+ },
117
+ name: 'Set1',
118
+ type: 'n8n-nodes-base.set',
119
+ typeVersion: 1,
120
+ position: [300, 250],
121
+ },
122
+ {
123
+ parameters: {
124
+ values: {
125
+ number: [
126
+ {
127
+ name: 'value2',
128
+ value: 2,
129
+ },
130
+ ],
131
+ },
132
+ },
133
+ name: 'Set2',
134
+ type: 'n8n-nodes-base.set',
135
+ typeVersion: 1,
136
+ position: [500, 400],
137
+ },
138
+ ],
139
+ connections: {
140
+ Start: {
141
+ main: [
142
+ [
143
+ {
144
+ node: 'Set1',
145
+ type: 'main',
146
+ index: 0,
147
+ },
148
+ {
149
+ node: 'Set2',
150
+ type: 'main',
151
+ index: 0,
152
+ },
153
+ ],
154
+ ],
155
+ },
156
+ Set1: {
157
+ main: [
158
+ [
159
+ {
160
+ node: 'Set2',
161
+ type: 'main',
162
+ index: 0,
163
+ },
164
+ ],
165
+ ],
166
+ },
167
+ },
168
+ },
169
+ },
170
+ output: {
171
+ nodeExecutionOrder: ['Start', 'Set1', 'Set2', 'Set2'],
172
+ nodeData: {
173
+ Set1: [
174
+ [
175
+ {
176
+ value1: 1,
177
+ },
178
+ ],
179
+ ],
180
+ Set2: [
181
+ [
182
+ {
183
+ value2: 2,
184
+ },
185
+ ],
186
+ [
187
+ {
188
+ value1: 1,
189
+ value2: 2,
190
+ },
191
+ ],
192
+ ],
193
+ },
194
+ },
195
+ },
196
+ {
197
+ description: 'should run complicated multi node workflow',
198
+ input: {
199
+ // Leave the workflowData in regular JSON to be able to easily
200
+ // copy it from/in the UI
201
+ workflowData: {
202
+ nodes: [
203
+ {
204
+ parameters: {
205
+ mode: 'passThrough',
206
+ },
207
+ name: 'Merge4',
208
+ type: 'n8n-nodes-base.merge',
209
+ typeVersion: 1,
210
+ position: [1150, 500],
211
+ },
212
+ {
213
+ parameters: {
214
+ values: {
215
+ number: [
216
+ {
217
+ name: 'value2',
218
+ value: 2,
219
+ },
220
+ ],
221
+ },
222
+ },
223
+ name: 'Set2',
224
+ type: 'n8n-nodes-base.set',
225
+ typeVersion: 1,
226
+ position: [290, 400],
227
+ },
228
+ {
229
+ parameters: {
230
+ values: {
231
+ number: [
232
+ {
233
+ name: 'value4',
234
+ value: 4,
235
+ },
236
+ ],
237
+ },
238
+ },
239
+ name: 'Set4',
240
+ type: 'n8n-nodes-base.set',
241
+ typeVersion: 1,
242
+ position: [850, 200],
243
+ },
244
+ {
245
+ parameters: {
246
+ values: {
247
+ number: [
248
+ {
249
+ name: 'value3',
250
+ value: 3,
251
+ },
252
+ ],
253
+ },
254
+ },
255
+ name: 'Set3',
256
+ type: 'n8n-nodes-base.set',
257
+ typeVersion: 1,
258
+ position: [650, 200],
259
+ },
260
+ {
261
+ parameters: {
262
+ mode: 'passThrough',
263
+ },
264
+ name: 'Merge4',
265
+ type: 'n8n-nodes-base.merge',
266
+ typeVersion: 1,
267
+ position: [1150, 500],
268
+ },
269
+ {
270
+ parameters: {},
271
+ name: 'Merge3',
272
+ type: 'n8n-nodes-base.merge',
273
+ typeVersion: 1,
274
+ position: [1000, 400],
275
+ },
276
+ {
277
+ parameters: {
278
+ mode: 'passThrough',
279
+ output: 'input2',
280
+ },
281
+ name: 'Merge2',
282
+ type: 'n8n-nodes-base.merge',
283
+ typeVersion: 1,
284
+ position: [700, 400],
285
+ },
286
+ {
287
+ parameters: {},
288
+ name: 'Merge1',
289
+ type: 'n8n-nodes-base.merge',
290
+ typeVersion: 1,
291
+ position: [500, 300],
292
+ },
293
+ {
294
+ parameters: {
295
+ values: {
296
+ number: [
297
+ {
298
+ name: 'value1',
299
+ value: 1,
300
+ },
301
+ ],
302
+ },
303
+ },
304
+ name: 'Set1',
305
+ type: 'n8n-nodes-base.set',
306
+ typeVersion: 1,
307
+ position: [300, 200],
308
+ },
309
+ {
310
+ parameters: {},
311
+ name: 'Start',
312
+ type: 'n8n-nodes-base.start',
313
+ typeVersion: 1,
314
+ position: [100, 300],
315
+ },
316
+ ],
317
+ connections: {
318
+ Set2: {
319
+ main: [
320
+ [
321
+ {
322
+ node: 'Merge1',
323
+ type: 'main',
324
+ index: 1,
325
+ },
326
+ {
327
+ node: 'Merge2',
328
+ type: 'main',
329
+ index: 1,
330
+ },
331
+ ],
332
+ ],
333
+ },
334
+ Set4: {
335
+ main: [
336
+ [
337
+ {
338
+ node: 'Merge3',
339
+ type: 'main',
340
+ index: 0,
341
+ },
342
+ ],
343
+ ],
344
+ },
345
+ Set3: {
346
+ main: [
347
+ [
348
+ {
349
+ node: 'Set4',
350
+ type: 'main',
351
+ index: 0,
352
+ },
353
+ ],
354
+ ],
355
+ },
356
+ Merge3: {
357
+ main: [
358
+ [
359
+ {
360
+ node: 'Merge4',
361
+ type: 'main',
362
+ index: 0,
363
+ },
364
+ ],
365
+ ],
366
+ },
367
+ Merge2: {
368
+ main: [
369
+ [
370
+ {
371
+ node: 'Merge3',
372
+ type: 'main',
373
+ index: 1,
374
+ },
375
+ ],
376
+ ],
377
+ },
378
+ Merge1: {
379
+ main: [
380
+ [
381
+ {
382
+ node: 'Merge2',
383
+ type: 'main',
384
+ index: 0,
385
+ },
386
+ ],
387
+ ],
388
+ },
389
+ Set1: {
390
+ main: [
391
+ [
392
+ {
393
+ node: 'Merge1',
394
+ type: 'main',
395
+ index: 0,
396
+ },
397
+ {
398
+ node: 'Set3',
399
+ type: 'main',
400
+ index: 0,
401
+ },
402
+ ],
403
+ ],
404
+ },
405
+ Start: {
406
+ main: [
407
+ [
408
+ {
409
+ node: 'Set1',
410
+ type: 'main',
411
+ index: 0,
412
+ },
413
+ {
414
+ node: 'Set2',
415
+ type: 'main',
416
+ index: 0,
417
+ },
418
+ {
419
+ node: 'Merge4',
420
+ type: 'main',
421
+ index: 1,
422
+ },
423
+ ],
424
+ ],
425
+ },
426
+ },
427
+ },
428
+ },
429
+ output: {
430
+ nodeExecutionOrder: [
431
+ 'Start',
432
+ 'Set1',
433
+ 'Set2',
434
+ 'Set3',
435
+ 'Merge1',
436
+ 'Set4',
437
+ 'Merge2',
438
+ 'Merge3',
439
+ 'Merge4',
440
+ ],
441
+ nodeData: {
442
+ Set1: [
443
+ [
444
+ {
445
+ value1: 1,
446
+ },
447
+ ],
448
+ ],
449
+ Set2: [
450
+ [
451
+ {
452
+ value2: 2,
453
+ },
454
+ ],
455
+ ],
456
+ Set3: [
457
+ [
458
+ {
459
+ value1: 1,
460
+ value3: 3,
461
+ },
462
+ ],
463
+ ],
464
+ Set4: [
465
+ [
466
+ {
467
+ value1: 1,
468
+ value3: 3,
469
+ value4: 4,
470
+ },
471
+ ],
472
+ ],
473
+ Merge1: [
474
+ [
475
+ {
476
+ value1: 1,
477
+ },
478
+ {
479
+ value2: 2,
480
+ },
481
+ ],
482
+ ],
483
+ Merge2: [
484
+ [
485
+ {
486
+ value2: 2,
487
+ },
488
+ ],
489
+ ],
490
+ Merge3: [
491
+ [
492
+ {
493
+ value1: 1,
494
+ value3: 3,
495
+ value4: 4,
496
+ },
497
+ {
498
+ value2: 2,
499
+ },
500
+ ],
501
+ ],
502
+ Merge4: [
503
+ [
504
+ {
505
+ value1: 1,
506
+ value3: 3,
507
+ value4: 4,
508
+ },
509
+ {
510
+ value2: 2,
511
+ },
512
+ ],
513
+ ],
514
+ },
515
+ },
516
+ },
517
+ {
518
+ description:
519
+ 'should run workflow also if node has multiple input connections and one is empty',
520
+ input: {
521
+ // Leave the workflowData in regular JSON to be able to easily
522
+ // copy it from/in the UI
523
+ workflowData: {
524
+ nodes: [
525
+ {
526
+ parameters: {},
527
+ name: 'Start',
528
+ type: 'n8n-nodes-base.start',
529
+ typeVersion: 1,
530
+ position: [250, 450],
531
+ },
532
+ {
533
+ parameters: {
534
+ conditions: {
535
+ boolean: [],
536
+ number: [
537
+ {
538
+ value1: '={{Object.keys($json).length}}',
539
+ operation: 'notEqual',
540
+ },
541
+ ],
542
+ },
543
+ },
544
+ name: 'IF',
545
+ type: 'n8n-nodes-base.if',
546
+ typeVersion: 1,
547
+ position: [650, 350],
548
+ },
549
+ {
550
+ parameters: {},
551
+ name: 'Merge1',
552
+ type: 'n8n-nodes-base.merge',
553
+ typeVersion: 1,
554
+ position: [1150, 450],
555
+ },
556
+ {
557
+ parameters: {
558
+ values: {
559
+ string: [
560
+ {
561
+ name: 'test1',
562
+ value: 'a',
563
+ },
564
+ ],
565
+ },
566
+ options: {},
567
+ },
568
+ name: 'Set1',
569
+ type: 'n8n-nodes-base.set',
570
+ typeVersion: 1,
571
+ position: [450, 450],
572
+ },
573
+ {
574
+ parameters: {
575
+ values: {
576
+ string: [
577
+ {
578
+ name: 'test2',
579
+ value: 'b',
580
+ },
581
+ ],
582
+ },
583
+ options: {},
584
+ },
585
+ name: 'Set2',
586
+ type: 'n8n-nodes-base.set',
587
+ typeVersion: 1,
588
+ position: [800, 250],
589
+ },
590
+ ],
591
+ connections: {
592
+ Start: {
593
+ main: [
594
+ [
595
+ {
596
+ node: 'Set1',
597
+ type: 'main',
598
+ index: 0,
599
+ },
600
+ ],
601
+ ],
602
+ },
603
+ IF: {
604
+ main: [
605
+ [
606
+ {
607
+ node: 'Set2',
608
+ type: 'main',
609
+ index: 0,
610
+ },
611
+ ],
612
+ [
613
+ {
614
+ node: 'Merge1',
615
+ type: 'main',
616
+ index: 0,
617
+ },
618
+ ],
619
+ ],
620
+ },
621
+ Set1: {
622
+ main: [
623
+ [
624
+ {
625
+ node: 'IF',
626
+ type: 'main',
627
+ index: 0,
628
+ },
629
+ {
630
+ node: 'Merge1',
631
+ type: 'main',
632
+ index: 1,
633
+ },
634
+ ],
635
+ ],
636
+ },
637
+ Set2: {
638
+ main: [
639
+ [
640
+ {
641
+ node: 'Merge1',
642
+ type: 'main',
643
+ index: 0,
644
+ },
645
+ ],
646
+ ],
647
+ },
648
+ },
649
+ },
650
+ },
651
+ output: {
652
+ nodeExecutionOrder: ['Start', 'Set1', 'IF', 'Set2', 'Merge1'],
653
+ nodeData: {
654
+ Merge1: [
655
+ [
656
+ {
657
+ test1: 'a',
658
+ test2: 'b',
659
+ },
660
+ {
661
+ test1: 'a',
662
+ },
663
+ ],
664
+ ],
665
+ },
666
+ },
667
+ },
668
+ {
669
+ description: 'should use empty data if second input does not have any data',
670
+ input: {
671
+ // Leave the workflowData in regular JSON to be able to easily
672
+ // copy it from/in the UI
673
+ workflowData: {
674
+ nodes: [
675
+ {
676
+ parameters: {},
677
+ name: 'Start',
678
+ type: 'n8n-nodes-base.start',
679
+ typeVersion: 1,
680
+ position: [250, 300],
681
+ },
682
+ {
683
+ parameters: {},
684
+ name: 'Merge',
685
+ type: 'n8n-nodes-base.merge',
686
+ typeVersion: 1,
687
+ position: [800, 450],
688
+ },
689
+ {
690
+ parameters: {},
691
+ name: 'Merge1',
692
+ type: 'n8n-nodes-base.merge',
693
+ typeVersion: 1,
694
+ position: [1000, 300],
695
+ },
696
+ {
697
+ parameters: {
698
+ conditions: {
699
+ boolean: [
700
+ {
701
+ value2: true,
702
+ },
703
+ ],
704
+ string: [
705
+ {
706
+ value1: '={{$json["key"]}}',
707
+ value2: 'a',
708
+ },
709
+ ],
710
+ },
711
+ combineOperation: 'any',
712
+ },
713
+ name: 'IF',
714
+ type: 'n8n-nodes-base.if',
715
+ typeVersion: 1,
716
+ position: [600, 600],
717
+ alwaysOutputData: false,
718
+ },
719
+ {
720
+ parameters: {
721
+ values: {
722
+ number: [
723
+ {
724
+ name: 'number0',
725
+ },
726
+ ],
727
+ string: [
728
+ {
729
+ name: 'key',
730
+ value: 'a',
731
+ },
732
+ ],
733
+ },
734
+ options: {},
735
+ },
736
+ name: 'Set0',
737
+ type: 'n8n-nodes-base.set',
738
+ typeVersion: 1,
739
+ position: [450, 300],
740
+ },
741
+ {
742
+ parameters: {
743
+ values: {
744
+ number: [
745
+ {
746
+ name: 'number1',
747
+ value: 1,
748
+ },
749
+ ],
750
+ string: [
751
+ {
752
+ name: 'key',
753
+ value: 'b',
754
+ },
755
+ ],
756
+ },
757
+ options: {},
758
+ },
759
+ name: 'Set1',
760
+ type: 'n8n-nodes-base.set',
761
+ typeVersion: 1,
762
+ position: [450, 450],
763
+ },
764
+ {
765
+ parameters: {
766
+ values: {
767
+ number: [
768
+ {
769
+ name: 'number2',
770
+ value: 2,
771
+ },
772
+ ],
773
+ string: [
774
+ {
775
+ name: 'key',
776
+ value: 'c',
777
+ },
778
+ ],
779
+ },
780
+ options: {},
781
+ },
782
+ name: 'Set2',
783
+ type: 'n8n-nodes-base.set',
784
+ typeVersion: 1,
785
+ position: [450, 600],
786
+ },
787
+ ],
788
+ connections: {
789
+ Start: {
790
+ main: [
791
+ [
792
+ {
793
+ node: 'Set0',
794
+ type: 'main',
795
+ index: 0,
796
+ },
797
+ ],
798
+ ],
799
+ },
800
+ Merge: {
801
+ main: [
802
+ [
803
+ {
804
+ node: 'Merge1',
805
+ type: 'main',
806
+ index: 1,
807
+ },
808
+ ],
809
+ ],
810
+ },
811
+ IF: {
812
+ main: [
813
+ [
814
+ {
815
+ node: 'Merge',
816
+ type: 'main',
817
+ index: 1,
818
+ },
819
+ ],
820
+ ],
821
+ },
822
+ Set0: {
823
+ main: [
824
+ [
825
+ {
826
+ node: 'Merge1',
827
+ type: 'main',
828
+ index: 0,
829
+ },
830
+ ],
831
+ ],
832
+ },
833
+ Set1: {
834
+ main: [
835
+ [
836
+ {
837
+ node: 'Merge',
838
+ type: 'main',
839
+ index: 0,
840
+ },
841
+ ],
842
+ ],
843
+ },
844
+ Set2: {
845
+ main: [
846
+ [
847
+ {
848
+ node: 'IF',
849
+ type: 'main',
850
+ index: 0,
851
+ },
852
+ ],
853
+ ],
854
+ },
855
+ },
856
+ },
857
+ },
858
+ output: {
859
+ nodeExecutionOrder: ['Start', 'Set0', 'Set2', 'IF', 'Set1', 'Merge', 'Merge1'],
860
+ nodeData: {
861
+ Merge: [
862
+ [
863
+ {
864
+ number1: 1,
865
+ key: 'b',
866
+ },
867
+ ],
868
+ ],
869
+ Merge1: [
870
+ [
871
+ {
872
+ number0: 0,
873
+ key: 'a',
874
+ },
875
+ {
876
+ number1: 1,
877
+ key: 'b',
878
+ },
879
+ ],
880
+ ],
881
+ },
882
+ },
883
+ },
884
+ {
885
+ description:
886
+ 'should use empty data if input of sibling does not receive any data from parent',
887
+ input: {
888
+ // Leave the workflowData in regular JSON to be able to easily
889
+ // copy it from/in the UI
890
+ workflowData: {
891
+ nodes: [
892
+ {
893
+ parameters: {},
894
+ name: 'Start',
895
+ type: 'n8n-nodes-base.start',
896
+ typeVersion: 1,
897
+ position: [250, 300],
898
+ },
899
+ {
900
+ parameters: {
901
+ conditions: {
902
+ number: [
903
+ {
904
+ value1: '={{$json["value1"]}}',
905
+ operation: 'equal',
906
+ value2: 1,
907
+ },
908
+ ],
909
+ },
910
+ },
911
+ name: 'IF',
912
+ type: 'n8n-nodes-base.if',
913
+ typeVersion: 1,
914
+ position: [650, 300],
915
+ },
916
+ {
917
+ parameters: {
918
+ values: {
919
+ string: [],
920
+ number: [
921
+ {
922
+ name: 'value2',
923
+ value: 2,
924
+ },
925
+ ],
926
+ },
927
+ options: {},
928
+ },
929
+ name: 'Set2',
930
+ type: 'n8n-nodes-base.set',
931
+ typeVersion: 1,
932
+ position: [850, 450],
933
+ },
934
+ {
935
+ parameters: {
936
+ values: {
937
+ number: [
938
+ {
939
+ name: 'value1',
940
+ value: 1,
941
+ },
942
+ ],
943
+ },
944
+ options: {},
945
+ },
946
+ name: 'Set1',
947
+ type: 'n8n-nodes-base.set',
948
+ typeVersion: 1,
949
+ position: [450, 300],
950
+ },
951
+ {
952
+ parameters: {},
953
+ name: 'Merge',
954
+ type: 'n8n-nodes-base.merge',
955
+ typeVersion: 1,
956
+ position: [1050, 300],
957
+ },
958
+ ],
959
+ connections: {
960
+ Start: {
961
+ main: [
962
+ [
963
+ {
964
+ node: 'Set1',
965
+ type: 'main',
966
+ index: 0,
967
+ },
968
+ ],
969
+ ],
970
+ },
971
+ IF: {
972
+ main: [
973
+ [
974
+ {
975
+ node: 'Merge',
976
+ type: 'main',
977
+ index: 0,
978
+ },
979
+ ],
980
+ [
981
+ {
982
+ node: 'Set2',
983
+ type: 'main',
984
+ index: 0,
985
+ },
986
+ ],
987
+ ],
988
+ },
989
+ Set2: {
990
+ main: [
991
+ [
992
+ {
993
+ node: 'Merge',
994
+ type: 'main',
995
+ index: 1,
996
+ },
997
+ ],
998
+ ],
999
+ },
1000
+ Set1: {
1001
+ main: [
1002
+ [
1003
+ {
1004
+ node: 'IF',
1005
+ type: 'main',
1006
+ index: 0,
1007
+ },
1008
+ ],
1009
+ ],
1010
+ },
1011
+ },
1012
+ },
1013
+ },
1014
+ output: {
1015
+ nodeExecutionOrder: ['Start', 'Set1', 'IF', 'Set2', 'Merge'],
1016
+ nodeData: {
1017
+ Merge: [
1018
+ [
1019
+ {
1020
+ value1: 1,
1021
+ },
1022
+ {
1023
+ value2: 2,
1024
+ },
1025
+ ],
1026
+ ],
1027
+ },
1028
+ },
1029
+ },
1030
+ {
1031
+ description: 'should not use empty data in sibling if parent did not send any data',
1032
+ input: {
1033
+ // Leave the workflowData in regular JSON to be able to easily
1034
+ // copy it from/in the UI
1035
+ workflowData: {
1036
+ nodes: [
1037
+ {
1038
+ parameters: {},
1039
+ name: 'Start',
1040
+ type: 'n8n-nodes-base.start',
1041
+ typeVersion: 1,
1042
+ position: [250, 300],
1043
+ },
1044
+ {
1045
+ parameters: {
1046
+ values: {
1047
+ number: [
1048
+ {
1049
+ name: 'value1',
1050
+ },
1051
+ ],
1052
+ },
1053
+ options: {},
1054
+ },
1055
+ name: 'Set',
1056
+ type: 'n8n-nodes-base.set',
1057
+ typeVersion: 1,
1058
+ position: [450, 300],
1059
+ },
1060
+ {
1061
+ parameters: {},
1062
+ name: 'Merge',
1063
+ type: 'n8n-nodes-base.merge',
1064
+ typeVersion: 1,
1065
+ position: [1050, 250],
1066
+ },
1067
+ {
1068
+ parameters: {
1069
+ conditions: {
1070
+ number: [
1071
+ {
1072
+ value1: '={{$json["value1"]}}',
1073
+ operation: 'equal',
1074
+ value2: 1,
1075
+ },
1076
+ ],
1077
+ },
1078
+ },
1079
+ name: 'IF',
1080
+ type: 'n8n-nodes-base.if',
1081
+ typeVersion: 1,
1082
+ position: [650, 300],
1083
+ },
1084
+ {
1085
+ parameters: {},
1086
+ name: 'NoOpTrue',
1087
+ type: 'n8n-nodes-base.noOp',
1088
+ typeVersion: 1,
1089
+ position: [850, 150],
1090
+ },
1091
+ {
1092
+ parameters: {},
1093
+ name: 'NoOpFalse',
1094
+ type: 'n8n-nodes-base.noOp',
1095
+ typeVersion: 1,
1096
+ position: [850, 400],
1097
+ },
1098
+ ],
1099
+ connections: {
1100
+ Start: {
1101
+ main: [
1102
+ [
1103
+ {
1104
+ node: 'Set',
1105
+ type: 'main',
1106
+ index: 0,
1107
+ },
1108
+ ],
1109
+ ],
1110
+ },
1111
+ Set: {
1112
+ main: [
1113
+ [
1114
+ {
1115
+ node: 'IF',
1116
+ type: 'main',
1117
+ index: 0,
1118
+ },
1119
+ ],
1120
+ ],
1121
+ },
1122
+ IF: {
1123
+ main: [
1124
+ [
1125
+ {
1126
+ node: 'NoOpTrue',
1127
+ type: 'main',
1128
+ index: 0,
1129
+ },
1130
+ {
1131
+ node: 'Merge',
1132
+ type: 'main',
1133
+ index: 1,
1134
+ },
1135
+ ],
1136
+ [
1137
+ {
1138
+ node: 'NoOpFalse',
1139
+ type: 'main',
1140
+ index: 0,
1141
+ },
1142
+ ],
1143
+ ],
1144
+ },
1145
+ NoOpTrue: {
1146
+ main: [
1147
+ [
1148
+ {
1149
+ node: 'Merge',
1150
+ type: 'main',
1151
+ index: 0,
1152
+ },
1153
+ ],
1154
+ ],
1155
+ },
1156
+ },
1157
+ },
1158
+ },
1159
+ output: {
1160
+ nodeExecutionOrder: ['Start', 'Set', 'IF', 'NoOpFalse'],
1161
+ nodeData: {
1162
+ IF: [[]],
1163
+ NoOpFalse: [
1164
+ [
1165
+ {
1166
+ value1: 0,
1167
+ },
1168
+ ],
1169
+ ],
1170
+ },
1171
+ },
1172
+ },
1173
+ ];
1174
+
1175
+ const fakeLogger = {
1176
+ log: () => {},
1177
+ debug: () => {},
1178
+ verbose: () => {},
1179
+ info: () => {},
1180
+ warn: () => {},
1181
+ error: () => {},
1182
+ } as ILogger;
1183
+
1184
+ const executionMode = 'manual';
1185
+ const nodeTypes = Helpers.NodeTypes();
1186
+ LoggerProxy.init(fakeLogger);
1187
+
1188
+ for (const testData of tests) {
1189
+ test(testData.description, async () => {
1190
+ const workflowInstance = new Workflow({
1191
+ id: 'test',
1192
+ nodes: testData.input.workflowData.nodes,
1193
+ connections: testData.input.workflowData.connections,
1194
+ active: false,
1195
+ nodeTypes,
1196
+ });
1197
+
1198
+ const waitPromise = await createDeferredPromise<IRun>();
1199
+ const nodeExecutionOrder: string[] = [];
1200
+ const additionalData = Helpers.WorkflowExecuteAdditionalData(
1201
+ waitPromise,
1202
+ nodeExecutionOrder,
1203
+ );
1204
+
1205
+ const workflowExecute = new WorkflowExecute(additionalData, executionMode);
1206
+
1207
+ const executionData = await workflowExecute.run(workflowInstance);
1208
+
1209
+ const result = await waitPromise.promise();
1210
+
1211
+ // Check if the data from WorkflowExecute is identical to data received
1212
+ // by the webhooks
1213
+ expect(executionData).toEqual(result);
1214
+
1215
+ // Check if the output data of the nodes is correct
1216
+ for (const nodeName of Object.keys(testData.output.nodeData)) {
1217
+ if (result.data.resultData.runData[nodeName] === undefined) {
1218
+ throw new Error(`Data for node "${nodeName}" is missing!`);
1219
+ }
1220
+
1221
+ const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
1222
+ if (nodeData.data === undefined) {
1223
+ return null;
1224
+ }
1225
+ return nodeData.data['main'][0]!.map((entry) => entry.json);
1226
+ });
1227
+
1228
+ // expect(resultData).toEqual(testData.output.nodeData[nodeName]);
1229
+ expect(resultData).toEqual(testData.output.nodeData[nodeName]);
1230
+ }
1231
+
1232
+ // Check if the nodes did execute in the correct order
1233
+ expect(nodeExecutionOrder).toEqual(testData.output.nodeExecutionOrder);
1234
+
1235
+ // Check if other data has correct value
1236
+ expect(result.finished).toEqual(true);
1237
+ expect(result.data.executionData!.contextData).toEqual({});
1238
+ expect(result.data.executionData!.nodeExecutionStack).toEqual([]);
1239
+ });
1240
+ }
1241
+ });
1242
+ });