@5minds/node-red-contrib-processcube-tools 1.2.0-feature-7ac247-mg92hchl → 1.2.0-feature-608421-mg9cjskq

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 (61) hide show
  1. package/.env.template +7 -1
  2. package/email-receiver/email-receiver.js +304 -0
  3. package/email-sender/email-sender.js +178 -0
  4. package/examples/.gitkeep +0 -0
  5. package/file-storage/file-storage.html +203 -0
  6. package/file-storage/file-storage.js +148 -0
  7. package/package.json +17 -26
  8. package/{src/html-to-text/html-to-text.html → processcube-html-to-text/processcube-html-to-text.html} +3 -3
  9. package/processcube-html-to-text/processcube-html-to-text.js +22 -0
  10. package/storage/providers/fs.js +117 -0
  11. package/storage/providers/postgres.js +160 -0
  12. package/storage/storage-core.js +77 -0
  13. package/test/helpers/email-receiver.mocks.js +447 -0
  14. package/test/helpers/email-sender.mocks.js +368 -0
  15. package/test/integration/email-receiver.integration.test.js +515 -0
  16. package/test/integration/email-sender.integration.test.js +239 -0
  17. package/test/unit/email-receiver.unit.test.js +304 -0
  18. package/test/unit/email-sender.unit.test.js +570 -0
  19. package/.mocharc.json +0 -5
  20. package/src/custom-node-template/custom-node-template.html.template +0 -45
  21. package/src/custom-node-template/custom-node-template.ts.template +0 -69
  22. package/src/email-receiver/email-receiver.ts +0 -439
  23. package/src/email-sender/email-sender.ts +0 -210
  24. package/src/html-to-text/html-to-text.ts +0 -53
  25. package/src/index.ts +0 -12
  26. package/src/interfaces/EmailReceiverMessage.ts +0 -22
  27. package/src/interfaces/EmailSenderNodeProperties.ts +0 -37
  28. package/src/interfaces/FetchState.ts +0 -9
  29. package/src/interfaces/ImapConnectionConfig.ts +0 -14
  30. package/src/test/framework/advanced-test-patterns.ts +0 -224
  31. package/src/test/framework/generic-node-test-suite.ts +0 -58
  32. package/src/test/framework/index.ts +0 -17
  33. package/src/test/framework/integration-assertions.ts +0 -67
  34. package/src/test/framework/integration-scenario-builder.ts +0 -77
  35. package/src/test/framework/integration-test-runner.ts +0 -101
  36. package/src/test/framework/node-assertions.ts +0 -63
  37. package/src/test/framework/node-test-runner.ts +0 -260
  38. package/src/test/framework/test-scenario-builder.ts +0 -74
  39. package/src/test/framework/types.ts +0 -61
  40. package/src/test/helpers/email-receiver-test-configs.ts +0 -67
  41. package/src/test/helpers/email-receiver-test-flows.ts +0 -16
  42. package/src/test/helpers/email-sender-test-configs.ts +0 -123
  43. package/src/test/helpers/email-sender-test-flows.ts +0 -16
  44. package/src/test/integration/email-receiver.integration.test.ts +0 -41
  45. package/src/test/integration/email-sender.integration.test.ts +0 -129
  46. package/src/test/interfaces/email-data.ts +0 -10
  47. package/src/test/interfaces/email-receiver-config.ts +0 -12
  48. package/src/test/interfaces/email-sender-config.ts +0 -26
  49. package/src/test/interfaces/imap-config.ts +0 -9
  50. package/src/test/interfaces/imap-mailbox.ts +0 -5
  51. package/src/test/interfaces/mail-options.ts +0 -20
  52. package/src/test/interfaces/parsed-email.ts +0 -11
  53. package/src/test/interfaces/send-mail-result.ts +0 -7
  54. package/src/test/mocks/imap-mock.ts +0 -147
  55. package/src/test/mocks/mailparser-mock.ts +0 -82
  56. package/src/test/mocks/nodemailer-mock.ts +0 -118
  57. package/src/test/unit/email-receiver.unit.test.ts +0 -471
  58. package/src/test/unit/email-sender.unit.test.ts +0 -550
  59. package/tsconfig.json +0 -23
  60. /package/{src/email-receiver → email-receiver}/email-receiver.html +0 -0
  61. /package/{src/email-sender → email-sender}/email-sender.html +0 -0
