diff --git a/.travis.yml b/.travis.yml
index 328a85ef7..054edefba 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,7 @@ matrix:
include:
- node_js: "10"
script:
- - istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
+ - ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
before_script:
- npm install -g istanbul coveralls
- node_js: "8"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d6cccb65..2a73106c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+#### 0.18.7: Maintenance Release
+
+Editor Fixes
+
+ - Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
+
+Node Fixes
+
+ - Relax twitter node version ready for major version bump
+ - Pass Date into the Function node sandbox to fix instanceof tests
+ - let TCP in node report remote ip and port when in single packet mode
+ - typo fix in node help (#1735)
+
+Other Fixes
+ - Tidy up default grunt task and fixup test break due to reorder Fixes #1738
+ - Bump jsonata version
+
#### 0.18.6: Maintenance Release
Editor Fixes
diff --git a/Gruntfile.js b/Gruntfile.js
index 2be2d23c0..3738e60b4 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -55,7 +55,7 @@ module.exports = function(grunt) {
reportFormats: ['lcov','html'],
print: 'both'
},
- all: { src: ['test/**/*_spec.js'] },
+ all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
@@ -474,7 +474,7 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
- ['build','test-core','test-editor','test-nodes']);
+ ['build','jshint:editor','mocha_istanbul:all']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
diff --git a/editor/js/nodes.js b/editor/js/nodes.js
index 0a2fe7268..433e400a2 100644
--- a/editor/js/nodes.js
+++ b/editor/js/nodes.js
@@ -1033,15 +1033,31 @@ RED.nodes = (function() {
node.type = "unknown";
}
if (node._def.category != "config") {
- node.inputs = n.inputs||node._def.inputs;
- node.outputs = n.outputs||node._def.outputs;
- // If 'wires' is longer than outputs, clip wires
+ if (n.hasOwnProperty('inputs')) {
+ node.inputs = n.inputs;
+ node._config.inputs = JSON.stringify(n.inputs);
+ } else {
+ node.inputs = node._def.inputs;
+ }
+ if (n.hasOwnProperty('outputs')) {
+ node.outputs = n.outputs;
+ node._config.outputs = JSON.stringify(n.outputs);
+ } else {
+ node.outputs = node._def.outputs;
+ }
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
- console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
- node.wires = node.wires.slice(0,node.outputs);
+ if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
+ // If 'wires' is longer than outputs, clip wires
+ console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
+ node.wires = node.wires.slice(0,node.outputs);
+ } else {
+ // The node declares outputs in its defaults, but has not got a valid value
+ // Defer to the length of the wires array
+ node.outputs = node.wires.length;
+ }
}
for (d in node._def.defaults) {
- if (node._def.defaults.hasOwnProperty(d)) {
+ if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d];
node._config[d] = JSON.stringify(n[d]);
}
diff --git a/nodes/core/core/80-function.js b/nodes/core/core/80-function.js
index a76e1eead..7edb6c4a8 100644
--- a/nodes/core/core/80-function.js
+++ b/nodes/core/core/80-function.js
@@ -82,6 +82,7 @@ module.exports = function(RED) {
console:console,
util:util,
Buffer:Buffer,
+ Date: Date,
RED: {
util: RED.util
},
diff --git a/nodes/core/io/10-mqtt.html b/nodes/core/io/10-mqtt.html
index 722a7a7ae..afe710472 100644
--- a/nodes/core/io/10-mqtt.html
+++ b/nodes/core/io/10-mqtt.html
@@ -41,7 +41,7 @@
payload string | buffer
a string unless detected as a binary buffer.
topic string
- the MQTT topic, uses / as a heirarchy separator.
+ the MQTT topic, uses / as a hierarchy separator.
qos number
0, fire and forget - 1, at least once - 2, once and once only.
retain boolean
diff --git a/nodes/core/io/31-tcpin.js b/nodes/core/io/31-tcpin.js
index 5853d4f42..c3bc2ab8c 100644
--- a/nodes/core/io/31-tcpin.js
+++ b/nodes/core/io/31-tcpin.js
@@ -130,6 +130,8 @@ module.exports = function(RED) {
socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16);
+ var fromi;
+ var fromp;
connectionPool[id] = socket;
count++;
node.status({text:RED._("tcpin.status.connections",{count:count})});
@@ -155,18 +157,21 @@ module.exports = function(RED) {
msg._session = {type:"tcp",id:id};
node.send(msg);
}
- } else {
+ }
+ else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
+ fromi = socket.remoteAddress;
+ fromp = socket.remotePort;
}
});
socket.on('end', function() {
if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
if (buffer.length > 0) {
- var msg = {topic:node.topic, payload:buffer, ip:socket.remoteAddress, port:socket.remotePort};
+ var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
diff --git a/package.json b/package.json
index f90789e43..ec0f63a34 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "node-red",
- "version": "0.18.6",
+ "version": "0.18.7",
"description": "A visual tool for wiring the Internet of Things",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -52,7 +52,7 @@
"is-utf8": "0.2.1",
"js-yaml": "3.11.0",
"json-stringify-safe": "5.0.1",
- "jsonata": "1.5.3",
+ "jsonata": "1.5.4",
"media-typer": "0.3.0",
"memorystore": "1.6.0",
"mqtt": "2.18.0",
@@ -61,7 +61,7 @@
"node-red-node-email": "0.1.*",
"node-red-node-feedparser": "0.1.*",
"node-red-node-rbe": "0.2.*",
- "node-red-node-twitter": "0.1.*",
+ "node-red-node-twitter": "*",
"nopt": "4.0.1",
"oauth2orize": "1.11.0",
"on-headers": "1.0.1",
diff --git a/red/api/auth/users.js b/red/api/auth/users.js
index 92c4c9ce9..24a762958 100644
--- a/red/api/auth/users.js
+++ b/red/api/auth/users.js
@@ -86,6 +86,10 @@ function init(config) {
} else {
api.authenticate = authenticate;
}
+ } else {
+ api.get = get;
+ api.authenticate = authenticate;
+ api.default = api.default;
}
if (config.default) {
if (typeof config.default === "function") {
diff --git a/test/nodes/core/core/80-function_spec.js b/test/nodes/core/core/80-function_spec.js
index 0e94f97af..491d1ed3b 100644
--- a/test/nodes/core/core/80-function_spec.js
+++ b/test/nodes/core/core/80-function_spec.js
@@ -524,7 +524,7 @@ describe('function node', function() {
it('should allow accessing node.name', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload = node.name; return msg;", "name":"name of node"},
- {id:"n2", type:"helper"}];
+ {id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -536,6 +536,21 @@ describe('function node', function() {
});
});
+ it('should use the same Date object from outside the sandbox', function(done) {
+ var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('typeTest')(new Date());return msg;"},
+ {id:"n2", type:"helper"}];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n1.context().global.set("typeTest",function(d) { return d instanceof Date });
+ n2.on("input", function(msg) {
+ msg.should.have.property('payload', true);
+ done();
+ });
+ n1.receive({payload:"foo",topic: "bar"});
+ });
+ });
+
describe('Logger', function () {
it('should log an Info Message', function (done) {
var flow = [{id: "n1", type: "function", wires: [["n2"]], func: "node.log('test');"}];
diff --git a/test/red/api/auth/users_spec.js b/test/red/api/auth/users_spec.js
index 23c34001d..e7b70f7b1 100644
--- a/test/red/api/auth/users_spec.js
+++ b/test/red/api/auth/users_spec.js
@@ -194,8 +194,7 @@ describe("api/auth/users", function() {
it('should fail to return user fred',function(done) {
Users.get("fred").then(function(userf) {
try {
- userf.should.not.have.a.property("username","fred");
- userf.should.not.have.a.property("permissions","*");
+ should.not.exist(userf);
done();
} catch(err) {
done(err);
@@ -212,9 +211,12 @@ describe("api/auth/users", function() {
default: function() { return("Done"); }
});
});
+ after(function() {
+ Users.init({});
+ });
describe('#default',function() {
it('handles api.default being a function',function(done) {
- Users.should.have.property('default').which.is.a.Function;
+ Users.should.have.property('default').which.is.a.Function();
(Users.default()).should.equal("Done");
done();
});