This is a draft version to be reviewed.
Test components
Runtime and nodes test
npm packages
Node-RED uses the following packages for runtime and node testing.
- mocha
- should
- sinon
- supertest
- istanbul
Test directory structure
There are test scripts under test directory (https://github.com/node-red/node-red/tree/master/test).
Test scripts in test/nodes
and test/red
are located in the same hierarchy as the source code in nodes
and red
.
test/resources
is used for storing files that are needed to run a test script. For example, 70-HTML-test-file.html
is used in 70-HTML_spec.js
.
This directory is also used for creating a temporary directory and/or file (e.g. 50-file_spec.js
).
Checking the existence of test cases for core components
test/_spec.js
traverses under a red
directory to check if all .js files have a corresponding _spec.js
test file.
When adding a code in red
directory, the corresponding test file also needs to be created.
Testing environment
When you develop a feature that depends on OS or browser, please test on the following environments according to the modification.
OS
- Linux (Ubuntu, Raspbian, etc.)
- Mac OS X
- Windows
Browser
- Chrome
- Safari
- Internet Explorer
- Firefox
UI test
npm packages
Node-RED uses the following packages for UI testing.
- webdriverio
- mocha
- chromedriver
Test directory structure
Test scripts for UI testing are in test/editor
directory.
Node Test Helper
In the core, there is a helper script for testing a node test/nodes/helper.js
. This has also been made available in a separate module at https://github.com/node-red/node-red-node-test-helper for node contributors to make use of. This module will serve as a node test framework with associated documentation that we aim to improve over time.
When testing a node, it is recommended to use this script. The test-helper can start Node-RED server, load a flow, and receive a payload from the previous node, etc.
Starting a server
helper.startServer
starts a Node-RED server. To start a Node-RED server on each test case:
beforeEach(function(done) {
helper.startServer(done);
});
Loading a flow
helper.load
loads a flow then starts the flow. This function has the following arguments in order.
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 intestFlows
.testFlows
: (array of objects) Flow data to test a node. If you want to use the flow data exported from Node-RED editor, need to covert it to JavaScript object using JSON.parse().testCredentials
: (object) Node credentials. This argument is optional.
Example testCredentials
for node "n1":
{
n1: {
user: "user",
password: "password"
}
}
cb
: (function) Function to call back when testFlows has been started.
The minimum script to test a flow is as follows. This case omits testCredentials
.
var testNode = require("../../../../nodes/core/core/20-inject.js");
it('should be loaded', function(done) {
var testFlows = [{id:"n1", type:"inject"}];
helper.load(testNode, testFlows, function() {
var n1 = helper.getNode("n1");
done();
});
});
Receiving a message
helper.getNode
returns a node instance. Any node that is defined in testFlows
can be retrieved, including helper
node that is automatically registered when a flow is loaded.
Helper node is a mock node with no functionality. By adding "input" event, the helper node can receive a message from the previous node and check if its contents are the expected value.
The following is a sample test case to check a message that is sent from inject
node.
Once the flow is loaded, "n1" inject node sends a message to "n2" helper node. "n2" node receives a message and checks if the payload is correct.
it('should send a message', function(done) {
var testFlows = [
{id:"n1", type:"inject", payload:"hello world!", once: true, wires:[["n2"]] },
{id:"n2", type:"helper"}
];
helper.load(testNode, testFlows, function() {
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('payload', 'hello world!');
done();
});
});
});
Unloading a flow
helper.unload
clears node registration and context, then stops a flow.
Stopping a server
helper.stopServer
stops a Node-RED server.
To unload a flow then stop a server:
afterEach(function(done) {
helper.unload().then(function() {
helper.stopServer(done);
});
});
Helper node for UI test
One important thing to write a UI testing code is that the UI test scripts run synchronously. (This comes from sync
option in wdio.conf.js)
If you need to write an asynchronous code, you need to call browser.call of WebdriverIO API with promise.
Starting a server
helper.startServer
starts a Node-RED server like node-red
command. As the test scripts run in the synchronous manner, to start a Node-RED server:
browser.call(function () {
return when.promise(function(resolve, reject) {
helper.startServer(function() {
resolve();
});
});
});
Stopping a server
helper.stopServer
stops a Node-RED server.
You need to call this function in the same manner of startServer.
Returning a URL
As helper script uses ephemeral port, URL will be changed on each test. So you need to receive a URL when you access to Node-RED.
Testing Node-RED
Running a test
You can run test scripts with grunt
command in the node-red
directory that is cloned from GitHub.
The following table shows the options for this command.
Option | Description |
---|---|
default |
Builds editor content then runs code style checks and unit tests on all components. default means to run grunt command without option. |
test-core |
Runs code style check and unit tests on core runtime code. |
test-editor |
Runs code style check on editor code. |
test-ui |
Builds editor content then runs code style check on editor code and unit tests on editor. |
test-nodes |
Runs unit tests on core nodes. |
clean |
Deletes build outputs |
build |
Builds editor contents |
dev |
Developer mode: runs node-red, watches for source changes and rebuilds/restart |
coverage |
Runs unit tests on all components, and outputs coverage reports. |
release |
Creates distribution zip file - this is the content that will get published to npm when do a release and make available as a zip download via GitHub. |
Testing runtime
Runtime consists of nodes
and red
directories.
When modified these components, the associated test file should be modified or created if not exists.
Running a specific test file
To run only a specific test script, run the following command in the node-red
directory:
npm install -g mocha
mocha test/nodes/core/core/20-inject_spec.js
If you cannot install mocha command globally or you want to run the specific test script, run the following command as an alternative:
node node_modules/mocha/bin/mocha test/nodes/core/core/20-inject_spec.js
Checking a coverage report
If a pull request causes the code coverage to decrease it will be rejected unless there is a good reason provided. To run all test cases and output coverage report:
grunt coverage
Once all tests finished, open index.html
in coverage/lcov-report
directory to see the coverage report.
If the source code that you developed is all covered by your test scripts, it is ok to send a pull request.
Testing editor
To run a UI test scripts, you need to install chrome browser first. Then you need to run npm install chromedriver@2
to install chromedriver. After you installed it, run the command:
grunt test-ui
To test your code by hand, you can run Node-RED with the following command to not minify and uglify scripts so that you can view a code on a browser debugger.
grunt dev
Sending a pull request
After finishing the above procedure, it is ready to send a pull request. Please read Contributing to Node-RED again before sending a pull request.