mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge branch 'dev' into function-modules
This commit is contained in:
@@ -53,6 +53,49 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should send returned message using send()', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"node.send(msg);"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should do something with the catch node', function(done) {
|
||||
var flow = [{"id":"funcNode","type":"function","wires":[["goodNode"]],"func":"node.error('This is an error', msg);"},{"id":"goodNode","type":"helper"},{"id":"badNode","type":"helper"},{"id":"catchNode","type":"catch","scope":null,"uncaught":false,"wires":[["badNode"]]}];
|
||||
var catchNodeModule = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js")
|
||||
helper.load([catchNodeModule, functionNode], flow, function() {
|
||||
var funcNode = helper.getNode("funcNode");
|
||||
var catchNode = helper.getNode("catchNode");
|
||||
var goodNode = helper.getNode("goodNode");
|
||||
var badNode = helper.getNode("badNode");
|
||||
|
||||
badNode.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
msg.should.have.property('error');
|
||||
msg.error.should.have.property('message',"This is an error");
|
||||
msg.error.should.have.property('source');
|
||||
msg.error.source.should.have.property('id', "funcNode");
|
||||
done();
|
||||
});
|
||||
funcNode.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"function", name: "function" }];
|
||||
helper.load(functionNode, flow, function() {
|
||||
@@ -1560,4 +1603,5 @@ describe('function node', function() {
|
||||
});
|
||||
|
||||
})
|
||||
*/
|
||||
});
|
||||
|
@@ -119,13 +119,17 @@ describe('switch Node', function() {
|
||||
* @param done - callback when done
|
||||
*/
|
||||
function customFlowSwitchTest(flow, shouldReceive, sendPayload, done) {
|
||||
customFlowMessageSwitchTest(flow,shouldReceive,{payload: sendPayload}, done);
|
||||
}
|
||||
|
||||
function customFlowMessageSwitchTest(flow, shouldReceive, message, done) {
|
||||
helper.load(switchNode, flow, function() {
|
||||
var switchNode1 = helper.getNode("switchNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
if (shouldReceive === true) {
|
||||
should.equal(msg.payload,sendPayload);
|
||||
should.equal(msg,message);
|
||||
done();
|
||||
} else {
|
||||
should.fail(null, null, "We should never get an input!");
|
||||
@@ -134,7 +138,7 @@ describe('switch Node', function() {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
switchNode1.receive({payload:sendPayload});
|
||||
switchNode1.receive(message);
|
||||
if (shouldReceive === false) {
|
||||
setTimeout(function() {
|
||||
done();
|
||||
@@ -425,6 +429,29 @@ describe('switch Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should use a nested message property to compare value - matches', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload[msg.topic]",rules:[{"t":"eq","v":"bar"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
customFlowMessageSwitchTest(flow, true, {topic:"foo",payload:{"foo":"bar"}}, done);
|
||||
})
|
||||
it('should use a nested message property to compare value - no match', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload[msg.topic]",rules:[{"t":"eq","v":"bar"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
customFlowMessageSwitchTest(flow, false, {topic:"foo",payload:{"foo":"none"}}, done);
|
||||
|
||||
})
|
||||
|
||||
it('should use a nested message property to compare nested message property - matches', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload[msg.topic]",rules:[{"t":"eq","v":"payload[msg.topic2]",vt:"msg"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
customFlowMessageSwitchTest(flow, true, {topic:"foo",topic2:"foo2",payload:{"foo":"bar","foo2":"bar"}}, done);
|
||||
})
|
||||
it('should use a nested message property to compare nested message property - no match', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload[msg.topic]",rules:[{"t":"eq","v":"payload[msg.topic2]",vt:"msg"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
customFlowMessageSwitchTest(flow, false, {topic:"foo",topic2:"foo2",payload:{"foo":"bar","foo2":"none"}}, done);
|
||||
})
|
||||
|
||||
it('should match regex with ignore-case flag set true', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"regex","v":"onetwothree","case":true}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
@@ -98,7 +98,7 @@ describe('change Node', function() {
|
||||
});
|
||||
|
||||
describe('#set' , function() {
|
||||
|
||||
|
||||
it('sets the value of the message property', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","action":"replace","property":"payload","from":"","to":"changed","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
@@ -672,6 +672,111 @@ describe('change Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of a message property using a nested property', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"lookup[msg.topic]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.equal(2);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
changeNode1.receive({payload:"",lookup:{a:1,b:2},topic:"b"});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of a nested message property using a message property', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","name":"","rules":[{"t":"set","p":"lookup[msg.topic]","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.lookup.b.should.equal("newValue");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var msg = {
|
||||
payload: "newValue",
|
||||
lookup:{a:1,b:2},
|
||||
topic:"b"
|
||||
}
|
||||
changeNode1.receive(msg);
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of a message property using a nested property in flow context', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"lookup[msg.topic]","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"wires":[["helperNode1"]],"z":"flow"},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.eql(2);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
changeNode1.context().flow.set("lookup",{a:1, b:2});
|
||||
changeNode1.receive({payload: "", topic: "b"});
|
||||
});
|
||||
})
|
||||
|
||||
it('sets the value of a message property using a nested property in flow context', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"lookup[msg.topic]","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"wires":[["helperNode1"]],"z":"flow"},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.eql(2);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
changeNode1.context().flow.set("lookup",{a:1, b:2});
|
||||
changeNode1.receive({payload: "", topic: "b"});
|
||||
});
|
||||
})
|
||||
|
||||
it('sets the value of a nested flow context property using a message property', function(done) {
|
||||
var flow = [{"id":"changeNode1","type":"change","name":"","rules":[{"t":"set","p":"lookup[msg.topic]","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"wires":[["helperNode1"]],"z":"flow"},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.eql("newValue");
|
||||
changeNode1.context().flow.get("lookup.b").should.eql("newValue");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
changeNode1.context().flow.set("lookup",{a:1, b:2});
|
||||
changeNode1.receive({payload: "newValue", topic: "b"});
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
describe('#change', function() {
|
||||
it('changes the value of the message property', function(done) {
|
||||
|
@@ -1759,13 +1759,13 @@ describe('JOIN node', function() {
|
||||
{ msg: {seq:0, payload:"A", parts:{id:1, type:"string", ch:",", index:0, count:3}}, delay:0, avr:500, var:100},
|
||||
{ msg: {seq:1, payload:"B", parts:{id:1, type:"string", ch:",", index:1, count:3}}, delay:200, avr:500, var:100},
|
||||
{ msg: {seq:2, payload:"dummy", reset: true, parts:{id:1}}, delay:500, avr:500, var:100}
|
||||
]);
|
||||
]);
|
||||
});
|
||||
it('should call done() when timed out', function (done) {
|
||||
mapiDoneJoinTestHelper(done, {mode:"custom", joiner:",", build:"string", timeout:0.5}, [
|
||||
{ msg: {seq:0, payload:"A"}, delay:0, avr:500, var:100},
|
||||
{ msg: {seq:1, payload:"B"}, delay:200, avr:500, var:100},
|
||||
]);
|
||||
]);
|
||||
});
|
||||
it('should call done() when all messages are reduced', function (done) {
|
||||
mapiDoneJoinTestHelper(done, {mode:"reduce", reduceRight:false, reduceExp:"$A+payload", reduceInit:"0",
|
||||
@@ -1785,4 +1785,40 @@ describe('JOIN node', function() {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle msg.parts even if messages are out of order in auto mode if exactly one message has count set', function (done) {
|
||||
var flow = [{ id: "n1", type: "join", wires: [["n2"]], mode: "auto" },
|
||||
{ id: "n2", type: "helper" }];
|
||||
helper.load(joinNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
|
||||
n2.on("input", function (msg) {
|
||||
msg.payload.length.should.be.eql(5);
|
||||
msg.payload.should.be.eql([0,1,2,3,4]);
|
||||
done();
|
||||
});
|
||||
|
||||
var msg = {};
|
||||
msg.parts = {
|
||||
id: RED.util.generateId()
|
||||
};
|
||||
for(var elem = 1; elem < 5; ++elem) {
|
||||
var _msg = RED.util.cloneMessage(msg);
|
||||
_msg.parts.index = elem;
|
||||
if(elem == 4) {
|
||||
_msg.parts.count = 5;
|
||||
}
|
||||
_msg.payload = elem;
|
||||
n1.receive(_msg);
|
||||
}
|
||||
|
||||
var _msg = RED.util.cloneMessage(msg);
|
||||
delete _msg.parts.count;
|
||||
_msg.parts.index = 0;
|
||||
_msg.payload = 0;
|
||||
n1.receive(_msg);
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugin": "winning"
|
||||
}
|
12
test/resources/plugin/test-plugin/package.json
Normal file
12
test/resources/plugin/test-plugin/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "test-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"node-red": {
|
||||
"plugins": {
|
||||
"test": "test.js",
|
||||
"test-editor-plugin": "test-editor-plugin.html",
|
||||
"test-runtime-plugin": "test-runtime-plugin.js"
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
<script type="text/javascript">
|
||||
console.log("Loaded test-plugin/test-editor-plugin")
|
||||
RED.plugins.registerPlugin("my-test-editor-only-plugin", {
|
||||
type: "bar",
|
||||
onadd: function() {
|
||||
console.log("my-test-editor-only-plugin.onadd called")
|
||||
}
|
||||
})
|
||||
</script>
|
10
test/resources/plugin/test-plugin/test-runtime-plugin.js
Normal file
10
test/resources/plugin/test-plugin/test-runtime-plugin.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = function(RED) {
|
||||
console.log("Loaded test-plugin/test-runtime-plugin")
|
||||
|
||||
RED.plugins.registerPlugin("my-test-runtime-only-plugin", {
|
||||
type: "bar",
|
||||
onadd: function() {
|
||||
console.log("my-test-runtime-only-plugin.onadd called")
|
||||
}
|
||||
})
|
||||
}
|
4
test/resources/plugin/test-plugin/test.html
Normal file
4
test/resources/plugin/test-plugin/test.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<script type="text/javascript">
|
||||
console.log("Loaded test-plugin/test")
|
||||
// RED.plugins.registerPlugin("")
|
||||
</script>
|
13
test/resources/plugin/test-plugin/test.js
Normal file
13
test/resources/plugin/test-plugin/test.js
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = function(RED) {
|
||||
console.log("Loaded test-plugin/test")
|
||||
|
||||
RED.plugins.registerPlugin("my-test-plugin", {
|
||||
type: "foo",
|
||||
onadd: function() {
|
||||
console.log("my-test-plugin.onadd called")
|
||||
RED.events.on("registry:plugin-added", function(id) {
|
||||
console.log(`my-test-plugin: plugin-added event "${id}"`)
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
111
test/unit/@node-red/editor-api/lib/admin/plugins_spec.js
Normal file
111
test/unit/@node-red/editor-api/lib/admin/plugins_spec.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const should = require("should");
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
const bodyParser = require("body-parser");
|
||||
|
||||
var app;
|
||||
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
|
||||
var plugins = NR_TEST_UTILS.require("@node-red/editor-api/lib/admin/plugins");
|
||||
|
||||
describe("api/editor/plugins", function() {
|
||||
const pluginList = [
|
||||
{
|
||||
"id": "test-module/test-set",
|
||||
"enabled": true,
|
||||
"local": false,
|
||||
"plugins": [
|
||||
{
|
||||
"type": "foo",
|
||||
"id": "a-plugin",
|
||||
"module": "test-module"
|
||||
},
|
||||
{
|
||||
"type": "bar",
|
||||
"id": "a-plugin2",
|
||||
"module": "test-module"
|
||||
},
|
||||
{
|
||||
"type": "foo",
|
||||
"id": "a-plugin3",
|
||||
"module": "test-module"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "test-module/test-disabled-set",
|
||||
"enabled": false,
|
||||
"local": false,
|
||||
"plugins": []
|
||||
}
|
||||
];
|
||||
const pluginConfigs = `
|
||||
<!-- --- [red-plugin:test-module/test-set] --- -->
|
||||
test-module-config`;
|
||||
|
||||
const pluginCatalogs = { "test-module": {"foo": "bar"}};
|
||||
|
||||
before(function() {
|
||||
app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.get("/plugins",plugins.getAll);
|
||||
app.get("/plugins/messages",plugins.getCatalogs);
|
||||
|
||||
plugins.init({
|
||||
plugins: {
|
||||
getPluginList: async function() { return pluginList },
|
||||
getPluginConfigs: async function() { return pluginConfigs },
|
||||
getPluginCatalogs: async function() { return pluginCatalogs }
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('returns the list of plugins', function(done) {
|
||||
request(app)
|
||||
.get("/plugins")
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
JSON.stringify(res.body).should.eql(JSON.stringify(pluginList));
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
});
|
||||
it('returns the plugin configs', function(done) {
|
||||
request(app)
|
||||
.get("/plugins")
|
||||
.set('Accept', 'text/html')
|
||||
.expect(200)
|
||||
.expect(pluginConfigs)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('returns the plugin catalogs', function(done) {
|
||||
request(app)
|
||||
.get("/plugins/messages")
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
JSON.stringify(res.body).should.eql(JSON.stringify(pluginCatalogs));
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@@ -33,11 +33,11 @@ describe("api/editor/theme", function () {
|
||||
theme.init({settings: {}});
|
||||
fs.statSync.restore();
|
||||
});
|
||||
it("applies the default theme", function () {
|
||||
it("applies the default theme", async function () {
|
||||
var result = theme.init({});
|
||||
should.not.exist(result);
|
||||
|
||||
var context = theme.context();
|
||||
var context = await theme.context();
|
||||
context.should.have.a.property("page");
|
||||
context.page.should.have.a.property("title", "Node-RED");
|
||||
context.page.should.have.a.property("favicon", "favicon.ico");
|
||||
@@ -52,7 +52,7 @@ describe("api/editor/theme", function () {
|
||||
should.not.exist(theme.settings());
|
||||
});
|
||||
|
||||
it("picks up custom theme", function () {
|
||||
it("picks up custom theme", async function () {
|
||||
theme.init({
|
||||
editorTheme: {
|
||||
page: {
|
||||
@@ -104,7 +104,7 @@ describe("api/editor/theme", function () {
|
||||
|
||||
theme.app();
|
||||
|
||||
var context = theme.context();
|
||||
var context = await theme.context();
|
||||
context.should.have.a.property("page");
|
||||
context.page.should.have.a.property("title", "Test Page Title");
|
||||
context.page.should.have.a.property("favicon", "theme/favicon/favicon");
|
||||
|
155
test/unit/@node-red/registry/lib/plugins_spec.js
Normal file
155
test/unit/@node-red/registry/lib/plugins_spec.js
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
const should = require("should");
|
||||
const sinon = require("sinon");
|
||||
const path = require("path");
|
||||
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
|
||||
const plugins = NR_TEST_UTILS.require("@node-red/registry/lib/plugins");
|
||||
const registry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
|
||||
const { events } = NR_TEST_UTILS.require("@node-red/util");
|
||||
|
||||
describe("red/nodes/registry/plugins",function() {
|
||||
let receivedEvents = [];
|
||||
let modules;
|
||||
function handleEvent(evnt) {
|
||||
receivedEvents.push(evnt);
|
||||
}
|
||||
beforeEach(function() {
|
||||
plugins.init({});
|
||||
receivedEvents = [];
|
||||
modules = {
|
||||
"test-module": {
|
||||
plugins: {
|
||||
"test-set": {
|
||||
id: "test-module/test-set",
|
||||
enabled: true,
|
||||
config: "test-module-config",
|
||||
plugins: []
|
||||
},
|
||||
"test-disabled-set": {
|
||||
id: "test-module/test-disabled-set",
|
||||
enabled: false,
|
||||
config: "disabled-plugin-config",
|
||||
plugins: []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
events.on("registry:plugin-added",handleEvent);
|
||||
sinon.stub(registry,"getModule", moduleId => modules[moduleId]);
|
||||
sinon.stub(registry,"getModuleList", () => modules)
|
||||
});
|
||||
afterEach(function() {
|
||||
events.removeListener("registry:plugin-added",handleEvent);
|
||||
registry.getModule.restore();
|
||||
registry.getModuleList.restore();
|
||||
})
|
||||
|
||||
describe("registerPlugin", function() {
|
||||
it("registers a plugin", function() {
|
||||
let pluginDef = {}
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
|
||||
receivedEvents.length.should.eql(1);
|
||||
receivedEvents[0].should.eql("a-plugin");
|
||||
should.exist(modules['test-module'].plugins['test-set'].plugins[0])
|
||||
modules['test-module'].plugins['test-set'].plugins[0].should.equal(pluginDef)
|
||||
})
|
||||
it("calls a plugins onadd function", function() {
|
||||
let pluginDef = { onadd: sinon.stub() }
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
|
||||
pluginDef.onadd.called.should.be.true();
|
||||
})
|
||||
})
|
||||
|
||||
describe("getPlugin", function() {
|
||||
it("returns a registered plugin", function() {
|
||||
let pluginDef = {}
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
|
||||
pluginDef.should.equal(plugins.getPlugin("a-plugin"));
|
||||
})
|
||||
})
|
||||
describe("getPluginsByType", function() {
|
||||
it("returns a plugins of a given type", function() {
|
||||
let pluginDef = {type: "foo"}
|
||||
let pluginDef2 = {type: "bar"}
|
||||
let pluginDef3 = {type: "foo"}
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
|
||||
|
||||
let fooPlugins = plugins.getPluginsByType("foo");
|
||||
let barPlugins = plugins.getPluginsByType("bar");
|
||||
let noPlugins = plugins.getPluginsByType("none");
|
||||
|
||||
noPlugins.should.be.of.length(0);
|
||||
|
||||
fooPlugins.should.be.of.length(2);
|
||||
fooPlugins.should.containEql(pluginDef);
|
||||
fooPlugins.should.containEql(pluginDef3);
|
||||
|
||||
barPlugins.should.be.of.length(1);
|
||||
barPlugins.should.containEql(pluginDef2);
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe("getPluginConfigs", function() {
|
||||
it("gets all plugin configs", function() {
|
||||
let configs = plugins.getPluginConfigs("en-US");
|
||||
configs.should.eql(`
|
||||
<!-- --- [red-plugin:test-module/test-set] --- -->
|
||||
test-module-config`)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe("getPluginList", function() {
|
||||
it("returns a plugins of a given type", function() {
|
||||
let pluginDef = {type: "foo"}
|
||||
let pluginDef2 = {type: "bar"}
|
||||
let pluginDef3 = {type: "foo"}
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
|
||||
plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
|
||||
|
||||
let pluginList = plugins.getPluginList();
|
||||
JSON.stringify(pluginList).should.eql(JSON.stringify(
|
||||
[
|
||||
{
|
||||
"id": "test-module/test-set",
|
||||
"enabled": true,
|
||||
"local": false,
|
||||
"user": false,
|
||||
"plugins": [
|
||||
{
|
||||
"type": "foo",
|
||||
"id": "a-plugin",
|
||||
"module": "test-module"
|
||||
},
|
||||
{
|
||||
"type": "bar",
|
||||
"id": "a-plugin2",
|
||||
"module": "test-module"
|
||||
},
|
||||
{
|
||||
"type": "foo",
|
||||
"id": "a-plugin3",
|
||||
"module": "test-module"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "test-module/test-disabled-set",
|
||||
"enabled": false,
|
||||
"local": false,
|
||||
"user": false,
|
||||
"plugins": []
|
||||
}
|
||||
]
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
});
|
68
test/unit/@node-red/runtime/lib/api/plugins_spec.js
Normal file
68
test/unit/@node-red/runtime/lib/api/plugins_spec.js
Normal file
@@ -0,0 +1,68 @@
|
||||
const should = require("should");
|
||||
const sinon = require("sinon");
|
||||
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
const plugins = NR_TEST_UTILS.require("@node-red/runtime/lib/api/plugins")
|
||||
|
||||
const mockLog = () => ({
|
||||
log: sinon.stub(),
|
||||
debug: sinon.stub(),
|
||||
trace: sinon.stub(),
|
||||
warn: sinon.stub(),
|
||||
info: sinon.stub(),
|
||||
metric: sinon.stub(),
|
||||
audit: sinon.stub(),
|
||||
_: function() { return "abc"}
|
||||
})
|
||||
|
||||
describe("runtime-api/plugins", function() {
|
||||
const pluginList = [{id:"one",module:'test-module'},{id:"two",module:"node-red"}];
|
||||
const pluginConfigs = "123";
|
||||
|
||||
describe("getPluginList", function() {
|
||||
it("gets the plugin list", function() {
|
||||
plugins.init({
|
||||
log: mockLog(),
|
||||
plugins: {
|
||||
getPluginList: function() { return pluginList}
|
||||
}
|
||||
});
|
||||
return plugins.getPluginList({}).then(function(result) {
|
||||
result.should.eql(pluginList);
|
||||
})
|
||||
});
|
||||
});
|
||||
describe("getPluginConfigs", function() {
|
||||
it("gets the plugin configs", function() {
|
||||
plugins.init({
|
||||
log: mockLog(),
|
||||
plugins: {
|
||||
getPluginConfigs: function() { return pluginConfigs}
|
||||
}
|
||||
});
|
||||
return plugins.getPluginConfigs({}).then(function(result) {
|
||||
result.should.eql(pluginConfigs);
|
||||
})
|
||||
});
|
||||
});
|
||||
describe("getPluginCatalogs", function() {
|
||||
it("gets the plugin catalogs", function() {
|
||||
plugins.init({
|
||||
log: mockLog(),
|
||||
plugins: {
|
||||
getPluginList: function() { return pluginList}
|
||||
},
|
||||
i18n: {
|
||||
i: {
|
||||
changeLanguage: function(lang,done) { done && done() },
|
||||
getResourceBundle: function(lang, id) { return {lang,id}}
|
||||
}
|
||||
}
|
||||
});
|
||||
return plugins.getPluginCatalogs({lang: "en-US"}).then(function(result) {
|
||||
JSON.stringify(result).should.eql(JSON.stringify({ one: { lang: "en-US", id: "one" } }))
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
});
|
13
test/unit/@node-red/runtime/lib/plugins_spec.js
Normal file
13
test/unit/@node-red/runtime/lib/plugins_spec.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const should = require("should");
|
||||
const sinon = require("sinon");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
|
||||
const plugins = NR_TEST_UTILS.require("@node-red/runtime/lib/plugins");
|
||||
|
||||
describe("runtime/plugins",function() {
|
||||
|
||||
it.skip("delegates all functions to registry module", function() {
|
||||
// There's no easy way to test this as we can't stub the registry functions
|
||||
// before the plugin module gets a reference to them
|
||||
})
|
||||
});
|
@@ -164,6 +164,13 @@ describe("@node-red/util/util", function() {
|
||||
var v2 = util.getMessageProperty({a:"foo"},"a");
|
||||
v2.should.eql("foo");
|
||||
});
|
||||
it('retrieves a nested property', function() {
|
||||
var v = util.getMessageProperty({a:"foo",b:{foo:1,bar:2}},"msg.b[msg.a]");
|
||||
v.should.eql(1);
|
||||
var v2 = util.getMessageProperty({a:"bar",b:{foo:1,bar:2}},"b[msg.a]");
|
||||
v2.should.eql(2);
|
||||
});
|
||||
|
||||
it('should return undefined if property does not exist', function() {
|
||||
var v = util.getMessageProperty({a:"foo"},"msg.b");
|
||||
should.not.exist(v);
|
||||
@@ -331,7 +338,18 @@ describe("@node-red/util/util", function() {
|
||||
msg.a[0].should.eql(1);
|
||||
msg.a[1].should.eql(3);
|
||||
})
|
||||
|
||||
it('handles nested message property references', function() {
|
||||
var obj = {a:"foo",b:{}};
|
||||
var result = util.setObjectProperty(obj,"b[msg.a]","bar");
|
||||
result.should.be.true();
|
||||
obj.b.should.have.property("foo","bar");
|
||||
});
|
||||
it('handles nested message property references', function() {
|
||||
var obj = {a:"foo",b:{"foo":[0,0,0]}};
|
||||
var result = util.setObjectProperty(obj,"b[msg.a][2]","bar");
|
||||
result.should.be.true();
|
||||
obj.b.foo.should.eql([0,0,"bar"])
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluateNodeProperty', function() {
|
||||
@@ -459,13 +477,24 @@ describe("@node-red/util/util", function() {
|
||||
// console.log(result);
|
||||
result.should.eql(expected);
|
||||
}
|
||||
|
||||
function testInvalid(input) {
|
||||
function testABCWithMessage(input,msg,expected) {
|
||||
var result = util.normalisePropertyExpression(input,msg);
|
||||
// console.log("+",input);
|
||||
// console.log(result);
|
||||
result.should.eql(expected);
|
||||
}
|
||||
function testInvalid(input,msg) {
|
||||
/*jshint immed: false */
|
||||
(function() {
|
||||
util.normalisePropertyExpression(input);
|
||||
util.normalisePropertyExpression(input,msg);
|
||||
}).should.throw();
|
||||
}
|
||||
function testToString(input,msg,expected) {
|
||||
var result = util.normalisePropertyExpression(input,msg,true);
|
||||
console.log("+",input);
|
||||
console.log(result);
|
||||
result.should.eql(expected);
|
||||
}
|
||||
it('pass a.b.c',function() { testABC('a.b.c',['a','b','c']); })
|
||||
it('pass a["b"]["c"]',function() { testABC('a["b"]["c"]',['a','b','c']); })
|
||||
it('pass a["b"].c',function() { testABC('a["b"].c',['a','b','c']); })
|
||||
@@ -479,12 +508,25 @@ describe("@node-red/util/util", function() {
|
||||
it("pass 'a.b'[1]",function() { testABC("'a.b'[1]",['a.b',1]); })
|
||||
it("pass 'a.b'.c",function() { testABC("'a.b'.c",['a.b','c']); })
|
||||
|
||||
it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
|
||||
it("pass a[msg[msg.b]]",function() { testABC("a[msg[msg.b]]",["a",["msg",["msg","b"]]]); })
|
||||
it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
|
||||
it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
|
||||
it("pass a[msg['b]\"[']]",function() { testABC("a[msg['b]\"[']]",["a",["msg","b]\"["]]); })
|
||||
it("pass a[msg['b][']]",function() { testABC("a[msg['b][']]",["a",["msg","b]["]]); })
|
||||
it("pass b[msg.a][2]",function() { testABC("b[msg.a][2]",["b",["msg","a"],2])})
|
||||
|
||||
it("pass b[msg.a][2] (with message)",function() { testABCWithMessage("b[msg.a][2]",{a: "foo"},["b","foo",2])})
|
||||
|
||||
it('pass a.$b.c',function() { testABC('a.$b.c',['a','$b','c']); })
|
||||
it('pass a["$b"].c',function() { testABC('a["$b"].c',['a','$b','c']); })
|
||||
it('pass a._b.c',function() { testABC('a._b.c',['a','_b','c']); })
|
||||
it('pass a["_b"].c',function() { testABC('a["_b"].c',['a','_b','c']); })
|
||||
|
||||
it("pass a['a.b[0]'].c",function() { testToString("a['a.b[0]'].c",null,'a["a.b[0]"]["c"]'); })
|
||||
it("pass a.b.c",function() { testToString("a.b.c",null,'a["b"]["c"]'); })
|
||||
it('pass a[msg.c][0]["fred"]',function() { testToString('a[msg.c][0]["fred"]',{c:"123"},'a["123"][0]["fred"]'); })
|
||||
|
||||
it("fail a'b'.c",function() { testInvalid("a'b'.c"); })
|
||||
it("fail a['b'.c",function() { testInvalid("a['b'.c"); })
|
||||
it("fail a[]",function() { testInvalid("a[]"); })
|
||||
@@ -505,6 +547,12 @@ describe("@node-red/util/util", function() {
|
||||
it("fail a['']",function() { testInvalid("a['']"); })
|
||||
it("fail 'a.b'c",function() { testInvalid("'a.b'c"); })
|
||||
it("fail <blank>",function() { testInvalid("");})
|
||||
it("fail a[b]",function() { testInvalid("a[b]"); })
|
||||
it("fail a[msg.]",function() { testInvalid("a[msg.]"); })
|
||||
it("fail a[msg[]",function() { testInvalid("a[msg[]"); })
|
||||
it("fail a[msg.[]]",function() { testInvalid("a[msg.[]]"); })
|
||||
it("fail a[msg['af]]",function() { testInvalid("a[msg['af]]"); })
|
||||
it("fail b[msg.undefined][2] (with message)",function() { testInvalid("b[msg.undefined][2]",{})})
|
||||
|
||||
});
|
||||
|
||||
@@ -983,4 +1031,5 @@ describe("@node-red/util/util", function() {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user