Skip to content

Commit

Permalink
Merge pull request #10 from mblackstock/init-runtime-path
Browse files Browse the repository at this point in the history
add helper.init() call to supply NR runtime path
  • Loading branch information
mblackstock authored Apr 12, 2018
2 parents 1a8e8a2 + e960c2d commit c8b1c6f
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 70 deletions.
48 changes: 10 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,21 @@ Using the test-helper, your tests can start the Node-RED runtime, load a test fl

## Adding to your node project dependencies

To add unit tests your node project test dependencies, add this test helper as follows:
Node-RED is required by the helper as a peer dependency, meaning it must be installed along with the helper itself. To create unit tests for your node project, add this test helper and Node-RED as follows:

npm install node-red-node-test-helper --save-dev
npm install node-red-node-test-helper node-red --save-dev

This will add the helper module to your `package.json` file as a development dependency:
This will add the helper module to your `package.json` file:

```json
...
"devDependencies": {
"node-red":"^0.18.4",
"node-red-node-test-helper": "^0.1.6"
}
...
```

The test-helper requires the node-red runtime to run its tests, but Node-RED is **not** installed as a dependency. The reason for this is that test-helper is (or will be) used in Node-RED core tests, and Node-RED itself has a large number of dependencies that you may not want to download if you already have it installed.

You can install the Node-RED runtime available for your unit tests one of two ways:

1. as a dev dependency in your project:

```
npm install node-red --save-dev
```

2. or link to Node-RED installed globally (recommended) using:

```
npm install -g node-red
npm link node-red
```

