Skip to content

Commit a04dc2c

Browse files
authored
Merge pull request #54 from Steve-Mcl/add-setFlows
add `setFlows` so that node being tested can modify flows
2 parents 229c5fb + 547980c commit a04dc2c

File tree

4 files changed

+122
-14
lines changed

4 files changed

+122
-14
lines changed

README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,44 @@ Loads a flow then starts the flow. This function has the following arguments:
314314
* testNode: (object|array of objects) Module object of a node to be tested returned by require function. This node will be registered, and can be used in testFlows.
315315
* testFlow: (array of objects) Flow data to test a node. If you want to use flow data exported from Node-RED editor, export the flow to the clipboard and paste the content into your test scripts.
316316
* testCredentials: (object) Optional node credentials.
317-
* cb: (function) Function to call back when testFlows has been started.
317+
* cb: (function) Function to call back when testFlows has been started (not required when called wih `await`)
318+
319+
### setFlows(testFlow, type, testCredentials, cb)
320+
321+
Updates the currently loaded flow. This function has the following arguments:
322+
323+
* testFlow: (array of objects) Flow data to test a node. If you want to use flow data exported from Node-RED editor, export the flow to the clipboard and paste the content into your test scripts.
324+
* type: (string) Flow data to test a node. If you want to use flow data exported from Node-RED editor, export the flow to the clipboard and paste the content into your test scripts.
325+
* testCredentials: (object) Optional node credentials.
326+
* cb: (function) Function to call back when testFlows has been loaded (not required when called wih `await`)
327+
328+
#### Example
329+
330+
```js
331+
it('should modify the flow then lower case of payload', async function () {
332+
const flow = [
333+
{ id: "n2", type: "helper" }
334+
]
335+
await helper.load(lowerNode, flow)
336+
const newFlow = [...flow]
337+
newFlow.push( { id: "n1", type: "lower-case", name: "lower-case", wires:[['n2']] },)
338+
await helper.setFlows(newFlow, "nodes") //update flows
339+
const n1 = helper.getNode('n1')
340+
n1.should.have.a.property('name', 'lower-case')
341+
await new Promise((resolve, reject) => {
342+
const n2 = helper.getNode('n2')
343+
n2.on('input', function (msg) {
344+
try {
345+
msg.should.have.property('payload', 'hello');
346+
resolve()
347+
} catch (err) {
348+
reject(err);
349+
}
350+
});
351+
n1.receive({ payload: 'HELLO' });
352+
});
353+
});
354+
```
318355

319356
### unload()
320357

examples/lower-case_spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,28 @@ describe('lower-case Node', function () {
5454
n1.receive({ payload: "UpperCase" });
5555
});
5656
});
57+
it('should modify the flow then lower case of payload', async function () {
58+
const flow = [
59+
{ id: "n2", type: "helper" }
60+
]
61+
await helper.load(lowerNode, flow)
62+
63+
const newFlow = [...flow]
64+
newFlow.push( { id: "n1", type: "lower-case", name: "lower-case", wires:[['n2']] },)
65+
await helper.setFlows(newFlow)
66+
const n1 = helper.getNode('n1')
67+
n1.should.have.a.property('name', 'lower-case')
68+
await new Promise((resolve, reject) => {
69+
const n2 = helper.getNode('n2')
70+
n2.on('input', function (msg) {
71+
try {
72+
msg.should.have.property('payload', 'hello');
73+
resolve()
74+
} catch (err) {
75+
reject(err);
76+
}
77+
});
78+
n1.receive({ payload: 'HELLO' });
79+
});
80+
});
5781
});

index.js

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,19 @@ class NodeTestHelper extends EventEmitter {
199199
});
200200

201201

202-
203202
if (typeof testCredentials === 'function') {
204203
cb = testCredentials;
205204
testCredentials = {};
206205
}
207-
208-
var storage = {
206+
const conf = {flows:testFlow,credentials:testCredentials|| {}}
207+
const storage = {
208+
conf: conf,
209209
getFlows: function () {
210-
return Promise.resolve({flows:testFlow,credentials:testCredentials});
210+
return Promise.resolve(conf);
211+
},
212+
saveFlows: function(conf) {
213+
storage.conf = conf;
214+
return Promise.resolve();
211215
}
212216
};
213217
// this._settings.logging = {console:{level:'off'}};
@@ -281,7 +285,7 @@ class NodeTestHelper extends EventEmitter {
281285
unload() {
282286
// TODO: any other state to remove between tests?
283287
this._redNodes.clearRegistry();
284-
this._logSpy.restore();
288+
this._logSpy && this._logSpy.restore();
285289
this._sandbox.restore();
286290

287291
// internal API
@@ -302,6 +306,49 @@ class NodeTestHelper extends EventEmitter {
302306
return this._redNodes.stopFlows();
303307
}
304308

309+
/**
310+
* Update flows
311+
* @param {object|object[]} testFlow Flow data to test a node
312+
* @param {"full"|"flows"|"nodes"} type The type of deploy mode "full", "flows" or "nodes" (defaults to "full")
313+
* @param {object} [testCredentials] Optional node credentials
314+
* @param {function} [cb] Optional callback (not required when called with await)
315+
* @returns {Promise}
316+
*/
317+
setFlows(testFlow, type, testCredentials, cb) {
318+
const helper = this;
319+
if (typeof testCredentials === 'string' ) {
320+
cb = testCredentials;
321+
testCredentials = {};
322+
}
323+
if(!type || typeof type != "string") {
324+
type = "full"
325+
}
326+
async function waitStarted() {
327+
return new Promise((resolve, reject) => {
328+
let timeover = setTimeout(() => {
329+
if (timeover) {
330+
timeover = null
331+
reject(Error("timeout waiting event"))
332+
}
333+
}, 300);
334+
function hander() {
335+
clearTimeout(timeover)
336+
helper._events.off('flows:started', hander)
337+
if (timeover) {
338+
timeover = null
339+
resolve()
340+
}
341+
}
342+
helper._events.on('flows:started', hander); // call resolve when its done
343+
});
344+
}
345+
return this._redNodes.setFlows(testFlow, testCredentials || {}, type)
346+
.then(waitStarted)
347+
.then(() => {
348+
if(cb) cb();
349+
});
350+
}
351+
305352
request() {
306353
return request(this._httpAdmin);
307354
}

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-red-node-test-helper",
3-
"version": "0.2.7",
3+
"version": "0.3.0",
44
"description": "A test framework for Node-RED nodes",
55
"main": "index.js",
66
"scripts": {
@@ -13,18 +13,18 @@
1313
"url": "https://github.com/node-red/node-red-node-test-helper.git"
1414
},
1515
"dependencies": {
16-
"express": "4.17.1",
17-
"body-parser": "1.19.0",
16+
"body-parser": "1.20.0",
17+
"express": "4.18.1",
1818
"read-pkg-up": "7.0.1",
19-
"semver": "7.3.4",
19+
"semver": "7.3.7",
2020
"should": "^13.2.3",
2121
"should-sinon": "0.0.6",
22-
"sinon": "9.2.4",
22+
"sinon": "11.1.2",
2323
"stoppable": "1.1.0",
24-
"supertest": "4.0.2"
24+
"supertest": "6.2.3"
2525
},
2626
"devDependencies": {
27-
"mocha": "~7.1.2"
27+
"mocha": "9.2.2"
2828
},
2929
"contributors": [
3030
{
@@ -46,6 +46,6 @@
4646
"node-red"
4747
],
4848
"engines": {
49-
"node": ">=8"
49+
"node": ">=14"
5050
}
5151
}

0 commit comments

Comments
 (0)