mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
upstream merge
This commit is contained in:
592
test/nodes/core/network/22-websocket_spec.js
Normal file
592
test/nodes/core/network/22-websocket_spec.js
Normal file
@@ -0,0 +1,592 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var ws = require("ws");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var websocketNode = require("nr-test-utils").require("@node-red/nodes/core/network/22-websocket.js");
|
||||
|
||||
var sockets = [];
|
||||
|
||||
function getWsUrl(path) {
|
||||
return helper.url().replace(/http/, "ws") + path;
|
||||
}
|
||||
|
||||
function createClient(listenerid) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var node = helper.getNode(listenerid);
|
||||
var url = getWsUrl(node.path);
|
||||
var sock = new ws(url);
|
||||
sockets.push(sock);
|
||||
|
||||
sock.on("open", function() {
|
||||
resolve(sock);
|
||||
});
|
||||
|
||||
sock.on("error", function(err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
for (var i = 0; i < sockets.length; i++) {
|
||||
sockets[i].close();
|
||||
}
|
||||
sockets = [];
|
||||
}
|
||||
|
||||
function getSocket(listenerid) {
|
||||
var node = helper.getNode(listenerid);
|
||||
return node.server;
|
||||
}
|
||||
|
||||
describe('websocket Node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
closeAll();
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
describe('websocket-listener', function() {
|
||||
it('should load', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("path", "/ws");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be server', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('isServer', true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wholemsg property', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-listener", path: "/ws2", wholemsg: "true" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("wholemsg", false);
|
||||
helper.getNode("n2").should.have.property("wholemsg", true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create socket', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
done();
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should close socket on delete', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("close", function(code, msg) {
|
||||
done();
|
||||
});
|
||||
helper.clearFlows();
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive data', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
sock.send("hello");
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.send('{"text":"hello"}');
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not JSON', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.send('hello');
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not object', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", 123);
|
||||
done();
|
||||
});
|
||||
sock.send(123);
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "helper", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
helper.getNode("n2").send({
|
||||
payload: "hello"
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket out", server: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
helper.getNode("n3").send({
|
||||
text: "hello"
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing if no payload', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "helper", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "file";
|
||||
});
|
||||
logEvents.should.have.length(0);
|
||||
done();
|
||||
},100);
|
||||
helper.getNode("n2").send({topic: "hello"});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should echo', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
sock.send("hello");
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should echo wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
sock.send('{"text":"hello"}');
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should broadcast', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket out", server: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
Promise.all([createClient("n1"), createClient("n1")]).then(function(socks) {
|
||||
var promises = [
|
||||
new Promise((resolve,reject) => {
|
||||
socks[0].on("message", function(msg, flags) {
|
||||
try {
|
||||
msg.should.equal("hello");
|
||||
resolve();
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}),
|
||||
new Promise((resolve,reject) => {
|
||||
socks[1].on("message", function(msg, flags) {
|
||||
try {
|
||||
msg.should.equal("hello");
|
||||
resolve();
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
})
|
||||
];
|
||||
helper.getNode("n3").send({
|
||||
payload: "hello"
|
||||
});
|
||||
return Promise.all(promises).then(() => {done()});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket-client', function() {
|
||||
it('should load', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('path', getWsUrl("/ws"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not be server', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('isServer', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wholemsg property', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("wholemsg", false);
|
||||
helper.getNode("n2").should.have.property("wholemsg", true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle protocol property', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws"), subprotocol: "testprotocol1, testprotocol2" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("subprotocol", []);
|
||||
helper.getNode("n2").should.have.property("subprotocol", ["testprotocol1","testprotocol2"]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should connect to server', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('should initiate with subprotocol', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws"), subprotocol: "testprotocol" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function (sock) {
|
||||
sock.should.have.property("protocol", "testprotocol")
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should close on delete', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('close', function() {
|
||||
done();
|
||||
});
|
||||
helper.getNode("n2").close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive data', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('hello');
|
||||
});
|
||||
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg data ', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('{"text":"hello"}');
|
||||
});
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not JSON', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('hello');
|
||||
});
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on("open", function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: "hello"
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send buffer', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
Buffer.isBuffer(msg).should.be.true();
|
||||
msg.should.have.length(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on("open", function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: Buffer.from("hello")
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on('open', function(){
|
||||
helper.getNode("n3").send({
|
||||
text: "hello"
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT feedback more than once', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "client", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n1", type: "websocket in", client: "client", wires: [["n2", "output"]] },
|
||||
{ id: "n2", type: "websocket out", server: "server" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] },
|
||||
{ id: "output", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('client').on('open', function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: "ping"
|
||||
});
|
||||
});
|
||||
var acc = 0;
|
||||
helper.getNode("output").on("input", function(msg) {
|
||||
acc = acc + 1;
|
||||
});
|
||||
setTimeout( function() {
|
||||
acc.should.equal(1);
|
||||
helper.clearFlows();
|
||||
done();
|
||||
}, 250);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket in node', function() {
|
||||
it('should report error if no server config', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket in", mode: "server" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "websocket in";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("websocket.errors.missing-conf");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket out node', function() {
|
||||
it('should report error if no server config', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket out", mode: "server" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "websocket out";
|
||||
});
|
||||
//console.log(logEvents);
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("websocket.errors.missing-conf");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
340
test/nodes/core/network/31-tcprequest_spec.js
Normal file
340
test/nodes/core/network/31-tcprequest_spec.js
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var net = require("net");
|
||||
var should = require("should");
|
||||
var stoppable = require('stoppable');
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var tcpinNode = require("nr-test-utils").require("@node-red/nodes/core/network/31-tcpin.js");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red.js");
|
||||
|
||||
|
||||
describe('TCP Request Node', function() {
|
||||
var server = undefined;
|
||||
var port = 9000;
|
||||
|
||||
function startServer(done) {
|
||||
port += 1;
|
||||
server = stoppable(net.createServer(function(c) {
|
||||
c.on('data', function(data) {
|
||||
var rdata = "ACK:"+data.toString();
|
||||
c.write(rdata);
|
||||
});
|
||||
c.on('error', function(err) {
|
||||
startServer(done);
|
||||
});
|
||||
})).listen(port, "127.0.0.1", function(err) {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
server.stop(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
function testTCP(flow, val0, val1, done) {
|
||||
helper.load(tcpinNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (typeof val1 === 'object') {
|
||||
msg.should.have.properties(Object.assign({}, val1, {payload: Buffer.from(val1.payload)}));
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(val1));
|
||||
}
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
if((typeof val0) === 'object') {
|
||||
n1.receive(val0);
|
||||
} else {
|
||||
n1.receive({payload:val0});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testTCPMany(flow, values, result, done) {
|
||||
helper.load(tcpinNode, flow, () => {
|
||||
const n1 = helper.getNode("n1");
|
||||
const n2 = helper.getNode("n2");
|
||||
n2.on("input", msg => {
|
||||
try {
|
||||
if (typeof result === 'object') {
|
||||
if (flow[0].ret === "string") {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: result.payload}));
|
||||
} else {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: Buffer.from(result.payload)}));
|
||||
}
|
||||
} else {
|
||||
if (flow[0].ret === "string") {
|
||||
msg.should.have.property('payload', result);
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(result));
|
||||
}
|
||||
}
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
values.forEach(value => {
|
||||
n1.receive(typeof value === 'object' ? value : {payload: value});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('single message', function () {
|
||||
it('should send & recv data', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should retain complete message', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data when specified character received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo0bar0',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo0',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data after fixed number of chars received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo bar',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data to/from server:port from msg', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: "foo",
|
||||
host: "localhost",
|
||||
port: port
|
||||
}, {
|
||||
payload: "ACK:foo",
|
||||
host: 'localhost',
|
||||
port: port
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('many messages', function () {
|
||||
it('should send & recv data', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: 'f',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data when specified character received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo0",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "bar0",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foo0",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data after fixed number of chars received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "fo",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "ob",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "ar",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foo",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "bar",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "baz",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foobarbaz",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection, and not split return strings', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", ret:"string", newline:"", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'boo'
|
||||
}, {
|
||||
payload: "bar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}], {
|
||||
payload: "ACK:foobar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection, and split return strings', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", ret:"string", newline:"<A>\\n", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'boo'
|
||||
}, {
|
||||
payload: "bar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}], {
|
||||
payload: "ACK:foobar<A>",
|
||||
topic: 'boo'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data to/from server:port from msg', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [
|
||||
{
|
||||
payload: "f",
|
||||
host: "localhost",
|
||||
port: port
|
||||
},
|
||||
{
|
||||
payload: "o",
|
||||
host: "localhost",
|
||||
port: port
|
||||
},
|
||||
{
|
||||
payload: "o",
|
||||
host: "localhost",
|
||||
port: port
|
||||
}
|
||||
], {
|
||||
payload: "ACK:foo",
|
||||
host: 'localhost',
|
||||
port: port
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should limit the queue size', function (done) {
|
||||
RED.settings.tcpMsgQueueSize = 10;
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
// create one more msg than is allowed
|
||||
const msgs = new Array(RED.settings.tcpMsgQueueSize + 1).fill('x');
|
||||
const expected = msgs.slice(0, -1);
|
||||
testTCPMany(flow, msgs, "ACK:" + expected.join(''), done);
|
||||
});
|
||||
|
||||
it('should only retain the latest message', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: 'f',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'baz'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'quux'
|
||||
}], {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'quux'
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
590
test/nodes/core/parsers/70-JSON_spec.js
Normal file
590
test/nodes/core/parsers/70-JSON_spec.js
Normal file
@@ -0,0 +1,590 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var jsonNode = require("nr-test-utils").require("@node-red/nodes/core/parsers/70-JSON.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('JSON node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should convert a valid json string to a javascript object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:jsonString,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a buffer of a valid json string to a javascript object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
});
|
||||
var jsonString = Buffer.from('{"employees":[{"firstName":"John", "lastName":"Smith"}]}');
|
||||
jn1.receive({payload:jsonString,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
done();
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a array to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '[1,2,3]');
|
||||
done();
|
||||
});
|
||||
var obj = [1,2,3];
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a boolean to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, 'true');
|
||||
done();
|
||||
});
|
||||
var obj = true;
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a json string to a boolean', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, true);
|
||||
done();
|
||||
});
|
||||
var obj = "true";
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a number to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '2019');
|
||||
done();
|
||||
});
|
||||
var obj = 2019;
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a json string to a number', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, 1962);
|
||||
done();
|
||||
});
|
||||
var obj = '1962';
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse an invalid json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn1.receive({payload:'foo',topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("Unexpected token o");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},20);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse an invalid json string in a buffer', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn1.receive({payload:Buffer.from('{"name":foo}'),topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("Unexpected token o");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},20);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// it('should log an error if asked to parse something thats not json or js and not in force object mode', function(done) {
|
||||
// var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
// {id:"jn2", type:"helper"}];
|
||||
// helper.load(jsonNode, flow, function() {
|
||||
// var jn1 = helper.getNode("jn1");
|
||||
// var jn2 = helper.getNode("jn2");
|
||||
// setTimeout(function() {
|
||||
// try {
|
||||
// var logEvents = helper.log().args.filter(function(evt) {
|
||||
// return evt[0].type == "json";
|
||||
// });
|
||||
// logEvents.should.have.length(1);
|
||||
// logEvents[0][0].should.have.a.property('msg');
|
||||
// logEvents[0][0].msg.toString().should.eql('json.errors.dropped');
|
||||
// done();
|
||||
// } catch(err) {
|
||||
// done(err);
|
||||
// }
|
||||
// },50);
|
||||
// jn1.receive({payload:Buffer.from("abcd")});
|
||||
// });
|
||||
// });
|
||||
|
||||
it('should pass straight through if no payload set', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.not.have.property('payload');
|
||||
done();
|
||||
});
|
||||
jn1.receive({topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure the result is a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var count = 0;
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
should.equal(msg.payload, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj,topic: "bar"});
|
||||
jn1.receive({payload:JSON.stringify(obj),topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure the result is a JS Object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var count = 0;
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj,topic: "bar"});
|
||||
jn1.receive({payload:JSON.stringify(obj),topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle any msg property - receive existing string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",property:"one.two",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('one');
|
||||
msg.one.should.have.property('two');
|
||||
msg.one.two.should.have.property('employees');
|
||||
msg.one.two.employees[0].should.have.property('firstName', 'John');
|
||||
msg.one.two.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:"",one:{two:jsonString},topic: "bar"});
|
||||
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle any msg property - receive existing obj', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",property:"one.two",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
should.equal(msg.one.two, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:"",one:{two:JSON.parse(jsonString)},topic: "bar"});
|
||||
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass an object if provided a valid JSON string and schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload.number, 3);
|
||||
should.equal(msg.payload.string, "allo");
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number": 3, "string": "allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass an object if provided a valid object and schema and action is object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload.number, 3);
|
||||
should.equal(msg.payload.string, "allo");
|
||||
done();
|
||||
});
|
||||
var obj = {"number": 3, "string": "allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass a string if provided a valid object and schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"number":3,"string":"allo"}');
|
||||
done();
|
||||
});
|
||||
var obj = {"number": 3, "string": "allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass a string if provided a valid JSON string and schema and action is string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"number":3,"string":"allo"}');
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number":3,"string":"allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid object and valid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid object and valid schema and action is object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid JSON string and valid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var jsonString = '{"number":"Hello","string":3}';
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid JSON string and valid schema and action is string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var jsonString = '{"number":"Hello","string":3}';
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed a valid object and invalid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = "garbage";
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.equal("json.errors.schema-error-compile");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('msg.schema property should be deleted before sending to next node (string input)', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.schema, undefined);
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number":3,"string":"allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('msg.schema property should be deleted before sending to next node (object input)', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.schema, undefined);
|
||||
done();
|
||||
});
|
||||
var jsonObject = {"number":3,"string":"allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonObject, schema:schema});
|
||||
});
|
||||
});
|
||||
});
|
||||
609
test/nodes/subflow/subflow_spec.js
Normal file
609
test/nodes/subflow/subflow_spec.js
Normal file
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var functionNode = require("nr-test-utils").require("@node-red/nodes/core/function/10-function.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
// Notice:
|
||||
// - nodes should have x, y, z property when defining subflow.
|
||||
|
||||
describe('subflow', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should define subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t1", type:"tab"},
|
||||
{id:"n1", z:"t1", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", z:"t1", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{wires:[ {id:"s1-n1"} ]}],
|
||||
out:[{wires:[ {id:"s1-n1", port:0} ]}]},
|
||||
{id:"s1-n1", z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass data to/from subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.payload = msg.payload+'bar'; return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("payload", "foobar");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass data to/from nested subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.payload = msg.payload+'baz'; return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.payload=msg.payload+'bar'; return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("payload", "foobarbaz");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of subflow template', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of subflow instance', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access last env var with same name', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V0"},
|
||||
{name: "X", type: "str", value: "VX"},
|
||||
{name: "K", type: "str", value: "V1"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V1");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access typed value of env var', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "KN", type: "num", value: "100"},
|
||||
{name: "KB", type: "bool", value: "true"},
|
||||
{name: "KJ", type: "json", value: "[1,2,3]"},
|
||||
{name: "Kb", type: "bin", value: "[65,65]"},
|
||||
{name: "Ke", type: "env", value: "KS"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}],
|
||||
env: [
|
||||
{name: "KS", type: "str", value: "STR"}
|
||||
]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("VS", "STR");
|
||||
msg.should.have.property("VN", 100);
|
||||
msg.should.have.property("VB", true);
|
||||
msg.should.have.property("VJ", [1,2,3]);
|
||||
msg.should.have.property("Vb");
|
||||
should.ok(msg.Vb instanceof Buffer);
|
||||
msg.should.have.property("VE","STR");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should overwrite env var of subflow template by env var of subflow instance', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "TV"}
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of parent subflow template', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"},
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of parent subflow instance', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of tab', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:"", env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of group', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"g1", z:"t0", type:"group", env:[
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"n1", x:10, y:10, z:"t0", g:"g1", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of nested group', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"g1", z:"t0", type:"group", env:[
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"g2", z:"t0", g:"g1", type:"group", env:[]},
|
||||
{id:"n1", x:10, y:10, z:"t0", g:"g2", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access NR_NODE_PATH env var within subflow instance', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [], wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.payload = env.get('NR_NODE_PATH'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "t0/n1/s1-n1");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
1006
test/unit/@node-red/runtime/lib/flows/Subflow_spec.js
Normal file
1006
test/unit/@node-red/runtime/lib/flows/Subflow_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
1250
test/unit/@node-red/runtime/lib/nodes/context/index_spec.js
Normal file
1250
test/unit/@node-red/runtime/lib/nodes/context/index_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
1110
test/unit/@node-red/util/lib/util_spec.js
Normal file
1110
test/unit/@node-red/util/lib/util_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user