@@ -1,118 +0,0 @@
1
- import { EnhancedMockNodeREDOptions } from '../framework/node-test-runner';
2
- import { MailOptions, MockNodemailerOptions } from '../interfaces/mail-options';
3
- import { SendMailResult } from '../interfaces/send-mail-result';
4
-
5
- class MockNodemailer {
6
- constructor(private options: MockNodemailerOptions = {}) {}
7
-
8
- sendMail(mailOptions: MailOptions, callback: (err: Error | null, result?: SendMailResult) => void): void {
9
- if (this.options.onSendMail) {
10
- this.options.onSendMail(mailOptions);
11
- }
12
-
13
- if (this.options.shouldFail) {
14
- console.log('💥 Triggering failure');
15
- const error = new Error(
16
- this.options.failureMessage || 'Invalid login: 535 Authentication credentials invalid',
17
- ) as Error & { code: string };
18
- error.code = this.options.failureCode || 'EAUTH';
19
- return callback(error);
20
- }
21
-
22
- // Process recipient status
23
- const recipients = this.normalizeRecipients(mailOptions.to);
24
- const result = this.categorizeRecipients(recipients);
25
-
26
- // Simulate realistic delays
27
- setTimeout(() => {
28
- callback(null, {
29
- messageId: this.generateMessageId(),
30
- response: this.getResponseMessage(result),
31
- accepted: result.accepted,
32
- rejected: result.rejected,
33
- pending: result.pending,
34
- });
35
- }, 10);
36
- }
37
-
38
- verify(callback?: (err: Error | null, success?: boolean) => void): Promise<boolean> | void {
39
- if (callback) {
40
- setTimeout(() => {
41
- if (this.options.shouldFailVerify) {
42
- const error = new Error('Mock verify error') as Error & { code: string };
43
- error.code = 'ECONNREFUSED';
44
- callback(error);
45
- } else {
46
- callback(null, true);
47
- }
48
- }, 10);
49
- } else {
50
- // Return a promise if no callback provided
51
- return new Promise((resolve, reject) => {
52
- if (this.options.shouldFailVerify) {
53
- const error = new Error('Mock verify error') as Error & { code: string };
54
- error.code = 'ECONNREFUSED';
55
- reject(error);
56
- } else {
57
- resolve(true);
58
- }
59
- });
60
- }
61
- }
62
-
63
- private normalizeRecipients(to: string | string[]): string[] {
64
- if (Array.isArray(to)) return to;
65
- if (typeof to === 'string') return to.split(',').map((email) => email.trim());
66
- return [];
67
- }
68
-
69
- private categorizeRecipients(recipients: string[]): { accepted: string[]; rejected: string[]; pending: string[] } {
70
- const result = { accepted: [] as string[], rejected: [] as string[], pending: [] as string[] };
71
-
72
- recipients.forEach((email) => {
73
- if (this.options.rejectedEmails?.includes(email)) {
74
- result.rejected.push(email);
75
- } else if (this.options.pendingEmails?.includes(email)) {
76
- result.pending.push(email);
77
- } else if (this.options.acceptedEmails?.length) {
78
- if (this.options.acceptedEmails.includes(email)) {
79
- result.accepted.push(email);
80
- }
81
- } else {
82
- // Default: accept all emails not explicitly rejected or pending
83
- result.accepted.push(email);
84
- }
85
- });
86
-
87
- return result;
88
- }
89
-
90
- private getResponseMessage(result: { accepted: string[]; rejected: string[]; pending: string[] }): string {
91
- if (result.rejected.length > 0) return '550 Mailbox unavailable';
92
- if (result.pending.length > 0) return '451 Requested action aborted: local error';
93
- return '250 OK: Message accepted';
94
- }
95
-
96
- private generateMessageId(): string {
97
- const timestamp = Date.now();
98
- const random = Math.random().toString(36).substr(2, 9);
99
- return `<${timestamp}.${random}@test.com>`;
100
- }
101
- }
102
-
103
- export function createMockNodemailer(options: MockNodemailerOptions = {}) {
104
- return {
105
- createTransport: (config?: any) => new MockNodemailer(options),
106
- restore: () => {
107
- // Cleanup method for compatibility
108
- },
109
- };
110
- }
111
-
112
- export function withNodemailerMock(options: MockNodemailerOptions): Partial<EnhancedMockNodeREDOptions> {
113
- return {
114
- dependencies: {
115
- nodemailer: createMockNodemailer(options),
116
- },
117
- };
118
- }
@@ -1,471 +0,0 @@
1
- import { expect } from 'chai';
2
- import emailReceiverNode from '../../email-receiver/email-receiver';
3
- import { EmailReceiverTestConfigs } from '../helpers/email-receiver-test-configs';
4
-
5
- import { MockImap } from '../mocks/imap-mock';
6
- import { createMockMailparser } from '../mocks/mailparser-mock';
7
-
8
- import {
9
- TestScenarioBuilder,
10
- NodeTestRunner,
11
- NodeAssertions,
12
- createNodeTestSuite,
13
- type TestScenario,
14
- type MockNodeREDOptions,
15
- SecurityTestBuilder,
16
- EdgeCaseTestBuilder,
17
- ErrorResilienceTestBuilder,
18
- } from '../framework';
19
-
20
- describe('E-Mail Receiver Node - Unit Tests', function () {
21
- // ========================================================================
22
- // USE GENERIC TEST SUITE FOR BASIC FUNCTIONALITY
23
- // ========================================================================
24
-
25
- createNodeTestSuite('Email Receiver', emailReceiverNode, EmailReceiverTestConfigs);
26
-
27
- // ========================================================================
28
- // SPECIFIC EMAIL RECEIVER TESTS
29
- // ========================================================================
30
-
31
- describe('Email Receiver Specific Tests', function () {
32
- describe('Configuration Validation', function () {
33
- const configTests = new TestScenarioBuilder()
34
- .addValidScenario('valid configuration', EmailReceiverTestConfigs.valid)
35
- .addValidScenario('minimal configuration', EmailReceiverTestConfigs.minimal)
36
- .addValidScenario('array folders configuration', EmailReceiverTestConfigs.arrayFolders)
37
- .addErrorScenario(
38
- 'invalid folder type',
39
- EmailReceiverTestConfigs.invalidFolderType,
40
- "The 'folders' property must be an array of strings.",
41
- )
42
- .addErrorScenario(
43
- 'missing required config',
44
- EmailReceiverTestConfigs.invalidConfig,
45
- 'Missing required IMAP config',
46
- );
47
-
48
- configTests.getScenarios().forEach((scenario) => {
49
- it(`should handle ${scenario.name}`, async function () {
50
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
51
-
52
- // Verify node was created
53
- expect(context.nodeInstance).to.exist;
54
-
55
- // Check specific expectations
56
- if (scenario.expectedError) {
57
- NodeAssertions.expectError(context, scenario.expectedError);
58
- } else {
59
- NodeAssertions.expectNoErrors(context);
60
- }
61
-
62
- // Verify node properties
63
- if (scenario.config.name) {
64
- NodeAssertions.expectNodeProperty(context, 'name', scenario.config.name);
65
- }
66
-
67
- if (scenario.config.id) {
68
- NodeAssertions.expectNodeProperty(context, 'id', scenario.config.id);
69
- }
70
- });
71
- });
72
- });
73
-
74
- describe('IMAP Connection Handling', function () {
75
- it('should establish connection successfully till the end', async function () {
76
- this.timeout(15000);
77
- const mockDependencies = {
78
- ImapClient: MockImap,
79
- mailParser: createMockMailparser(),
80
- };
81
-
82
- const mockOptions: MockNodeREDOptions = {
83
- dependencies: mockDependencies,
84
- statusHandler: function (status: any) {
85
- console.log('📊 Status received:', JSON.stringify(status, null, 2));
86
- },
87
- errorHandler: function (err: any) {
88
- console.log('❌ Error received:', err);
89
- },
90
- };
91
-
92
- const scenario: TestScenario = {
93
- name: 'successful connection',
94
- config: EmailReceiverTestConfigs.valid,
95
- input: { payload: 'test' },
96
- expectedStatus: { fill: 'green', shape: 'dot', text: 'IMAP connection ended.' },
97
- timeout: 10000,
98
- };
99
-
100
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario, mockOptions);
101
-
102
- // Should have received a green status
103
- const finalStatus = context.statuses.pop(); // Get the last status update
104
- expect(finalStatus.fill).to.equal('green', 'IMAP connection ended.');
105
- expect(finalStatus.text).to.include(
106
- 'IMAP connection ended.',
107
- 'Final status text should indicate completion',
108
- );
109
- });
110
-
111
- it('should establish connection successfully to show mails received', async function () {
112
- this.timeout(15000);
113
- const mockDependencies = {
114
- ImapClient: MockImap,
115
- mailParser: createMockMailparser(),
116
- };
117
-
118
- const mockOptions: MockNodeREDOptions = {
119
- dependencies: mockDependencies,
120
- statusHandler: function (status: any) {
121
- console.log('📊 Status received:', JSON.stringify(status, null, 2));
122
- },
123
- errorHandler: function (err: any) {
124
- console.log('❌ Error received:', err);
125
- },
126
- };
127
-
128
- const scenario: TestScenario = {
129
- name: 'successful connection',
130
- config: EmailReceiverTestConfigs.valid,
131
- input: { payload: 'test' },
132
- expectedStatus: { fill: 'green', shape: 'dot', text: 'Done, fetched 5 mails from INBOX.' },
133
- timeout: 10000,
134
- };
135
-
136
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario, mockOptions);
137
- const doneStatus = context.statuses.find((s) => s.text?.includes('Done, fetched'));
138
-
139
- // Should have received a green status
140
- expect(doneStatus).to.exist;
141
- expect(doneStatus.fill).to.equal('green', 'Done, fetched 5 mails from INBOX.');
142
- expect(doneStatus.text).to.include(
143
- 'Done, fetched',
144
- 'Final status text should indicate completion and fetched mails',
145
- );
146
- });
147
-
148
- it('should handle connection failures gracefully', async function () {
149
- const mockDependencies = {
150
- ImapClient: MockImap,
151
- mailParser: createMockMailparser(),
152
- };
153
-
154
- const mockOptions: MockNodeREDOptions = {
155
- dependencies: mockDependencies,
156
- statusHandler: function (status: any) {
157
- console.log('📊 Status received:', JSON.stringify(status, null, 2));
158
- },
159
- errorHandler: function (err: any) {
160
- console.log('❌ Error received:', err);
161
- },
162
- };
163
-
164
- const scenario: TestScenario = {
165
- name: 'connection failure',
166
- config: EmailReceiverTestConfigs.invalidConfig,
167
- input: { payload: 'test' },
168
- expectedStatus: { fill: 'red', shape: 'ring', text: 'config error' },
169
- expectedError: 'Missing required IMAP config: host, password. Aborting.',
170
- timeout: 5000,
171
- };
172
-
173
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario, mockOptions);
174
-
175
- // Should have either error or red status (or both)
176
- const hasError = context.errors.length > 0;
177
- const hasRedStatus = context.statuses.some((s) => s.fill === 'red');
178
-
179
- expect(hasError || hasRedStatus, 'Should have error or red status for connection failure').to.be.true;
180
-
181
- if (hasRedStatus) {
182
- const redStatus = context.statuses.find((s) => s.fill === 'red');
183
- expect(redStatus!.text).to.include('error');
184
- }
185
- });
186
- });
187
-
188
- describe('Email Processing', function () {
189
- const processingTests = new TestScenarioBuilder()
190
- .addCustomScenario({
191
- name: 'single email fetch',
192
- config: EmailReceiverTestConfigs.valid,
193
- input: { payload: 'fetch' },
194
- timeout: 5000,
195
- })
196
- .addCustomScenario({
197
- name: 'multiple folders processing',
198
- config: EmailReceiverTestConfigs.arrayFolders,
199
- input: { payload: 'fetch' },
200
- timeout: 5000,
201
- });
202
-
203
- processingTests.getScenarios().forEach((scenario) => {
204
- it(`should handle ${scenario.name}`, async function () {
205
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
206
-
207
- // Node should be created without errors
208
- expect(context.nodeInstance).to.exist;
209
- NodeAssertions.expectNoErrors(context);
210
-
211
- // For now, just verify the node processes input without crashing
212
- // You can add more specific email processing assertions here
213
- });
214
- });
215
- });
216
-
217
- describe('Error Recovery', function () {
218
- it('should recover from temporary connection issues', async function () {
219
- // This test would verify that the node can recover from network issues
220
- // Implementation depends on your specific error recovery logic
221
- const scenario: TestScenario = {
222
- name: 'error recovery',
223
- config: EmailReceiverTestConfigs.valid,
224
- input: { payload: 'test' },
225
- timeout: 3000,
226
- };
227
-
228
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
229
- expect(context.nodeInstance).to.exist;
230
- });
231
- });
232
- });
233
-
234
- // ========================================================================
235
- // EMAIL-SPECIFIC ERROR RESILIENCE TESTS
236
- // ========================================================================
237
-
238
- describe('Email Error Resilience', function () {
239
- const resilience = new ErrorResilienceTestBuilder()
240
- .addNetworkErrorScenario('IMAP connection', EmailReceiverTestConfigs.valid)
241
- .addMalformedInputScenario('email message processing', EmailReceiverTestConfigs.valid)
242
- .addRapidFireScenario('email burst handling', EmailReceiverTestConfigs.valid, 50);
243
-
244
- resilience.getScenarios().forEach((scenario) => {
245
- it(`should handle ${scenario.name}`, async function () {
246
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
247
-
248
- // Node should exist and handle errors gracefully
249
- expect(context.nodeInstance).to.exist;
250
-
251
- // Should either process successfully or handle errors appropriately
252
- const hasGracefulHandling =
253
- context.errors.length === 0 ||
254
- context.statuses.some((s) => s.fill === 'red') ||
255
- context.errors.some((e) => typeof e === 'string');
256
-
257
- expect(hasGracefulHandling, 'Should handle errors gracefully').to.be.true;
258
- });
259
- });
260
- });
261
-
262
- // ========================================================================
263
- // EMAIL-SPECIFIC EDGE CASES
264
- // ========================================================================
265
-
266
- describe('Email Edge Cases', function () {
267
- const edgeCases = new EdgeCaseTestBuilder()
268
- .addEmptyDataScenarios('empty email data', EmailReceiverTestConfigs.valid)
269
- .addSpecialCharacterScenarios('special characters in emails', EmailReceiverTestConfigs.valid)
270
- .addLargeDataScenarios('large email attachments', EmailReceiverTestConfigs.valid);
271
-
272
- // Add email-specific edge cases
273
- const emailSpecificCases = new TestScenarioBuilder()
274
- .addCustomScenario({
275
- name: 'very long subject line',
276
- config: EmailReceiverTestConfigs.valid,
277
- input: {
278
- payload: 'fetch',
279
- subject: 'a'.repeat(1000), // Very long subject
280
- },
281
- })
282
- .addCustomScenario({
283
- name: 'multiple folder processing',
284
- config: {
285
- ...EmailReceiverTestConfigs.valid,
286
- folders: Array.from({ length: 50 }, (_, i) => `FOLDER${i}`),
287
- },
288
- input: { payload: 'fetch' },
289
- })
290
- .addCustomScenario({
291
- name: 'special email characters',
292
- config: EmailReceiverTestConfigs.valid,
293
- input: {
294
- payload: 'fetch',
295
- from: 'tëst@exämple.com',
296
- subject: '📧 Émails with spéciál chars! 🌟',
297
- },
298
- });
299
-
300
- [...edgeCases.getScenarios(), ...emailSpecificCases.getScenarios()].forEach((scenario) => {
301
- it(`should handle ${scenario.name}`, async function () {
302
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
303
- expect(context.nodeInstance).to.exist;
304
- });
305
- });
306
- });
307
-
308
- // ========================================================================
309
- // SECURITY TESTS FOR EMAIL PROCESSING
310
- // ========================================================================
311
-
312
- describe('Email Security', function () {
313
- const security = new SecurityTestBuilder()
314
- .addInjectionTestScenarios('email content injection', EmailReceiverTestConfigs.valid)
315
- .addOversizedPayloadScenarios('large email payload', EmailReceiverTestConfigs.valid);
316
-
317
- // Email-specific security tests
318
- const emailSecurity = new TestScenarioBuilder()
319
- .addCustomScenario({
320
- name: 'malicious email headers',
321
- config: EmailReceiverTestConfigs.valid,
322
- input: {
323
- payload: 'fetch',
324
- headers: {
325
- 'X-Malicious': '<script>alert("xss")</script>',
326
- 'X-Injection': "'; DROP TABLE emails; --",
327
- },
328
- },
329
- })
330
- .addCustomScenario({
331
- name: 'suspicious attachment handling',
332
- config: EmailReceiverTestConfigs.valid,
333
- input: {
334
- payload: 'fetch',
335
- attachments: [
336
- { filename: '../../../../../../etc/passwd' },
337
- { filename: 'virus.exe.txt' },
338
- { filename: '<script>evil.js</script>' },
339
- ],
340
- },
341
- });
342
-
343
- [...security.getScenarios(), ...emailSecurity.getScenarios()].forEach((scenario) => {
344
- it(`should resist ${scenario.name}`, async function () {
345
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario);
346
-
347
- // Node should exist and not crash
348
- expect(context.nodeInstance).to.exist;
349
-
350
- // Should handle security threats gracefully
351
- const handledSecurely =
352
- context.errors.length === 0 || context.errors.some((e) => typeof e === 'string');
353
-
354
- expect(handledSecurely, 'Should handle security threats gracefully').to.be.true;
355
- });
356
- });
357
- });
358
-
359
- // ========================================================================
360
- // DATA-DRIVEN TESTS FOR EMAIL SCENARIOS
361
- // ========================================================================
362
-
363
- describe('Email Receiver Data driven tests', function () {
364
- const mockDependencies = {
365
- ImapClient: MockImap,
366
- mailParser: createMockMailparser(),
367
- };
368
- const mockOptions: MockNodeREDOptions = {
369
- dependencies: mockDependencies,
370
- statusHandler: function (status: any) {
371
- console.log('📊 Status:', JSON.stringify(status, null, 2));
372
- },
373
- errorHandler: function (err: any) {
374
- console.log('❌ Error:', err);
375
- console.log('❌ Error stack:', new Error().stack); // See when error occurs
376
- },
377
- onHandler: function (event: string, callback: Function) {
378
- console.log(`🎯 Event registered: ${event}`);
379
- if (event === 'input') {
380
- (this as any).inputCallback = callback;
381
- }
382
- },
383
- };
384
-
385
- const DataDrivenTests = [
386
- {
387
- name: 'fetch INBOX emails',
388
- config: {
389
- ...EmailReceiverTestConfigs.valid,
390
- folder: 'INBOX',
391
- },
392
- },
393
- {
394
- name: 'fetch SENT emails',
395
- config: {
396
- ...EmailReceiverTestConfigs.valid,
397
- folder: 'SENT',
398
- },
399
- },
400
- {
401
- name: 'invalid email receiver',
402
- config: {
403
- ...EmailReceiverTestConfigs.valid,
404
- folder: 'INBOX',
405
- host: '',
406
- },
407
- expectedStatus: { fill: 'red' },
408
- expectedError: /invalid|unknown|missing/i,
409
- },
410
- {
411
- name: 'empty folder name',
412
- config: {
413
- ...EmailReceiverTestConfigs.valid,
414
- folder: '',
415
- },
416
- expectedStatus: { fill: 'red' },
417
- expectedError: /folders|empty|invalid/i,
418
- timeout: 2000,
419
- },
420
- {
421
- name: 'numeric folder name',
422
- config: {
423
- ...EmailReceiverTestConfigs.valid,
424
- folder: 123,
425
- },
426
- expectedStatus: { fill: 'red' },
427
- expectedError: /folder|string|type/i,
428
- timeout: 2000,
429
- },
430
- ];
431
-
432
- DataDrivenTests.forEach((testCase) => {
433
- it(`Email Processing Scenarios ${testCase.name}`, async function () {
434
- const scenario: TestScenario = {
435
- name: testCase.name,
436
- config: testCase.config,
437
- input: { payload: 'fetch' },
438
- expectedError: testCase.expectedError,
439
- expectedStatus: testCase.expectedStatus,
440
- timeout: 3000,
441
- };
442
- console.log(`\n🧪 Starting test: ${testCase.name}`);
443
- console.log('📝 Config:', JSON.stringify(scenario.config));
444
- console.log('📝 Input:', JSON.stringify(scenario.input));
445
-
446
- const context = await NodeTestRunner.runScenario(emailReceiverNode, scenario, mockOptions);
447
-
448
- // 🔍 DEBUG
449
- console.log('📦 Node constructed');
450
- console.log('❌ Errors so far:', context.errors);
451
- console.log('📊 Statuses so far:', context.statuses);
452
- console.log('🐛 Has configError:', !!(context.nodeInstance as any).configError);
453
-
454
- setTimeout(() => {
455
- console.log('⏰ After 100ms:');
456
- console.log('❌ Errors:', context.errors);
457
- console.log('📊 Statuses:', context.statuses);
458
- }, 100);
459
- expect(context.nodeInstance).to.exist;
460
-
461
- if (scenario.expectedStatus) {
462
- NodeAssertions.expectStatus(context, scenario.expectedStatus);
463
- }
464
-
465
- if (scenario.expectedError) {
466
- NodeAssertions.expectError(context, scenario.expectedError);
467
- }
468
- });
469
- });
470
- });
471
- });