Both [Mocha](https://mochajs.org/) and [Should](https://shouldjs.github.io/) will be pulled in with the test helper. Mocha is a unit test framework for Javascript; Should is an assertion library. For more information on these frameworks, see their associated documentation.

## Linking to additional test dependencies

To reduce disk use further, you can install the test-helper and additional dev dependencies globally and then link them to your node project. This may be a better option especially if you are developing more than one node.

See the `package.json` file for the additional dependencies used by test-helper.

For example to install express globally:

npm install -g express

Then link to it in your project:

npm link express

Depending on the nodes in your test flow, you may also want to link to other global packages. If a test indicates that a package cannot be found, and you expect to need it for testing other nodes, consider installing the package globally and then linking it to your node project the same way.

## Adding test script to `package.json`

To run your tests you can add a test script to your `package.json` file in the `scripts` section. To run all of the files with the `_spec.js` prefix in the test directory for example:
Expand Down Expand Up @@ -84,6 +50,8 @@ var should = require("should");
var helper = require("node-red-node-test-helper");
var lowerNode = require("../lower-case.js");

helper.init(require.resolve('node-red'));

describe('lower-case Node', function () {

afterEach(function () {
Expand Down Expand Up @@ -121,6 +89,10 @@ In this example, we require `should` for assertions, this helper module, as well

We then have a set of mocha unit tests. These tests check that the node loads correctly, and ensures it makes the payload string lower case as expected.

## Initializing Helper

To get started, we need to tell the helper where to find the node-red runtime. this is done by calling `helper.init(require.resolve('node-red'))` as shown.

## Getting nodes in the runtime

The asynchronous `helper.load()` method calls the supplied callback function once the Node-RED server and runtime is ready. We can then call the `helper.getNode(id)` method to get a reference to nodes in the runtime. For more information on these methods see the API section below.
Expand Down
2 changes: 2 additions & 0 deletions examples/comment_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

var should = require("should");
var helper = require("../index.js");
helper.init(require.resolve('node-red'));

var commentNode = require("./nodes/90-comment.js");

describe('comment Node', function() {
Expand Down
1 change: 1 addition & 0 deletions examples/function_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

var should = require("should");
var helper = require("../index.js");
helper.init(require.resolve('node-red'));

var functionNode = require("./nodes/80-function.js");

Expand Down
2 changes: 2 additions & 0 deletions examples/lower-case_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ var should = require("should");
var helper = require("../index.js");
var lowerNode = require("./nodes/lower-case.js");

helper.init(require.resolve('node-red'));

describe('lower-case Node', function () {

afterEach(function () {
Expand Down
83 changes: 54 additions & 29 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,59 @@
* limitations under the License.
**/

var path = require("path");
var should = require("should");
var sinon = require("sinon");
var when = require("when");
var request = require('supertest');
var express = require("express");
var http = require('http');
var stoppable = require('stoppable');
const readPkgUp = require('read-pkg-up');

var RED;
var redNodes;
var flows;
var comms;
var log;
var context;
var events;

var runtimePath;
var package = readPkgUp.sync();
if (package.pkg.name === 'node-red') {
runtimePath = path.join(process.cwd(),package.pkg.main);
initRuntime(runtimePath);
} else {
try {
runtimePath = require.resolve('node-red');
initRuntime(runtimePath);
} catch (err) {
// no runtime path - init must be called from test
}
}

function initRuntime(requirePath) {

try {
RED = require(requirePath);

try {
var RED = require('node-red');
var redNodes = require("node-red/red/runtime/nodes");
var flows = require("node-red/red/runtime/nodes/flows");
var credentials = require("node-red/red/runtime/nodes/credentials");
var comms = require("node-red/red/api/editor/comms.js");
var log = require("node-red/red/runtime/log.js");
var context = require("node-red/red/runtime/nodes/context.js");
var events = require('node-red/red/runtime/events');
} catch (err) {
// no node-red in helper-test dependencies so assume we're testing node-red
var nrPath = process.cwd();
var RED = require(nrPath+"/red/red.js");
var redNodes = require(nrPath+"/red/runtime/nodes");
var flows = require(nrPath+"/red/runtime/nodes/flows");
var credentials = require(nrPath+"/red/runtime/nodes/credentials");
var comms = require(nrPath+"/red/api/editor/comms.js");
var log = require(nrPath+"/red/runtime/log.js");
var context = require(nrPath+"/red/runtime/nodes/context.js");
var events = require(nrPath+"/red/runtime/events.js");
// public runtime API
redNodes = RED.nodes;
events = RED.events;
log = RED.log;

// access internal Node-RED runtime methods
var prefix = requirePath.substring(0, requirePath.indexOf('/red.js'));
context = require(prefix+"/runtime/nodes/context");
comms = require(prefix+"/api/editor/comms");
} catch (err) {
// ignore, assume init will be called again by a test script supplying the runtime path
}
}

initRuntime(runtimePath);

var app = express();

var address = '127.0.0.1';
Expand All @@ -58,6 +81,7 @@ function helperNode(n) {
}

module.exports = {
init: initRuntime,
load: function(testNode, testFlow, testCredentials, cb) {
var i;

Expand Down Expand Up @@ -98,17 +122,17 @@ module.exports = {
};

redNodes.init({events:events,settings:settings, storage:storage,log:log,});
RED.nodes.registerType("helper", helperNode);
redNodes.registerType("helper", helperNode);
if (Array.isArray(testNode)) {
for (i = 0; i < testNode.length; i++) {
testNode[i](red);
}
} else {
testNode(red);
}
flows.load().then(function() {
flows.startFlows();
should.deepEqual(testFlow, flows.getFlows().flows);
redNodes.loadFlows().then(function() {
redNodes.startFlows();
should.deepEqual(testFlow, redNodes.getFlows().flows);
cb();
});
},
Expand All @@ -117,18 +141,17 @@ module.exports = {
// TODO: any other state to remove between tests?
redNodes.clearRegistry();
logSpy.restore();
// internal API
context.clean({allNodes:[]});
return flows.stopFlows();
return redNodes.stopFlows();
},

getNode: function(id) {
return flows.get(id);
return redNodes.getNode(id);
},

credentials: credentials,

clearFlows: function() {
return flows.stopFlows();
return redNodes.stopFlows();
},

request: function() {
Expand All @@ -146,6 +169,7 @@ module.exports = {
server.on('listening', function() {
port = server.address().port;
url = 'http://' + address + ':' + port;
// internal API
comms.start();
done();
});
Expand All @@ -155,6 +179,7 @@ module.exports = {
stopServer: function(done) {
if (server) {
try {
// internal API
comms.stop();
server.stop(done);
} catch(e) {
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
},
"dependencies": {
"express": "4.16.2",
"should": "^8.4.0",
"read-pkg-up": "3.0.0",
"should": "8.4.0",
"sinon": "1.17.7",
"stoppable": "1.0.6",
"supertest": "3.0.0",
"stoppable": "boneskull/stoppable#boneskull-patch-1",
"when": "3.7.8"
},
"peerDependencies": {
"node-red": "0.18.x"
"node-red": "~0.18.4"
},
"devDependencies": {
"mocha": "~5.0.4"
Expand Down

0 comments on commit c8b1c6f

Please sign in to comment.