@5minds/node-red-contrib-processcube-tools 1.0.1-feature-f506be-mfe3agh6 → 1.0.1-feature-20a8ee-mff2npts

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.
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Shared mock objects and utilities for Email Receiver Node tests
3
+ */
4
+
5
+ /**
6
+ * Mock IMAP implementation for testing
7
+ */
8
+ function createMockImap() {
9
+ return function MockImap(config) {
10
+ this.config = config;
11
+ this.events = {};
12
+
13
+ // Simulate connection behavior
14
+ this.connect = () => {
15
+ // Simulate successful connection by emitting 'ready' event
16
+ if (this.events && this.events.ready) {
17
+ // Use setTimeout to simulate async behavior
18
+ setTimeout(() => this.events.ready(), 10);
19
+ }
20
+ };
21
+
22
+ // Simulate opening a mailbox
23
+ this.openBox = (folder, readOnly, callback) => {
24
+ setTimeout(() => {
25
+ callback(null, {
26
+ messages: { total: 1 },
27
+ name: folder,
28
+ readOnly: readOnly
29
+ });
30
+ }, 10);
31
+ };
32
+
33
+ // Simulate searching for emails
34
+ this.search = (criteria, callback) => {
35
+ setTimeout(() => {
36
+ // Return mock message IDs
37
+ callback(null, [123, 456, 789]);
38
+ }, 10);
39
+ };
40
+
41
+ // Simulate fetching email messages
42
+ this.fetch = (results, options) => {
43
+ return {
44
+ on: (event, callback) => {
45
+ if (event === 'message') {
46
+ setTimeout(() => {
47
+ const mockMessage = {
48
+ on: (messageEvent, messageCallback) => {
49
+ if (messageEvent === 'body') {
50
+ setTimeout(() => {
51
+ messageCallback(Buffer.from('mock email body'));
52
+ }, 5);
53
+ } else if (messageEvent === 'attributes') {
54
+ setTimeout(() => {
55
+ messageCallback({
56
+ uid: 123,
57
+ flags: ['\\Seen'],
58
+ date: new Date(),
59
+ size: 1024
60
+ });
61
+ }, 5);
62
+ }
63
+ },
64
+ once: (messageEvent, messageCallback) => {
65
+ if (messageEvent === 'end') {
66
+ setTimeout(() => messageCallback(), 15);
67
+ }
68
+ }
69
+ };
70
+ callback(mockMessage);
71
+ }, 10);
72
+ }
73
+ },
74
+ once: (event, callback) => {
75
+ if (event === 'end') {
76
+ setTimeout(() => callback(), 20);
77
+ } else if (event === 'error') {
78
+ // Store error callback for potential use
79
+ this.errorCallback = callback;
80
+ }
81
+ }
82
+ };
83
+ };
84
+
85
+ // Simulate closing connection
86
+ this.end = () => {
87
+ if (this.events && this.events.end) {
88
+ setTimeout(() => this.events.end(), 5);
89
+ }
90
+ };
91
+
92
+ // Event listener setup
93
+ this.once = (event, callback) => {
94
+ if (!this.events) this.events = {};
95
+ this.events[event] = callback;
96
+ };
97
+
98
+ // Additional IMAP methods that might be used
99
+ this.addFlags = (source, flags, callback) => {
100
+ setTimeout(() => callback(null), 5);
101
+ };
102
+
103
+ this.removeFlags = (source, flags, callback) => {
104
+ setTimeout(() => callback(null), 5);
105
+ };
106
+
107
+ return this;
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Mock Mailparser implementation for testing
113
+ */
114
+ function createMockMailparser() {
115
+ return {
116
+ simpleParser: function(source, options = {}) {
117
+ return Promise.resolve({
118
+ subject: options.subject || 'Mock Email Subject',
119
+ text: options.text || 'This is a mock email body for testing purposes.',
120
+ html: options.html || '<p>This is a mock email body for testing purposes.</p>',
121
+ from: {
122
+ text: options.from || 'sender@test.com',
123
+ value: [{ address: options.from || 'sender@test.com', name: 'Test Sender' }]
124
+ },
125
+ to: {
126
+ text: options.to || 'recipient@test.com',
127
+ value: [{ address: options.to || 'recipient@test.com', name: 'Test Recipient' }]
128
+ },
129
+ date: options.date || new Date(),
130
+ messageId: options.messageId || '<mock-message-id@test.com>',
131
+ headers: new Map([
132
+ ['message-id', '<mock-message-id@test.com>'],
133
+ ['subject', options.subject || 'Mock Email Subject'],
134
+ ['from', options.from || 'sender@test.com'],
135
+ ['to', options.to || 'recipient@test.com']
136
+ ]),
137
+ attachments: options.attachments || []
138
+ });
139
+ }
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Create mock Node-RED object for unit testing
145
+ */
146
+ function createMockNodeRED(options = {}) {
147
+ // Store input callback in the mock RED context
148
+ let storedInputCallback = null;
149
+ let nodeInstance = null;
150
+
151
+ const mockRED = {
152
+ nodes: {
153
+ createNode: function(node, config) {
154
+ nodeInstance = node; // Capture the node instance
155
+
156
+ // Apply config properties to node
157
+ Object.assign(node, {
158
+ id: config.id || 'mock-node-id',
159
+ type: config.type || 'email-receiver',
160
+ name: config.name || 'Mock Node',
161
+ on: function(event, callback) {
162
+ if (event === 'input') {
163
+ storedInputCallback = callback;
164
+ // Store the callback on the node instance for easy access
165
+ node.inputCallback = callback;
166
+ }
167
+ // Call the original onHandler if provided
168
+ if (options.onHandler) {
169
+ options.onHandler.call(node, event, callback);
170
+ }
171
+ },
172
+ status: options.statusHandler || function() {},
173
+ error: options.errorHandler || function() {},
174
+ send: options.sendHandler || function() {},
175
+ log: options.logHandler || function() {},
176
+ warn: options.warnHandler || function() {},
177
+ debug: options.debugHandler || function() {}
178
+ });
179
+ return node;
180
+ },
181
+ registerType: function(type, constructor) {
182
+ // Store registration for verification in tests
183
+ this.lastRegisteredType = type;
184
+ this.lastRegisteredConstructor = constructor;
185
+ },
186
+ // Helper method to get the stored input callback
187
+ getInputCallback: function() {
188
+ return storedInputCallback;
189
+ },
190
+ // Helper method to get the node instance
191
+ getNodeInstance: function() {
192
+ return nodeInstance;
193
+ }
194
+ },
195
+ util: {
196
+ evaluateNodeProperty: function(value, type, node, msg, callback) {
197
+ if (type === 'json') {
198
+ try {
199
+ // Simulate parsing a JSON string into an object
200
+ return JSON.parse(JSON.stringify(value));
201
+ } catch (e) {
202
+ if (callback) {
203
+ callback(e, null);
204
+ }
205
+ return null;
206
+ }
207
+ }
208
+
209
+ // Simple mock implementation
210
+ if (callback) {
211
+ callback(null, value);
212
+ }
213
+ return value;
214
+ },
215
+ encrypt: function(value) {
216
+ return 'encrypted:' + value;
217
+ },
218
+ decrypt: function(value) {
219
+ return value.replace('encrypted:', '');
220
+ }
221
+ },
222
+ log: {
223
+ info: options.logInfo || function() {},
224
+ warn: options.logWarn || function() {},
225
+ error: options.logError || function() {},
226
+ debug: options.logDebug || function() {}
227
+ }
228
+ };
229
+
230
+ return mockRED;
231
+ }
232
+
233
+ /**
234
+ * Set up module mocks for require() calls
235
+ */
236
+ function setupModuleMocks() {
237
+ const mockModules = {
238
+ 'node-imap': createMockImap(),
239
+ 'mailparser': createMockMailparser()
240
+ };
241
+
242
+ const Module = require('module');
243
+ const originalLoad = Module._load;
244
+
245
+ Module._load = function(request, parent) {
246
+ if (mockModules[request]) {
247
+ return mockModules[request];
248
+ }
249
+ return originalLoad.apply(this, arguments);
250
+ };
251
+
252
+ // Return cleanup function
253
+ return function cleanup() {
254
+ Module._load = originalLoad;
255
+ };
256
+ }
257
+
258
+ /**
259
+ * Create test configurations for different scenarios
260
+ */
261
+ const testConfigs = {
262
+ valid: {
263
+ id: 'test-node-1',
264
+ type: 'email-receiver',
265
+ name: 'Test Email Receiver',
266
+ host: 'imap.test.com',
267
+ hostType: 'str',
268
+ port: 993,
269
+ portType: 'num',
270
+ tls: true,
271
+ tlsType: 'bool',
272
+ user: 'test@test.com',
273
+ userType: 'str',
274
+ password: 'testpass',
275
+ passwordType: 'str',
276
+ folder: ['INBOX'],
277
+ folderType: 'str',
278
+ markseen: true,
279
+ markseenType: 'bool'
280
+ },
281
+
282
+ arrayFolders: {
283
+ id: 'test-node-3',
284
+ type: 'email-receiver',
285
+ name: 'Array Folders Test',
286
+ host: 'imap.test.com',
287
+ hostType: 'str',
288
+ port: 993,
289
+ portType: 'num',
290
+ user: 'test@test.com',
291
+ userType: 'str',
292
+ password: 'testpass',
293
+ passwordType: 'str',
294
+ folder: ['INBOX', 'Junk', 'Drafts'],
295
+ folderType: 'json',
296
+ markseen: false,
297
+ markseenType: 'bool'
298
+ },
299
+
300
+ invalidFolderType: {
301
+ id: 'test-node-4',
302
+ type: 'email-receiver',
303
+ name: 'Invalid Config Test',
304
+ host: '', // Missing host
305
+ hostType: 'str',
306
+ port: 993,
307
+ portType: 'num',
308
+ user: 'test@test.com',
309
+ userType: 'str',
310
+ password: '', // Missing password
311
+ passwordType: 'str',
312
+ folder: 123,
313
+ folderType: 'num'
314
+ },
315
+
316
+ invalidConfig: {
317
+ id: 'test-node-4',
318
+ type: 'email-receiver',
319
+ name: 'Invalid Config Test',
320
+ host: '', // Missing host
321
+ hostType: 'str',
322
+ port: 993,
323
+ portType: 'num',
324
+ user: 'test@test.com',
325
+ userType: 'str',
326
+ password: '', // Missing password
327
+ passwordType: 'str',
328
+ folder: ["Inbox"],
329
+ folderType: 'num'
330
+ },
331
+
332
+ minimal: {
333
+ id: 'test-node-5',
334
+ type: 'email-receiver',
335
+ host: 'imap.minimal.com',
336
+ hostType: 'str',
337
+ port: 993,
338
+ portType: 'num',
339
+ user: 'minimal@test.com',
340
+ userType: 'str',
341
+ password: 'minimalpass',
342
+ passwordType: 'str',
343
+ folder: 'INBOX',
344
+ folderType: 'str'
345
+ }
346
+ };
347
+
348
+ /**
349
+ * Create test flows for Node-RED integration tests
350
+ */
351
+ const testFlows = {
352
+ single: [
353
+ testConfigs.valid
354
+ ],
355
+
356
+ withHelper: [
357
+ testConfigs.valid,
358
+ { id: 'h1', type: 'helper' }
359
+ ],
360
+
361
+ connected: [
362
+ { ...testConfigs.valid, wires: [['h1']] },
363
+ { id: 'h1', type: 'helper' }
364
+ ],
365
+
366
+ multiOutput: [
367
+ { ...testConfigs.valid, wires: [['h1', 'h2']] },
368
+ { id: 'h1', type: 'helper' },
369
+ { id: 'h2', type: 'helper' }
370
+ ]
371
+ };
372
+
373
+ /**
374
+ * Utility functions for test assertions
375
+ */
376
+ const testUtils = {
377
+ /**
378
+ * Wait for a specified amount of time
379
+ */
380
+ wait: (ms = 100) => new Promise(resolve => setTimeout(resolve, ms)),
381
+
382
+ /**
383
+ * Create a promise that resolves when a node receives a message
384
+ */
385
+ waitForMessage: (node, timeout = 1000) => {
386
+ return new Promise((resolve, reject) => {
387
+ const timer = setTimeout(() => {
388
+ reject(new Error('Timeout waiting for message'));
389
+ }, timeout);
390
+
391
+ node.on('input', (msg) => {
392
+ clearTimeout(timer);
393
+ resolve(msg);
394
+ });
395
+ });
396
+ },
397
+
398
+ /**
399
+ * Verify that a message has expected properties
400
+ */
401
+ verifyMessage: (msg, expectedProps = {}) => {
402
+ const should = require('should');
403
+ should.exist(msg);
404
+
405
+ Object.keys(expectedProps).forEach(prop => {
406
+ if (expectedProps[prop] !== undefined) {
407
+ msg.should.have.property(prop, expectedProps[prop]);
408
+ }
409
+ });
410
+ }
411
+ };
412
+
413
+ module.exports = {
414
+ createMockImap,
415
+ createMockMailparser,
416
+ createMockNodeRED,
417
+ setupModuleMocks,
418
+ testConfigs,
419
+ testFlows,
420
+ testUtils
421
+ };