Promises and node-red-node-test-helper

Should promises be implemented in the test helper, so node developers are free to choose callback-based or ES2017 async/await syntax?

I was a little annoyed that the test helper is callback-based, specially considering it has one method that returns a promise. I tried making a version that calls callbacks, but also returns a promise. And it works really well for me, it solves several problems:

  • No increasing indentation for each call to an async function
  • No worries about forgetting to catch an error in a callback
  • More linear execution of code (the line that sends a message is now above the line that receives it)

Example:

it('should make payload lower case',function(done) {
    var flow = [
        {id:"n1",type:"lower-case",name:"test name",wires:[["n2"]]},
        {id:"n2",type:"helper"}
    ];
    helper.load(lowerNode,flow,function() {
        var n2 = helper.getNode("n2");
        var n1 = helper.getNode("n1");
        n2.on("input",function(msg) {
            try {
                msg.should.have.property('payload','uppercase');
                done();
            } catch (e) {
                done(e);
            }
        });
        n1.receive({payload:"UpperCase"});
    });
});

is now

it('should make payload lower case',async function() {
    var flow = [
        {id:"n1",type:"lower-case",name:"test name",wires:[["n2"]]},
        {id:"n2",type:"helper"}
    ];
    await helper.load(lowerNode,flow);
    var n2 = helper.getNode("n2");
    var n1 = helper.getNode("n1");

    n1.receive({payload:"UpperCase"});
    let msg = await n2.next("input");
    msg.should.have.property('payload','uppercase');
});

You can try my version by changing your devDependency in package.json to:

"node-red-node-test-helper": "github:myplacedk/node-red-node-test-helper#async",

(and of course npm install)

I didn't document it yet, but I just made every method that takes a callback also return a promise. And I added a "next"-method that can be used as an alternative to "on". Events are queued, so you can process them linearly. If an event isn't in queue, "next" will wait until there's an event. If the event is "input", you'll get a clone of the message, just in case the message is changed during the flow.

Source: https://github.com/myplacedk/node-red-node-test-helper/tree/async

Changes in index.js: https://github.com/node-red/node-red-node-test-helper/compare/master...myplacedk:async?expand=1#diff-168726dbe96b3ce427e7fedce31bb0bc

Matching unit-test: https://github.com/node-red/node-red-node-test-helper/compare/master...myplacedk:async?expand=1#diff-fa77609e9ad7e21848f3e1b660d1ee26

Examples: https://github.com/myplacedk/node-red-node-test-helper/commit/73f154fd480130eb51ed51888a25a3d4d9851be3?diff=split&w=1

Right now, Node-RED still supports node 4 so we can't use async functions yet.

The 0.20 release drops node 4 and 6 support so we could contemplate this change once that's done.

It doesn't need to use async functions. I can change that so it just returns a Promise. Developers are then free to use ES2017 in their projects.

Fixed, "async" is no longer used in index.js.

Hi @myplacedk

thanks. That makes sense. If you wanted to open a pull-request with your proposed changes we can review them properly.

I'm on holiday this week moving house. I won't be online very much and after Wednesday, at best, only from my mobile. So I won't be doing any substantial code reviews until the week after.

I updated README, moved to Github and made a PR.