@5minds/node-red-contrib-processcube-tools 1.0.1-develop-b4cfca-mfdomgtt → 1.0.1-feature-b241c2-mfdq69jq

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,300 @@
1
+ const should = require('should');
2
+
3
+ describe('Email Receiver Node - Unit Tests', function() {
4
+ // Set a reasonable timeout
5
+ this.timeout(10000);
6
+
7
+ // Module and mocking setup
8
+ let emailReceiverNode;
9
+ let originalLoad;
10
+ let mockImap;
11
+ let mockMailparser;
12
+
13
+ before(function() {
14
+ // Create mock modules with correct behavior
15
+ mockImap = function(config) {
16
+ this.config = config;
17
+ this.connect = () => {
18
+ // Simulate a successful connection by immediately emitting 'ready'
19
+ if (this.events && this.events.ready) {
20
+ this.events.ready();
21
+ }
22
+ };
23
+ this.openBox = (folder, readOnly, callback) => { callback(null, { messages: { total: 1 } }); };
24
+ this.search = (criteria, callback) => { callback(null, [123]); };
25
+ this.fetch = (results, options) => {
26
+ return {
27
+ on: (event, cb) => {
28
+ if (event === 'message') {
29
+ cb({ on: (e, bodyCb) => { if (e === 'body') bodyCb({}); } });
30
+ }
31
+ },
32
+ once: (event, cb) => {
33
+ if (event === 'end') { cb(); }
34
+ }
35
+ };
36
+ };
37
+ this.end = () => {};
38
+ this.once = (event, callback) => {
39
+ if (!this.events) this.events = {};
40
+ this.events[event] = callback;
41
+ };
42
+ return this;
43
+ };
44
+
45
+ mockMailparser = {
46
+ simpleParser: function() {
47
+ return Promise.resolve({
48
+ subject: 'test',
49
+ text: 'test body',
50
+ html: '<p>test</p>',
51
+ from: { text: 'test@test.com' },
52
+ date: new Date(),
53
+ headers: new Map(),
54
+ attachments: []
55
+ });
56
+ }
57
+ };
58
+
59
+ const mockModules = {
60
+ 'node-imap': mockImap,
61
+ 'mailparser': mockMailparser
62
+ };
63
+
64
+ // Override require
65
+ const Module = require('module');
66
+ originalLoad = Module._load;
67
+ Module._load = function(request, parent) {
68
+ if (mockModules[request]) {
69
+ return mockModules[request];
70
+ }
71
+ return originalLoad.apply(this, arguments);
72
+ };
73
+
74
+ // Load the node with mocked dependencies
75
+ emailReceiverNode = require('../../email-receiver/email-receiver.js');
76
+ });
77
+
78
+ after(function() {
79
+ // Restore original module loading
80
+ if (originalLoad) {
81
+ const Module = require('module');
82
+ Module._load = originalLoad;
83
+ }
84
+ });
85
+
86
+ describe('Module Export', function() {
87
+ it('should export a function', function() {
88
+ // ARRANGE: Node module is already loaded
89
+
90
+ // ACT: Check the type of the exported module
91
+
92
+ // ASSERT: Should be a function
93
+ emailReceiverNode.should.be.type('function');
94
+ });
95
+ });
96
+
97
+ describe('Node Registration', function() {
98
+ it('should register node type without errors', function() {
99
+ // ARRANGE: Set up mock RED object and capture registration calls
100
+ let registeredType;
101
+ let registeredConstructor;
102
+
103
+ const mockRED = {
104
+ nodes: {
105
+ createNode: function(node, config) {
106
+ node.id = config.id;
107
+ node.type = config.type;
108
+ node.name = config.name;
109
+ node.on = function() {};
110
+ node.status = function() {};
111
+ node.error = function() {};
112
+ node.send = function() {};
113
+ return node;
114
+ },
115
+ registerType: function(type, constructor) {
116
+ registeredType = type;
117
+ registeredConstructor = constructor;
118
+ }
119
+ },
120
+ util: {
121
+ evaluateNodeProperty: function(value, type) {
122
+ return value;
123
+ },
124
+ encrypt: function(value) {
125
+ return 'encrypted:' + value;
126
+ }
127
+ }
128
+ };
129
+
130
+ // ACT: Call the node registration function
131
+ emailReceiverNode(mockRED);
132
+
133
+ // ASSERT: Verify registration was called correctly
134
+ registeredType.should.equal('email-receiver');
135
+ registeredConstructor.should.be.type('function');
136
+ });
137
+ });
138
+
139
+ describe('Node Instantiation', function() {
140
+ it('should handle node instantiation with valid config', function() {
141
+ // ARRANGE: Set up mock RED object and node instance tracking
142
+ let nodeInstance;
143
+
144
+ const mockRED = {
145
+ nodes: {
146
+ createNode: function(node, config) {
147
+ nodeInstance = node;
148
+ node.id = config.id;
149
+ node.type = config.type;
150
+ node.name = config.name;
151
+ node.on = function() {};
152
+ node.status = function() {};
153
+ node.error = function() {};
154
+ node.send = function() {};
155
+ return node;
156
+ },
157
+ registerType: function(type, NodeConstructor) {
158
+ // Simulate creating a node instance with valid config
159
+ const config = {
160
+ id: 'test-node',
161
+ type: 'email-receiver',
162
+ name: 'Test Email Receiver',
163
+ host: 'imap.test.com',
164
+ hostType: 'str',
165
+ port: 993,
166
+ portType: 'num',
167
+ user: 'test@test.com',
168
+ userType: 'str',
169
+ password: 'testpass',
170
+ passwordType: 'str',
171
+ folder: 'INBOX',
172
+ folderType: 'str',
173
+ markseen: true,
174
+ markseenType: 'bool'
175
+ };
176
+
177
+ new NodeConstructor(config);
178
+ }
179
+ },
180
+ util: {
181
+ evaluateNodeProperty: function(value, type) {
182
+ return value;
183
+ },
184
+ encrypt: function(value) {
185
+ return 'encrypted:' + value;
186
+ }
187
+ }
188
+ };
189
+
190
+ // ACT: Register the node and create an instance
191
+ emailReceiverNode(mockRED);
192
+
193
+ // ASSERT: Verify the node instance was created with correct properties
194
+ should.exist(nodeInstance);
195
+ nodeInstance.should.have.property('name', 'Test Email Receiver');
196
+ });
197
+ });
198
+
199
+ describe('Folder Configuration', function() {
200
+ it('should handle an array of folders', function(done) {
201
+ // ARRANGE: Mock the Node-RED environment
202
+ let nodeInstance;
203
+ let inputCallback;
204
+ const mockRED = {
205
+ nodes: {
206
+ createNode: function(node, config) {
207
+ nodeInstance = node;
208
+ node.on = (event, callback) => { if (event === 'input') inputCallback = callback; };
209
+ node.status = () => {};
210
+ node.error = () => {};
211
+ node.send = (msg) => {
212
+ should.exist(msg);
213
+ msg.payload.should.equal('test body');
214
+ done();
215
+ };
216
+ return node;
217
+ },
218
+ registerType: (type, constructor) => {
219
+ new constructor({
220
+ host: "imap.test.com", hostType: "str",
221
+ port: 993, portType: "num",
222
+ user: "test@test.com", userType: "str",
223
+ password: "testpass", passwordType: "str",
224
+ folder: ["INBOX", "Junk"], folderType: 'json',
225
+ markseen: true, markseenType: 'bool'
226
+ });
227
+ }
228
+ },
229
+ util: { evaluateNodeProperty: (value) => value },
230
+ };
231
+
232
+ // ACT: Register the node, then simulate input
233
+ emailReceiverNode(mockRED);
234
+ inputCallback({});
235
+ });
236
+ });
237
+
238
+ describe('Error Handling', function() {
239
+ it('should call node.error for invalid folder type', function(done) {
240
+ // ARRANGE: Mock the node instance to capture errors
241
+ let errorCalled = false;
242
+ const nodeInstance = {
243
+ config: { folder: 123, folderType: 'num' },
244
+ on: (event, callback) => { if (event === 'input') nodeInstance.inputCallback = callback; },
245
+ status: () => {},
246
+ error: (err) => {
247
+ errorCalled = true;
248
+ err.should.containEql('The \'folders\' property must be an array of strings');
249
+ done();
250
+ },
251
+ send: () => {},
252
+ };
253
+ const mockRED = {
254
+ nodes: {
255
+ createNode: (node, config) => Object.assign(node, { on: nodeInstance.on, status: nodeInstance.status, error: nodeInstance.error, send: nodeInstance.send }),
256
+ registerType: (type, constructor) => new constructor(nodeInstance.config),
257
+ },
258
+ util: { evaluateNodeProperty: (value, type) => value },
259
+ };
260
+
261
+ // ACT: Register and instantiate the node, then simulate an input message
262
+ emailReceiverNode(mockRED);
263
+ nodeInstance.inputCallback({});
264
+ });
265
+
266
+ it('should call node.error for missing config', function(done) {
267
+ // ARRANGE: Mock the node instance to capture errors
268
+ let errorCalled = false;
269
+ let statusCalled = false;
270
+ const nodeInstance = {
271
+ config: {
272
+ host: "imap.test.com", hostType: "str",
273
+ port: 993, portType: "num",
274
+ user: "test@test.com", userType: "str",
275
+ password: "", passwordType: "str", // Empty password should trigger error
276
+ folder: "INBOX", folderType: "str"
277
+ },
278
+ on: (event, callback) => { if (event === 'input') nodeInstance.inputCallback = callback; },
279
+ status: (s) => { statusCalled = true; s.fill.should.equal('red'); },
280
+ error: (err) => {
281
+ errorCalled = true;
282
+ err.should.containEql('Missing required IMAP config');
283
+ done();
284
+ },
285
+ send: () => {},
286
+ };
287
+ const mockRED = {
288
+ nodes: {
289
+ createNode: (node, config) => Object.assign(node, { on: nodeInstance.on, status: nodeInstance.status, error: nodeInstance.error, send: nodeInstance.send }),
290
+ registerType: (type, constructor) => new constructor(nodeInstance.config),
291
+ },
292
+ util: { evaluateNodeProperty: (value, type) => value },
293
+ };
294
+
295
+ // ACT: Register and instantiate the node, then simulate an input message
296
+ emailReceiverNode(mockRED);
297
+ nodeInstance.inputCallback({});
298
+ });
299
+ });
300
+ });