@5minds/node-red-contrib-processcube-tools 1.0.1-develop-b4cfca-mfdomgtt → 1.0.1-develop-c7d5e6-mfffb5w1

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,309 @@
1
+ const should = require('should');
2
+ const {
3
+ createMockNodeRED,
4
+ setupModuleMocks,
5
+ testConfigs,
6
+ testUtils
7
+ } = require('../helpers/email-receiver.mocks.js');
8
+
9
+ describe('Email Receiver Node - Unit Tests with Helpers', function() {
10
+ this.timeout(10000);
11
+
12
+ let emailReceiverNode;
13
+ let cleanupMocks;
14
+
15
+ before(function() {
16
+ // Set up module mocks using helper
17
+ cleanupMocks = setupModuleMocks();
18
+
19
+ // Load the node with mocked dependencies
20
+ emailReceiverNode = require('../../email-receiver/email-receiver.js');
21
+ });
22
+
23
+ after(function() {
24
+ // Clean up mocks
25
+ if (cleanupMocks) {
26
+ cleanupMocks();
27
+ }
28
+ });
29
+
30
+ describe('Module Export', function() {
31
+ it('should export a function', function() {
32
+ emailReceiverNode.should.be.type('function');
33
+ });
34
+ });
35
+
36
+ describe('Node Registration', function() {
37
+ it('should register node type without errors', function() {
38
+ // ARRANGE: Create mock Node-RED with tracking
39
+ const mockRED = createMockNodeRED();
40
+
41
+ // ACT: Register the node
42
+ emailReceiverNode(mockRED);
43
+
44
+ // ASSERT: Verify registration
45
+ mockRED.nodes.lastRegisteredType.should.equal('email-receiver');
46
+ mockRED.nodes.lastRegisteredConstructor.should.be.type('function');
47
+ });
48
+ });
49
+
50
+ describe('Node Instantiation', function() {
51
+ it('should handle node instantiation with valid config', function() {
52
+ // ARRANGE: Track node creation
53
+ let createdNode = null;
54
+ const mockRED = createMockNodeRED({
55
+ onHandler: function(event, callback) {
56
+ createdNode = this;
57
+ }
58
+ });
59
+
60
+ // ACT: Register and create node instance
61
+ emailReceiverNode(mockRED);
62
+ new mockRED.nodes.lastRegisteredConstructor(testConfigs.valid);
63
+
64
+ // ASSERT: Verify node was created with correct properties
65
+ should.exist(createdNode);
66
+ createdNode.should.have.property('name', testConfigs.valid.name);
67
+ createdNode.should.have.property('id', testConfigs.valid.id);
68
+ });
69
+
70
+ it('should handle minimal config', function() {
71
+ // ARRANGE: Use minimal test config
72
+ let createdNode = null;
73
+ const mockRED = createMockNodeRED({
74
+ onHandler: function(event, callback) {
75
+ createdNode = this;
76
+ }
77
+ });
78
+
79
+ // ACT: Register and create node with minimal config
80
+ emailReceiverNode(mockRED);
81
+ new mockRED.nodes.lastRegisteredConstructor(testConfigs.minimal);
82
+
83
+ // ASSERT: Verify node creation
84
+ should.exist(createdNode);
85
+ createdNode.should.have.property('id', testConfigs.minimal.id);
86
+ });
87
+ });
88
+
89
+ describe('Folder Configuration', function() {
90
+ it('should handle array of folders', async function() {
91
+ // ARRANGE: Set up message tracking
92
+ let sentMessage = null;
93
+ const mockRED = createMockNodeRED({
94
+ sendHandler: function(msg) {
95
+ sentMessage = msg;
96
+ }
97
+ });
98
+
99
+ // ACT: Register node and create instance with array folders
100
+ emailReceiverNode(mockRED);
101
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
102
+ const nodeInstance = new nodeConstructor(testConfigs.arrayFolders);
103
+
104
+ // Wait for processing
105
+ await testUtils.wait(50);
106
+
107
+ // ASSERT: Should handle array folders without error
108
+ should.exist(nodeInstance);
109
+ nodeInstance.should.have.property('name', testConfigs.arrayFolders.name);
110
+ });
111
+ });
112
+
113
+ describe('Error Handling', function() {
114
+ it('should call node.error for invalid folder type', function(done) {
115
+ // ARRANGE: Set up error tracking
116
+ const mockRED = createMockNodeRED({
117
+ onHandler: function(event, callback) {
118
+ if (event === 'input') {
119
+ this.inputCallback = callback;
120
+ }
121
+ },
122
+ errorHandler: function(err) {
123
+ // ASSERT: Should receive appropriate error message
124
+ err.should.containEql("The 'folders' property must be an array of strings.");
125
+ done();
126
+ }
127
+ });
128
+
129
+ // ACT: Register node and create instance with invalid config
130
+ emailReceiverNode(mockRED);
131
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
132
+ const nodeInstance = new nodeConstructor(testConfigs.invalidFolderType);
133
+
134
+ // Trigger the error by sending an input message
135
+ // Use a small delay to ensure the constructor has completed
136
+ setTimeout(() => {
137
+ if (nodeInstance.inputCallback) {
138
+ nodeInstance.inputCallback({ payload: "test" });
139
+ } else {
140
+ done(new Error('inputCallback was not set on the node instance'));
141
+ }
142
+ }, 10);
143
+ });
144
+
145
+ it('should call node.error for missing config', function(done) {
146
+ // ARRANGE: Set up error and status tracking
147
+ let statusCalled = false;
148
+ const mockRED = createMockNodeRED({
149
+ onHandler: function(event, callback) {
150
+ if (event === 'input') {
151
+ this.inputCallback = callback;
152
+ }
153
+ },
154
+ statusHandler: function(status) {
155
+ statusCalled = true;
156
+ if (status.fill) {
157
+ status.fill.should.equal('red');
158
+ }
159
+ },
160
+ errorHandler: function(err) {
161
+ // ASSERT: Should receive config error
162
+ err.should.containEql('Missing required IMAP config');
163
+ statusCalled.should.be.true();
164
+ done();
165
+ }
166
+ });
167
+
168
+ // ACT: Register node and create instance with invalid config
169
+ emailReceiverNode(mockRED);
170
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
171
+ const nodeInstance = new nodeConstructor(testConfigs.invalidConfig);
172
+
173
+ // Trigger the error by sending an input message
174
+ // Use a small delay to ensure the constructor has completed
175
+ setTimeout(() => {
176
+ if (nodeInstance.inputCallback) {
177
+ nodeInstance.inputCallback({ payload: "test" });
178
+ } else {
179
+ done(new Error('inputCallback was not set on the node instance'));
180
+ }
181
+ }, 10);
182
+ });
183
+
184
+ it('should handle connection errors gracefully', function(done) {
185
+ // ARRANGE: Set up connection error scenario with done() protection
186
+ let testCompleted = false;
187
+
188
+ const completeDone = () => {
189
+ if (!testCompleted) {
190
+ testCompleted = true;
191
+ done();
192
+ }
193
+ };
194
+
195
+ const mockRED = createMockNodeRED({
196
+ onHandler: function(event, callback) {
197
+ if (event === 'input') {
198
+ this.inputCallback = callback;
199
+ }
200
+ },
201
+ statusHandler: function(status) {
202
+ if (status.fill === 'red' && status.text && status.text.includes('error')) {
203
+ completeDone(); // Success - error status was set
204
+ }
205
+ },
206
+ errorHandler: function(err) {
207
+ // Also accept errors as valid completion
208
+ should.exist(err);
209
+ completeDone();
210
+ }
211
+ });
212
+
213
+ // Use a config that should cause connection issues
214
+ const badConfig = {
215
+ ...testConfigs.valid,
216
+ host: 'nonexistent.invalid.host.com',
217
+ port: 12345 // Invalid port
218
+ };
219
+
220
+ // ACT: Register node and create instance with invalid config
221
+ emailReceiverNode(mockRED);
222
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
223
+ const nodeInstance = new nodeConstructor(badConfig);
224
+
225
+ // Trigger the error by sending an input message
226
+ // Use a small delay to ensure the constructor has completed
227
+ setTimeout(() => {
228
+ if (nodeInstance.inputCallback) {
229
+ nodeInstance.inputCallback({ payload: "test" });
230
+ } else {
231
+ completeDone(new Error('inputCallback was not set on the node instance'));
232
+ }
233
+ }, 10);
234
+ });
235
+ });
236
+
237
+ describe('IMAP Connection', function() {
238
+ it('should handle connection success', function(done) {
239
+ // ARRANGE: Set up connection tracking
240
+ const mockRED = createMockNodeRED({
241
+ onHandler: function(event, callback) {
242
+ if (event === 'input') {
243
+ this.inputCallback = callback;
244
+ }
245
+ },
246
+ statusHandler: function(status) {
247
+ // ASSERT: Check for 'connected' status and then complete the test
248
+ if (status.fill === 'green' && status.text === 'connected') {
249
+ done();
250
+ }
251
+ }
252
+ });
253
+
254
+ // ACT: Create node with config that should fail
255
+ emailReceiverNode(mockRED);
256
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
257
+ const nodeInstance = new nodeConstructor(testConfigs.valid);
258
+
259
+ // Trigger the connection attempt by sending an input message
260
+ setTimeout(() => {
261
+ if (nodeInstance.inputCallback) {
262
+ nodeInstance.inputCallback({ payload: "test" });
263
+ } else {
264
+ done(new Error('inputCallback was not set on the node instance'));
265
+ }
266
+ }, 10);
267
+ });
268
+
269
+ it('should handle connection errors', function(done) {
270
+ // ARRANGE: Set up error tracking
271
+ const mockRED = createMockNodeRED({
272
+ onHandler: function(event, callback) {
273
+ if (event === 'input') {
274
+ // Store the callback on the node instance
275
+ this.inputCallback = callback;
276
+ }
277
+ },
278
+ errorHandler: function(err) {
279
+ // ASSERT: Should handle connection errors gracefully
280
+ should.exist(err);
281
+ done();
282
+ },
283
+ statusHandler: function(status) {
284
+ if (status.fill === 'red') {
285
+ // Connection failed status
286
+ status.text.should.containEql('error');
287
+ }
288
+ }
289
+ });
290
+
291
+ // ACT: Create node with config that should fail
292
+ emailReceiverNode(mockRED);
293
+ const nodeConstructor = mockRED.nodes.lastRegisteredConstructor;
294
+
295
+ // Use invalid config to trigger connection error
296
+ const invalidConfig = { ...testConfigs.valid, host: 'invalid.host.com' };
297
+ const nodeInstance = new nodeConstructor(invalidConfig);
298
+
299
+ // Trigger the connection attempt by sending an input message
300
+ setTimeout(() => {
301
+ if (nodeInstance.inputCallback) {
302
+ nodeInstance.inputCallback({ payload: "test" });
303
+ } else {
304
+ done(new Error('inputCallback was not set on the node instance'));
305
+ }
306
+ }, 10);
307
+ });
308
+ });
309
+ });