Node-RED Node Test Helper
The Node-RED Node Test Helper is a comprehensive framework designed for unit testing Node-RED nodes and flows. It enables developers to start a dedicated Node-RED runtime instance within their test environment, load specific test flows, and simulate message injection and reception to verify node behavior. The current stable version is 0.3.6, with regular maintenance updates including dependency bumps and minor feature enhancements. This helper differentiates itself by integrating directly with the Node-RED runtime, providing a realistic testing environment that goes beyond simple JavaScript unit tests, ensuring nodes function correctly within the flow-based programming paradigm. It is an essential tool for maintaining the quality and reliability of custom Node-RED nodes.
Common errors
-
Error: Cannot find module 'node-red' from '<your-project-path>'
cause The `node-red` package, a peer dependency, has not been installed alongside `node-red-node-test-helper`.fixRun `npm install node-red node-red-node-test-helper --save-dev` to ensure both packages are available in your project. -
Test timeout of 2000ms exceeded. Ensure the done() callback is being called.
cause An assertion inside an asynchronous callback (e.g., `n2.on('input', ...)`) failed, but the error was not propagated, preventing `done()` from being called, or `done()` was never called.fixWrap assertions in a `try...catch` block and call `done(err)` on error, or `reject(err)` if using promises, to properly report failures and complete the test. -
TypeError: helper.startServer is not a function (or similar for other async methods)
cause Attempting to call an asynchronous helper method without awaiting it in an `async` function, or potentially using an outdated version where the method signature changed.fixEnsure your test functions (e.g., `beforeEach`, `afterEach`, `it`) are declared `async` and use `await` before calling helper methods like `helper.startServer()`. -
Node-RED requires Node.js version >= 14
cause The current Node.js version in your environment is older than the minimum required by `node-red-node-test-helper` (and Node-RED itself since v0.3.0 of the helper).fixUpdate your Node.js installation to version 14 or newer. You can use a tool like NVM (Node Version Manager) to manage multiple Node.js versions.
Warnings
- breaking Version 0.3.0 and above of `node-red-node-test-helper` requires Node.js version 14 or higher. Running tests with older Node.js versions will result in runtime errors.
- gotcha Node-RED runtime inherently swallows exceptions that occur within a flow. When writing unit tests, assertion failures inside `n2.on('input', ...)` callbacks will not automatically fail the test; they will simply cause a timeout. You must explicitly catch errors and pass them to your test runner's `done` callback or reject a Promise.
- gotcha The `node-red` package is a peer dependency and must be installed alongside `node-red-node-test-helper`. Failure to do so will result in `Cannot find module 'node-red'` errors during helper initialization.
- gotcha Asynchronous methods like `startServer`, `stopServer`, `load`, and `setFlows` were updated in version 0.3.5 to be fully async/await compatible. While older synchronous calls might still function, it's best practice to `await` these operations in your tests to prevent race conditions and ensure proper test execution, especially with newer test runners like Vitest.
Install
-
npm install node-red-node-test-helper -
yarn add node-red-node-test-helper -
pnpm add node-red-node-test-helper
Imports
- helper
import { helper } from 'node-red-node-test-helper';import helper from 'node-red-node-test-helper';
- require ('node-red-node-test-helper')
const helper = require('node-red-node-test-helper'); - init
helper.init();
helper.init(require.resolve('node-red'));
Quickstart
import helper from 'node-red-node-test-helper';
import should from 'should';
import path from 'path';
// Assuming your node is in ../my-awesome-node.js relative to the test file
const myAwesomeNode = require(path.resolve(__dirname, '../my-awesome-node.js'));
// Initialize the helper to locate the Node-RED runtime
helper.init(require.resolve('node-red'));
describe('My Awesome Node', function () {
beforeEach(async function () {
await helper.startServer();
});
afterEach(async function () {
await helper.unload();
await helper.stopServer();
});
it('should be loaded correctly', async function () {
const flow = [{ id: 'n1', type: 'my-awesome-node', name: 'test node' }];
await helper.load(myAwesomeNode, flow);
const n1 = helper.getNode('n1');
n1.should.have.property('name', 'test node');
});
it('should process input and send expected output', async function () {
const flow = [
{ id: 'n1', type: 'my-awesome-node', name: 'test node', wires:[['n2']] },
{ id: 'n2', type: 'helper' }
];
await helper.load(myAwesomeNode, flow);
const n2 = helper.getNode('n2');
const n1 = helper.getNode('n1');
const promise = new Promise((resolve, reject) => {
n2.on('input', function (msg) {
try {
msg.should.have.property('payload', 'processed value');
resolve();
} catch(err) {
reject(err);
}
});
});
n1.receive({ payload: 'initial value' });
await promise;
});
});