Fixup all the tests

This commit is contained in:
Nick O'Leary
2018-04-24 15:01:49 +01:00
parent 34832d5942
commit 5d064aa1d7
50 changed files with 3480 additions and 1762 deletions

View File

@@ -33,6 +33,24 @@ var listenPort = 0; // use ephemeral port
describe("api/editor/comms", function() {
var connections = [];
var mockComms = {
addConnection: function(opts) {
connections.push(opts.client);
return Promise.resolve()
},
removeConnection: function(opts) {
for (var i=0;i<connections.length;i++) {
if (connections[i] === opts.client) {
connections.splice(i,1);
break;
}
}
return Promise.resolve()
},
subscribe: function() { return Promise.resolve()},
unsubscribe: function() { return Promise.resolve(); }
}
describe("with default keepalive", function() {
var server;
@@ -41,11 +59,7 @@ describe("api/editor/comms", function() {
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -63,9 +77,15 @@ describe("api/editor/comms", function() {
it('accepts connection', function(done) {
var ws = new WebSocket(url);
connections.length.should.eql(0);
ws.on('open', function() {
ws.close();
done();
try {
connections.length.should.eql(1);
ws.close();
done();
} catch(err) {
done(err);
}
});
});
@@ -73,7 +93,8 @@ describe("api/editor/comms", function() {
var ws = new WebSocket(url);
ws.on('open', function() {
ws.send('{"subscribe":"topic1"}');
comms.publish('topic1', 'foo');
connections.length.should.eql(1);
connections[0].send('topic1', 'foo');
});
ws.on('message', function(msg) {
msg.should.equal('[{"topic":"topic1","data":"foo"}]');
@@ -82,43 +103,13 @@ describe("api/editor/comms", function() {
});
});
it('publishes retained message for subscription', function(done) {
comms.publish('topic2', 'bar', true);
var ws = new WebSocket(url);
ws.on('open', function() {
ws.send('{"subscribe":"topic2"}');
});
ws.on('message', function(msg) {
console.log(msg);
msg.should.equal('[{"topic":"topic2","data":"bar"}]');
ws.close();
done();
});
});
it('retained message is deleted by non-retained message', function(done) {
comms.publish('topic3', 'retained', true);
comms.publish('topic3', 'non-retained');
var ws = new WebSocket(url);
ws.on('open', function() {
ws.send('{"subscribe":"topic3"}');
comms.publish('topic3', 'new');
});
ws.on('message', function(msg) {
console.log(msg);
msg.should.equal('[{"topic":"topic3","data":"new"}]');
ws.close();
done();
});
});
it('malformed messages are ignored',function(done) {
var ws = new WebSocket(url);
ws.on('open', function() {
ws.send('not json');
ws.send('[]');
ws.send('{"subscribe":"topic3"}');
comms.publish('topic3', 'correct');
connections[0].send('topic3', 'correct');
});
ws.on('message', function(msg) {
console.log(msg);
@@ -127,40 +118,16 @@ describe("api/editor/comms", function() {
done();
});
});
// The following test currently fails due to minimum viable
// implementation. More test should be written to test topic
// matching once this one is passing
it.skip('receives message on correct topic', function(done) {
var ws = new WebSocket(url);
ws.on('open', function() {
ws.send('{"subscribe":"topic4"}');
comms.publish('topic5', 'foo');
comms.publish('topic4', 'bar');
});
ws.on('message', function(msg) {
console.log(msg);
msg.should.equal('[{"topic":"topic4","data":"bar"}]');
ws.close();
done();
});
});
it('listens for node/status events');
});
describe("disabled editor", function() {
var server;
var url;
var port;
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{disableEditor:true},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {disableEditor:true}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -177,12 +144,14 @@ describe("api/editor/comms", function() {
});
it('rejects websocket connections',function(done) {
connections.length.should.eql(0);
var ws = new WebSocket(url);
ws.on('open', function() {
done(new Error("Socket connection unexpectedly accepted"));
ws.close();
});
ws.on('error', function() {
connections.length.should.eql(0);
done();
});
@@ -196,11 +165,7 @@ describe("api/editor/comms", function() {
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{httpAdminRoot:"/adminPath"},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {httpAdminRoot:"/adminPath"}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -217,8 +182,10 @@ describe("api/editor/comms", function() {
});
it('accepts connections',function(done) {
connections.length.should.eql(0);
var ws = new WebSocket(url);
ws.on('open', function() {
connections.length.should.eql(1);
ws.close();
done();
});
@@ -236,11 +203,7 @@ describe("api/editor/comms", function() {
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server,{
settings:{httpAdminRoot:"/adminPath"},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {httpAdminRoot:"/adminPath/"}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -257,8 +220,10 @@ describe("api/editor/comms", function() {
});
it('accepts connections',function(done) {
connections.length.should.eql(0);
var ws = new WebSocket(url);
ws.on('open', function() {
connections.length.should.eql(1);
ws.close();
done();
});
@@ -276,11 +241,7 @@ describe("api/editor/comms", function() {
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{httpAdminRoot:"adminPath"},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {httpAdminRoot:"adminPath"}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -297,8 +258,10 @@ describe("api/editor/comms", function() {
});
it('accepts connections',function(done) {
connections.length.should.eql(0);
var ws = new WebSocket(url);
ws.on('open', function() {
connections.length.should.eql(1);
ws.close();
done();
});
@@ -316,11 +279,7 @@ describe("api/editor/comms", function() {
before(function(done) {
sinon.stub(Users,"default",function() { return when.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{webSocketKeepAliveTime: 100},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {webSocketKeepAliveTime: 100}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -355,7 +314,7 @@ describe("api/editor/comms", function() {
ws.on('open', function() {
ws.send('{"subscribe":"foo"}');
interval = setInterval(function() {
comms.publish('foo', 'bar');
connections[0].send('foo', 'bar');
}, 50);
});
ws.on('message', function(data) {
@@ -403,11 +362,7 @@ describe("api/editor/comms", function() {
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server,{
settings:{adminAuth:{}},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {adminAuth:{}}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -447,7 +402,7 @@ describe("api/editor/comms", function() {
if (received == 1) {
msg.should.equal('{"auth":"ok"}');
ws.send('{"subscribe":"foo"}');
comms.publish('foo', 'correct');
connections[0].send('foo', 'correct');
} else {
msg.should.equal('[{"topic":"foo","data":"correct"}]');
ws.close();
@@ -494,11 +449,7 @@ describe("api/editor/comms", function() {
before(function(done) {
getDefaultUser = sinon.stub(Users,"default",function() { return when.resolve({permissions:"read"});});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {
settings:{adminAuth:{}},
log:{warn:function(){},_:function(){},trace:function(){},audit:function(){}},
events:{on:function(){},removeListener:function(){}}
});
comms.init(server, {adminAuth:{}}, {comms: mockComms});
server.listen(listenPort, address);
server.on('listening', function() {
port = server.address().port;
@@ -520,7 +471,7 @@ describe("api/editor/comms", function() {
ws.on('open', function() {
ws.send('{"subscribe":"foo"}');
setTimeout(function() {
comms.publish('foo', 'correct');
connections[0].send('foo', 'correct');
},200);
});
ws.on('message', function(msg) {

View File

@@ -29,64 +29,30 @@ describe('api/editor/credentials', function() {
app = express();
app.get('/credentials/:type/:id',credentials.get);
credentials.init({
log:{audit:function(){}},
nodes:{
getCredentials: function(id) {
if (id === "n1") {
return {user1:"abc",password1:"123"};
flows: {
getNodeCredentials: function(opts) {
if (opts.type === "known-type" && opts.id === "n1") {
return Promise.resolve({
user1:"abc",
has_password1: true
});
} else {
return null;
}
},
getCredentialDefinition:function(type) {
if (type === "known-type") {
return {user1:{type:"text"},password1:{type:"password"}};
} else {
return null;
var err = new Error("message");
err.code = "test_code";
var p = Promise.reject(err);
p.catch(()=>{});
return p;
}
}
}
});
});
it('returns empty credentials if unknown type',function(done) {
request(app)
.get("/credentials/unknown-type/n1")
.expect(200)
.expect("Content-Type",/json/)
.end(function(err,res) {
if (err) {
done(err);
} else {
try {
res.body.should.eql({});
done();
} catch(e) {
done(e);
}
}
})
});
it('returns empty credentials if none are stored',function(done) {
request(app)
.get("/credentials/known-type/n2")
.expect("Content-Type",/json/)
.end(function(err,res) {
if (err) {
done(err);
} else {
try {
res.body.should.eql({});
done();
} catch(e) {
done(e);
}
}
})
});
it('returns stored credentials',function(done) {
request(app)
.get("/credentials/known-type/n1")
.expect("Content-Type",/json/)
.expect(200)
.end(function(err,res) {
if (err) {
done(err);
@@ -102,5 +68,26 @@ describe('api/editor/credentials', function() {
}
})
});
it('returns any error',function(done) {
request(app)
.get("/credentials/unknown-type/n2")
.expect("Content-Type",/json/)
.expect(500)
.end(function(err,res) {
if (err) {
done(err);
} else {
try {
res.body.should.have.property('code');
res.body.code.should.be.equal("test_code");
res.body.should.have.property('message');
res.body.message.should.be.equal('message');
done();
} catch(e) {
done(e);
}
}
})
});
});

View File

@@ -22,6 +22,10 @@ var editorApi = require("../../../../red/api/editor");
var comms = require("../../../../red/api/editor/comms");
var info = require("../../../../red/api/editor/settings");
var auth = require("../../../../red/api/auth");
var log = require("../../../../red/util/log");
var when = require("when");
@@ -37,9 +41,7 @@ describe("api/editor/index", function() {
info.init.restore();
});
it("disables the editor", function() {
var editorApp = editorApi.init({},{
settings:{disableEditor:true}
});
var editorApp = editorApi.init({},{disableEditor:true},{});
should.not.exist(editorApp);
comms.init.called.should.be.false();
info.init.called.should.be.false();
@@ -67,15 +69,13 @@ describe("api/editor/index", function() {
})
require("../../../../red/api/editor/theme").app.restore();
auth.needsPermission.restore();
log.error.restore();
});
before(function() {
app = editorApi.init({},{
log:{audit:function(){},error:function(msg){errors.push(msg)}},
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false,exportNodeSettings:function(){}},
events:{on:function(){},removeListener:function(){}},
isStarted: function() { return isStarted; },
nodes: {paletteEditorEnabled: function() { return false }}
sinon.stub(log,"error",function(err) { errors.push(err)})
app = editorApi.init({},{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false,exportNodeSettings:function(){}},{
isStarted: () => Promise.resolve(isStarted)
});
});
it('serves the editor', function(done) {
@@ -117,7 +117,7 @@ describe("api/editor/index", function() {
done();
});
});
// it('GET /settings', function(done) {
// it.skip('GET /settings', function(done) {
// request(app).get("/settings").expect(200).end(function(err,res) {
// if (err) {
// return done(err);

View File

@@ -16,334 +16,287 @@
var should = require("should");
var sinon = require("sinon");
var fs = require("fs");
var fspath = require('path');
var request = require('supertest');
var express = require('express');
var bodyParser = require('body-parser');
var when = require('when');
var app;
var library = require("../../../../red/api/editor/library");
var auth = require("../../../../red/api/auth");
describe("api/editor/library", function() {
function initLibrary(_flows,_libraryEntries,_examples,_exampleFlowPathFunction) {
var flows = _flows;
var libraryEntries = _libraryEntries;
library.init(app,{
log:{audit:function(){},_:function(){},warn:function(){}},
storage: {
init: function() {
return when.resolve();
},
getAllFlows: function() {
return when.resolve(flows);
},
getFlow: function(fn) {
if (flows[fn]) {
return when.resolve(flows[fn]);
} else if (fn.indexOf("..")!==-1) {
var err = new Error();
err.code = 'forbidden';
return when.reject(err);
} else {
return when.reject();
}
},
saveFlow: function(fn,data) {
if (fn.indexOf("..")!==-1) {
var err = new Error();
err.code = 'forbidden';
return when.reject(err);
}
flows[fn] = data;
return when.resolve();
},
getLibraryEntry: function(type,path) {
if (path.indexOf("..")!==-1) {
var err = new Error();
err.code = 'forbidden';
return when.reject(err);
}
if (libraryEntries[type] && libraryEntries[type][path]) {
return when.resolve(libraryEntries[type][path]);
} else {
return when.reject();
}
},
saveLibraryEntry: function(type,path,meta,body) {
if (path.indexOf("..")!==-1) {
var err = new Error();
err.code = 'forbidden';
return when.reject(err);
}
libraryEntries[type][path] = body;
return when.resolve();
before(function() {
app = express();
app.use(bodyParser.json());
app.get("/library/flows",library.getAll);
app.post(/library\/([^\/]+)\/(.*)/,library.saveEntry);
app.get(/library\/([^\/]+)(?:$|\/(.*))/,library.getEntry);
});
after(function() {
});
it('returns all flows', function(done) {
library.init({
library: {
getEntries: function(opts) {
return Promise.resolve({a:1,b:2});
}
},
events: {
on: function(){},
removeListener: function(){}
},
nodes: {
getNodeExampleFlows: function() {
return _examples;
},
getNodeExampleFlowPath: _exampleFlowPathFunction
}
});
}
describe("flows", function() {
before(function() {
app = express();
app.use(bodyParser.json());
app.get("/library/flows",library.getAll);
app.post(new RegExp("/library/flows\/(.*)"),library.post);
app.get(new RegExp("/library/flows\/(.*)"),library.get);
app.response.sendFile = function (path) {
app.response.json.call(this, {sendFile: path});
};
sinon.stub(fs,"statSync",function() { return true; });
});
after(function() {
fs.statSync.restore();
});
it('returns empty result', function(done) {
initLibrary({},{flows:{}});
request(app)
.get('/library/flows')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.not.have.property('f');
res.body.should.not.have.property('d');
done();
});
});
it('returns 404 for non-existent entry', function(done) {
initLibrary({},{flows:{}});
request(app)
.get('/library/flows/foo')
.expect(404)
.end(done);
});
it('can store and retrieve item', function(done) {
initLibrary({},{flows:{}});
var flow = '[]';
request(app)
.post('/library/flows/foo')
.set('Content-Type', 'application/json')
.send(flow)
.expect(204).end(function (err, res) {
if (err) {
throw err;
}
request(app)
.get('/library/flows/foo')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.text.should.equal(flow);
done();
});
});
});
it('lists a stored item', function(done) {
initLibrary({f:["bar"]});
request(app)
.get('/library/flows')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.have.property('f');
should.deepEqual(res.body.f,['bar']);
done();
});
});
it('returns 403 for malicious get attempt', function(done) {
initLibrary({});
// without the userDir override the malicious url would be
// http://127.0.0.1:1880/library/flows/../../package to
// obtain package.json from the node-red root.
request(app)
.get('/library/flows/../../../../../package')
.expect(403)
.end(done);
});
it('returns 403 for malicious post attempt', function(done) {
initLibrary({});
// without the userDir override the malicious url would be
// http://127.0.0.1:1880/library/flows/../../package to
// obtain package.json from the node-red root.
request(app)
.post('/library/flows/../../../../../package')
.expect(403)
.end(done);
});
it('includes examples flows if set', function(done) {
var examples = {"d":{"node-module":{"f":["example-one"]}}};
initLibrary({},{},examples);
request(app)
.get('/library/flows')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.have.property('d');
res.body.d.should.have.property('_examples_');
should.deepEqual(res.body.d._examples_,examples);
done();
});
});
it('can retrieve an example flow', function(done) {
var examples = {"d":{"node-module":{"f":["example-one"]}}};
initLibrary({},{},examples,function(module,path) {
return module + ':' + path
request(app)
.get('/library/flows')
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('a',1);
res.body.should.have.property('b',2);
done();
});
request(app)
.get('/library/flows/_examples_/node-module/example-one')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.have.property('sendFile',
'node-module:example-one');
done();
});
})
it('returns an error on all flows', function(done) {
library.init({
library: {
getEntries: function(opts) {
var err = new Error("message");
err.code = "random_error";
err.status = 400;
var p = Promise.reject(err);
p.catch(()=>{});
return p;
}
}
});
it('can retrieve an example flow in an org scoped package', function(done) {
var examples = {"d":{"@org_scope/node_package":{"f":["example-one"]}}};
initLibrary({},{},examples,function(module,path) {
return module + ':' + path
request(app)
.get('/library/flows')
.expect(400)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('code');
res.body.code.should.be.equal("random_error");
res.body.should.have.property('message');
res.body.message.should.be.equal("message");
done();
});
request(app)
.get('/library/flows/_examples_/@org_scope/node_package/example-one')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.have.property('sendFile',
'@org_scope/node_package:example-one');
done();
});
});
});
describe("type", function() {
before(function() {
app = express();
app.use(bodyParser.json());
initLibrary({},{});
auth.init({settings:{}});
library.register("test");
it('returns an individual entry - flow type', function(done) {
var opts;
library.init({
library: {
getEntry: function(_opts) {
opts = _opts;
return Promise.resolve('{"a":1,"b":2}');
}
}
});
it('returns empty result', function(done) {
initLibrary({},{'test':{"":[]}});
request(app)
.get('/library/test')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.body.should.not.have.property('f');
done();
});
request(app)
.get('/library/flows/abc')
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('a',1);
res.body.should.have.property('b',2);
opts.should.have.property('type','flows');
opts.should.have.property('path','abc');
done();
});
})
it('returns a directory listing - flow type', function(done) {
var opts;
library.init({
library: {
getEntry: function(_opts) {
opts = _opts;
return Promise.resolve({"a":1,"b":2});
}
}
});
it('returns 404 for non-existent entry', function(done) {
initLibrary({},{});
request(app)
.get('/library/test/foo')
.expect(404)
.end(done);
request(app)
.get('/library/flows/abc/def')
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('a',1);
res.body.should.have.property('b',2);
opts.should.have.property('type','flows');
opts.should.have.property('path','abc/def');
done();
});
})
it('returns an individual entry - non-flow type', function(done) {
var opts;
library.init({
library: {
getEntry: function(_opts) {
opts = _opts;
return Promise.resolve('{"a":1,"b":2}');
}
}
});
it('can store and retrieve item', function(done) {
initLibrary({},{'test':{}});
var flow = {text:"test content"};
request(app)
.post('/library/test/foo')
.set('Content-Type', 'application/json')
.send(flow)
.expect(204).end(function (err, res) {
if (err) {
throw err;
}
request(app)
.get('/library/test/foo')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
res.text.should.equal(flow.text);
done();
});
});
request(app)
.get('/library/non-flow/abc')
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
opts.should.have.property('type','non-flow');
opts.should.have.property('path','abc');
res.text.should.eql('{"a":1,"b":2}');
done();
});
})
it('returns a directory listing - non-flow type', function(done) {
var opts;
library.init({
library: {
getEntry: function(_opts) {
opts = _opts;
return Promise.resolve({"a":1,"b":2});
}
}
});
request(app)
.get('/library/non-flow/abc/def')
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('a',1);
res.body.should.have.property('b',2);
opts.should.have.property('type','non-flow');
opts.should.have.property('path','abc/def');
done();
});
})
it('lists a stored item', function(done) {
initLibrary({},{'test':{'a':['abc','def']}});
request(app)
.get('/library/test/a')
.expect(200)
.end(function(err,res) {
if (err) {
throw err;
}
// This response isn't strictly accurate - but it
// verifies the api returns what storage gave it
should.deepEqual(res.body,['abc','def']);
done();
});
it('returns an error on individual get', function(done) {
var opts;
library.init({
library: {
getEntry: function(_opts) {
opts = _opts;
var err = new Error("message");
err.code = "random_error";
err.status = 400;
var p = Promise.reject(err);
p.catch(()=>{});
return p;
}
}
});
request(app)
.get('/library/flows/123')
.expect(400)
.end(function(err,res) {
if (err) {
return done(err);
}
opts.should.have.property('type','flows');
opts.should.have.property('path','123');
res.body.should.have.property('code');
res.body.code.should.be.equal("random_error");
res.body.should.have.property('message');
res.body.message.should.be.equal("message");
done();
});
});
it('returns 403 for malicious access attempt', function(done) {
request(app)
.get('/library/test/../../../../../../../../../../etc/passwd')
.expect(403)
.end(done);
it('saves an individual entry - flow type', function(done) {
var opts;
library.init({
library: {
saveEntry: function(_opts) {
opts = _opts;
return Promise.resolve();
}
}
});
request(app)
.post('/library/flows/abc/def')
.expect(204)
.send({a:1,b:2,c:3})
.end(function(err,res) {
if (err) {
return done(err);
}
opts.should.have.property('type','flows');
opts.should.have.property('path','abc/def');
opts.should.have.property('meta',{});
opts.should.have.property('body',JSON.stringify({a:1,b:2,c:3}));
done();
});
})
it('returns 403 for malicious access attempt', function(done) {
request(app)
.get('/library/test/..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd')
.expect(403)
.end(done);
it('saves an individual entry - non-flow type', function(done) {
var opts;
library.init({
library: {
saveEntry: function(_opts) {
opts = _opts;
return Promise.resolve();
}
}
});
request(app)
.post('/library/non-flow/abc/def')
.expect(204)
.send({a:1,b:2,text:"123"})
.end(function(err,res) {
if (err) {
return done(err);
}
opts.should.have.property('type','non-flow');
opts.should.have.property('path','abc/def');
opts.should.have.property('meta',{a:1,b:2});
opts.should.have.property('body',"123");
done();
});
})
it('returns 403 for malicious access attempt', function(done) {
request(app)
.post('/library/test/../../../../../../../../../../etc/passwd')
.set('Content-Type', 'text/plain')
.send('root:x:0:0:root:/root:/usr/bin/tclsh')
.expect(403)
.end(done);
it('returns an error on individual save', function(done) {
var opts;
library.init({
library: {
saveEntry: function(_opts) {
opts = _opts;
var err = new Error("message");
err.code = "random_error";
err.status = 400;
var p = Promise.reject(err);
p.catch(()=>{});
return p;
}
}
});
request(app)
.post('/library/non-flow/abc/def')
.send({a:1,b:2,text:"123"})
.expect(400)
.end(function(err,res) {
if (err) {
return done(err);
}
opts.should.have.property('type','non-flow');
opts.should.have.property('path','abc/def');
res.body.should.have.property('code');
res.body.code.should.be.equal("random_error");
res.body.should.have.property('message');
res.body.message.should.be.equal("message");
done();
});
});
});

View File

@@ -20,6 +20,8 @@ var express = require('express');
var sinon = require('sinon');
var locales = require("../../../../red/api/editor/locales");
var i18n = require("../../../../red/util/i18n");
describe("api/editor/locales", function() {
beforeEach(function() {
@@ -30,24 +32,18 @@ describe("api/editor/locales", function() {
var app;
before(function() {
// bit of a mess of internal workings
locales.init({
i18n: {
i: {
lng: function() { return 'en-US'},
setLng: function(lang,callback) {
if (callback) {
callback();
}
}
},
catalog: function(namespace, lang) {
return {namespace:namespace, lang:lang};
}
}
});
locales.init({});
sinon.stub(i18n.i,'lng',function() { return 'en-US'});
sinon.stub(i18n.i,'setLng',function(lang,callback) { if (callback) {callback();}});
sinon.stub(i18n,'catalog',function(namespace, lang) {return {namespace:namespace, lang:lang};});
app = express();
app.get(/locales\/(.+)\/?$/,locales.get);
});
after(function() {
i18n.i.lng.restore();
i18n.i.setLng.restore();
i18n.catalog.restore();
})
it('returns with default language', function(done) {
request(app)
.get("/locales/message-catalog")
@@ -79,30 +75,31 @@ describe("api/editor/locales", function() {
var app;
before(function() {
// bit of a mess of internal workings
locales.init({
i18n: {
catalog: function(namespace, lang) {
sinon.stub(i18n,'catalog',function(namespace, lang) {
return {
"node-red": "should not return",
"test-module-a-id": "test-module-a-catalog",
"test-module-b-id": "test-module-b-catalog",
"test-module-c-id": "test-module-c-catalog"
}[namespace]
}
},
});
locales.init({
nodes: {
getNodeList: function() {
return [
getNodeList: function(opts) {
return Promise.resolve([
{module:"node-red",id:"node-red-id"},
{module:"test-module-a",id:"test-module-a-id"},
{module:"test-module-b",id:"test-module-b-id"}
];
]);
}
}
});
app = express();
app.get("/locales/nodes",locales.getAllNodes);
});
after(function() {
i18n.catalog.restore();
})
it('returns with the node catalogs', function(done) {
request(app)
.get("/locales/nodes")

View File

@@ -17,215 +17,103 @@
var should = require("should");
var request = require('supertest');
var express = require('express');
var bodyParser = require("body-parser");
var sinon = require('sinon');
var when = require('when');
var app = express();
var app;
var info = require("../../../../red/api/editor/settings");
var theme = require("../../../../red/api/editor/theme");
describe("api/editor/settings", function() {
describe("settings handler", function() {
before(function() {
sinon.stub(theme,"settings",function() { return { test: 456 };});
app = express();
app.get("/settings",info.runtimeSettings);
});
before(function() {
sinon.stub(theme,"settings",function() { return { test: 456 };});
app = express();
app.use(bodyParser.json());
app.get("/settings",info.runtimeSettings);
app.get("/settings/user",function(req,res,next) {req.user = "fred"; next()}, info.userSettings);
app.post("/settings/user",function(req,res,next) {req.user = "fred"; next()},info.updateUserSettings);
});
after(function() {
theme.settings.restore();
});
after(function() {
theme.settings.restore();
});
it('returns the filtered settings', function(done) {
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"],
exportNodeSettings: function(obj) {
obj.testNodeSetting = "helloWorld";
}
},
nodes: {
paletteEditorEnabled: function() { return true; },
getCredentialKeyType: function() { return "test-key-type"}
},
log: { error: console.error },
storage: {}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
res.body.should.have.property("version","testVersion");
res.body.should.have.property("paletteCategories",["red","blue","green"]);
res.body.should.have.property("editorTheme",{test:456});
res.body.should.have.property("testNodeSetting","helloWorld");
res.body.should.not.have.property("foo",123);
res.body.should.have.property("flowEncryptionType","test-key-type");
done();
});
});
it('includes project settings if projects available', function(done) {
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"],
exportNodeSettings: function(obj) {
obj.testNodeSetting = "helloWorld";
}
},
nodes: {
paletteEditorEnabled: function() { return true; },
getCredentialKeyType: function() { return "test-key-type"}
},
log: { error: console.error },
storage: {
projects: {
getActiveProject: () => 'test-active-project',
getFlowFilename: () => 'test-flow-file',
getCredentialsFilename: () => 'test-creds-file',
getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
}
it('returns the runtime settings', function(done) {
info.init({
settings: {
getRuntimeSettings: function(opts) {
return Promise.resolve({
a:1,
b:2
})
}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property("project","test-active-project");
res.body.should.not.have.property("files");
res.body.should.have.property("git");
res.body.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
done();
});
}
});
it('includes existing files details if projects enabled but no active project and files exist', function(done) {
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"],
exportNodeSettings: function(obj) {
obj.testNodeSetting = "helloWorld";
}
},
nodes: {
paletteEditorEnabled: function() { return true; },
getCredentialKeyType: function() { return "test-key-type"}
},
log: { error: console.error },
storage: {
projects: {
flowFileExists: () => true,
getActiveProject: () => false,
getFlowFilename: () => 'test-flow-file',
getCredentialsFilename: () => 'test-creds-file',
getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property("a",1);
res.body.should.have.property("b",2);
res.body.should.have.property("editorTheme",{test:456});
done();
});
});
it('returns the user settings', function(done) {
info.init({
settings: {
getUserSettings: function(opts) {
if (opts.user !== "fred") {
return Promise.reject(new Error("Unknown user"));
}
return Promise.resolve({
c:3,
d:4
})
}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.not.have.property("project");
res.body.should.have.property("files");
res.body.files.should.have.property("flow",'test-flow-file');
res.body.files.should.have.property("credentials",'test-creds-file');
res.body.should.have.property("git");
res.body.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
done();
});
}
});
it('does not include file details if projects enabled but no active project and files do not exist', function(done) {
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"],
exportNodeSettings: function(obj) {
obj.testNodeSetting = "helloWorld";
}
},
nodes: {
paletteEditorEnabled: function() { return true; },
getCredentialKeyType: function() { return "test-key-type"}
},
log: { error: console.error },
storage: {
projects: {
flowFileExists: () => false,
getActiveProject: () => false,
getFlowFilename: () => 'test-flow-file',
getCredentialsFilename: () => 'test-creds-file',
getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
request(app)
.get("/settings/user")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.eql({c:3,d:4});
done();
});
});
it('updates the user settings', function(done) {
var update;
info.init({
settings: {
updateUserSettings: function(opts) {
if (opts.user !== "fred") {
return Promise.reject(new Error("Unknown user"));
}
update = opts.settings;
return Promise.resolve()
}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.not.have.property("project");
res.body.should.not.have.property("files");
res.body.should.have.property("git");
res.body.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
done();
});
}
});
it('overrides palette editable if runtime says it is disabled', function(done) {
info.init({
settings: {
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"],
exportNodeSettings: function() {}
},
nodes: {
paletteEditorEnabled: function() { return false; },
getCredentialKeyType: function() { return "test-key-type"}
},
log: { error: console.error },
storage: {}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
res.body.should.have.property("version","testVersion");
res.body.should.have.property("paletteCategories",["red","blue","green"]);
res.body.should.have.property("editorTheme");
res.body.editorTheme.should.have.property("test",456);
res.body.editorTheme.should.have.property("palette",{editable:false});
done();
});
request(app)
.post("/settings/user")
.send({
e:4,
f:5
})
.expect(204)
.end(function(err,res) {
if (err) {
return done(err);
}
update.should.eql({e:4,f:5});
done();
});
});
});

View File

@@ -18,83 +18,42 @@ var should = require("should");
var sinon = require("sinon");
var request = require("supertest");
var express = require("express");
var editorApi = require("../../../../red/api/editor");
var comms = require("../../../../red/api/editor/comms");
var info = require("../../../../red/api/editor/settings");
var auth = require("../../../../red/api/auth");
var sshkeys = require("../../../../red/api/editor/sshkeys");
var when = require("when");
var bodyParser = require("body-parser");
var fs = require("fs-extra");
var fspath = require("path");
describe("api/editor/sshkeys", function() {
var app;
var mockList = [
'library','theme','locales','credentials','comms'
]
var isStarted = true;
var errors = [];
var session_data = {};
var mockRuntime = {
settings:{
httpNodeRoot: true,
httpAdminRoot: true,
disableEditor: false,
exportNodeSettings:function(){},
storage: {
getSessions: function(){
return when.resolve(session_data);
},
setSessions: function(_session) {
session_data = _session;
return when.resolve();
}
}
},
log:{audit:function(){},error:function(msg){errors.push(msg)},trace:function(){}},
storage: {
projects: {
ssh: {
init: function(){},
listSSHKeys: function(){},
getSSHKey: function(){},
generateSSHKey: function(){},
deleteSSHKey: function(){}
}
}
},
events:{on:function(){},removeListener:function(){}},
isStarted: function() { return isStarted; },
nodes: {paletteEditorEnabled: function() { return false }}
};
settings: {
getUserKeys: function() {},
getUserKey: function() {},
generateUserKey: function() {},
removeUserKey: function() {}
}
}
before(function() {
auth.init(mockRuntime);
sshkeys.init(mockRuntime);
app = express();
app.use(bodyParser.json());
app.use(editorApi.init({},mockRuntime));
app.use("/settings/user/keys", sshkeys.app());
});
after(function() {
})
beforeEach(function() {
sinon.stub(mockRuntime.storage.projects.ssh, "listSSHKeys");
sinon.stub(mockRuntime.storage.projects.ssh, "getSSHKey");
sinon.stub(mockRuntime.storage.projects.ssh, "generateSSHKey");
sinon.stub(mockRuntime.storage.projects.ssh, "deleteSSHKey");
sinon.stub(mockRuntime.settings, "getUserKeys");
sinon.stub(mockRuntime.settings, "getUserKey");
sinon.stub(mockRuntime.settings, "generateUserKey");
sinon.stub(mockRuntime.settings, "removeUserKey");
})
afterEach(function() {
mockRuntime.storage.projects.ssh.listSSHKeys.restore();
mockRuntime.storage.projects.ssh.getSSHKey.restore();
mockRuntime.storage.projects.ssh.generateSSHKey.restore();
mockRuntime.storage.projects.ssh.deleteSSHKey.restore();
mockRuntime.settings.getUserKeys.restore();
mockRuntime.settings.getUserKey.restore();
mockRuntime.settings.generateUserKey.restore();
mockRuntime.settings.removeUserKey.restore();
})
it('GET /settings/user/keys --- return empty list', function(done) {
mockRuntime.storage.projects.ssh.listSSHKeys.returns(Promise.resolve([]));
mockRuntime.settings.getUserKeys.returns(Promise.resolve([]));
request(app)
.get("/settings/user/keys")
.expect(200)
@@ -118,7 +77,7 @@ describe("api/editor/sshkeys", function() {
name: elem
};
});
mockRuntime.storage.projects.ssh.listSSHKeys.returns(Promise.resolve(retList));
mockRuntime.settings.getUserKeys.returns(Promise.resolve(retList));
request(app)
.get("/settings/user/keys")
.expect(200)
@@ -139,16 +98,16 @@ describe("api/editor/sshkeys", function() {
errInstance.code = "test_code";
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.listSSHKeys.returns(p);
mockRuntime.settings.getUserKeys.returns(p);
request(app)
.get("/settings/user/keys")
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal(errInstance.code);
res.body.should.have.property('code');
res.body.code.should.be.equal(errInstance.code);
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.message);
done();
@@ -156,7 +115,12 @@ describe("api/editor/sshkeys", function() {
});
it('GET /settings/user/keys/<key_file_name> --- return 404', function(done) {
mockRuntime.storage.projects.ssh.getSSHKey.returns(Promise.resolve(null));
var errInstance = new Error("Not Found.");
errInstance.code = "not_found";
errInstance.status = 404;
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.settings.getUserKey.returns(p);
request(app)
.get("/settings/user/keys/NOT_REAL")
.expect(404)
@@ -168,19 +132,19 @@ describe("api/editor/sshkeys", function() {
});
});
it('GET /settings/user/keys --- return Unexpected Error', function(done) {
var errInstance = new Error("Messages.....");
var errInstance = new Error();
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.listSSHKeys.returns(p);
mockRuntime.settings.getUserKeys.returns(p)
request(app)
.get("/settings/user/keys")
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("unexpected_error");
res.body.should.have.property('code');
res.body.code.should.be.equal("unexpected_error");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.toString());
done();
@@ -190,7 +154,7 @@ describe("api/editor/sshkeys", function() {
it('GET /settings/user/keys/<key_file_name> --- return content', function(done) {
var key_file_name = "test_key";
var fileContent = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD3a+sgtgzSbbliWxmOq5p6+H/mE+0gjWfLWrkIVmHENd1mifV4uCmIHAR2NfuadUYMQ3+bQ90kpmmEKTMYPsyentsKpHQZxTzG7wOCAIpJnbPTHDMxEJhVTaAwEjbVyMSIzTTPfnhoavWIBu0+uMgKDDlBm+RjlgkFlyhXyCN6UwFrIUUMH6Gw+eQHLiooKIl8ce7uDxIlt+9b7hFCU+sQ3kvuse239DZluu6+8buMWqJvrEHgzS9adRFKku8nSPAEPYn85vDi7OgVAcLQufknNgs47KHBAx9h04LeSrFJ/P5J1b//ItRpMOIme+O9d1BR46puzhvUaCHLdvO9czj+OmW+dIm+QIk6lZIOOMnppG72kZxtLfeKT16ur+2FbwAdL9ItBp4BI/YTlBPoa5mLMxpuWfmX1qHntvtGc9wEwS1P7YFfmF3XiK5apxalzrn0Qlr5UmDNbVIqJb1OlbC0w03Z0oktti1xT+R2DGOLWM4lBbpXDHV1BhQ7oYOvbUD8Cnof55lTP0WHHsOHlQc/BGDti1XA9aBX/OzVyzBUYEf0pkimsD0RYo6aqt7QwehJYdlz9x1NBguBffT0s4NhNb9IWr+ASnFPvNl2sw4XH/8U0J0q8ZkMpKkbLM1Zdp1Fv00GF0f5UNRokai6uM3w/ccantJ3WvZ6GtctqytWrw== \n";
mockRuntime.storage.projects.ssh.getSSHKey.returns(Promise.resolve(fileContent));
mockRuntime.settings.getUserKey.returns(Promise.resolve(fileContent));
request(app)
.get("/settings/user/keys/" + key_file_name)
.expect(200)
@@ -198,7 +162,8 @@ describe("api/editor/sshkeys", function() {
if (err) {
return done(err);
}
mockRuntime.storage.projects.ssh.getSSHKey.called.should.be.true();
mockRuntime.settings.getUserKey.called.should.be.true();
mockRuntime.settings.getUserKey.firstCall.args[0].should.eql({ user: undefined, id: 'test_key' });
res.body.should.be.deepEqual({ publickey: fileContent });
done();
});
@@ -210,16 +175,16 @@ describe("api/editor/sshkeys", function() {
errInstance.code = "test_code";
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.getSSHKey.returns(p);
mockRuntime.settings.getUserKey.returns(p);
request(app)
.get("/settings/user/keys/" + key_file_name)
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal(errInstance.code);
res.body.should.have.property('code');
res.body.code.should.be.equal(errInstance.code);
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.message);
done();
@@ -231,25 +196,25 @@ describe("api/editor/sshkeys", function() {
var errInstance = new Error("Messages.....");
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.getSSHKey.returns(p);
mockRuntime.settings.getUserKey.returns(p);
request(app)
.get("/settings/user/keys/" + key_file_name)
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("unexpected_error");
res.body.should.have.property('code');
res.body.code.should.be.equal("unexpected_error");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.toString());
res.body.message.should.be.equal("Messages.....");
done();
});
});
it('POST /settings/user/keys --- success', function(done) {
var key_file_name = "test_key";
mockRuntime.storage.projects.ssh.generateSSHKey.returns(Promise.resolve(key_file_name));
mockRuntime.settings.generateUserKey.returns(Promise.resolve(key_file_name));
request(app)
.post("/settings/user/keys")
.send({ name: key_file_name })
@@ -262,41 +227,23 @@ describe("api/editor/sshkeys", function() {
});
});
it('POST /settings/user/keys --- return parameter error', function(done) {
var key_file_name = "test_key";
mockRuntime.storage.projects.ssh.generateSSHKey.returns(Promise.resolve(key_file_name));
request(app)
.post("/settings/user/keys")
.expect(400)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("unexpected_error");
res.body.should.have.property('message');
res.body.message.should.be.equal("You need to have body or body.name");
done();
});
});
it('POST /settings/user/keys --- return Error', function(done) {
var key_file_name = "test_key";
var errInstance = new Error("Messages.....");
errInstance.code = "test_code";
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.generateSSHKey.returns(p);
mockRuntime.settings.generateUserKey.returns(p);
request(app)
.post("/settings/user/keys")
.send({ name: key_file_name })
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("test_code");
res.body.should.have.property('code');
res.body.code.should.be.equal("test_code");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.message);
done();
@@ -308,26 +255,26 @@ describe("api/editor/sshkeys", function() {
var errInstance = new Error("Messages.....");
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.generateSSHKey.returns(p);
mockRuntime.settings.generateUserKey.returns(p);
request(app)
.post("/settings/user/keys")
.send({ name: key_file_name })
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("unexpected_error");
res.body.should.have.property('code');
res.body.code.should.be.equal("unexpected_error");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.toString());
res.body.message.should.be.equal("Messages.....");
done();
});
});
it('DELETE /settings/user/keys/<key_file_name> --- success', function(done) {
var key_file_name = "test_key";
mockRuntime.storage.projects.ssh.deleteSSHKey.returns(Promise.resolve(true));
mockRuntime.settings.removeUserKey.returns(Promise.resolve(true));
request(app)
.delete("/settings/user/keys/" + key_file_name)
.expect(204)
@@ -346,16 +293,16 @@ describe("api/editor/sshkeys", function() {
errInstance.code = "test_code";
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.deleteSSHKey.returns(p);
mockRuntime.settings.removeUserKey.returns(p);
request(app)
.delete("/settings/user/keys/" + key_file_name)
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("test_code");
res.body.should.have.property('code');
res.body.code.should.be.equal("test_code");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.message);
done();
@@ -367,18 +314,18 @@ describe("api/editor/sshkeys", function() {
var errInstance = new Error("Messages.....");
var p = Promise.reject(errInstance);
p.catch(()=>{});
mockRuntime.storage.projects.ssh.deleteSSHKey.returns(p);
mockRuntime.settings.removeUserKey.returns(p);
request(app)
.delete("/settings/user/keys/" + key_file_name)
.expect(400)
.expect(500)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property('error');
res.body.error.should.be.equal("unexpected_error");
res.body.should.have.property('code');
res.body.code.should.be.equal("unexpected_error");
res.body.should.have.property('message');
res.body.message.should.be.equal(errInstance.toString());
res.body.message.should.be.equal('Messages.....');
done();
});
});

View File

@@ -33,7 +33,7 @@ describe("api/editor/theme", function() {
fs.statSync.restore();
});
it("applies the default theme", function() {
var result = theme.init({settings:{},version:function() { return '123.456'}});
var result = theme.init({});
should.not.exist(result);
var context = theme.context();
@@ -43,13 +43,12 @@ describe("api/editor/theme", function() {
context.should.have.a.property("header");
context.header.should.have.a.property("title","Node-RED");
context.header.should.have.a.property("image","red/images/node-red.png");
context.should.have.a.property("version","123.456");
should.not.exist(theme.settings());
});
it("picks up custom theme", function() {
theme.init({settings:{
theme.init({
editorTheme: {
page: {
title: "Test Page Title",
@@ -84,7 +83,7 @@ describe("api/editor/theme", function() {
image: "/absolute/path/to/login/page/big/image" // a 256x256 image
}
}
}});
});
theme.app();

View File

@@ -20,8 +20,6 @@ var express = require("express");
var fs = require("fs");
var path = require("path");
var EventEmitter = require('events').EventEmitter;
var events = new EventEmitter();
var ui = require("../../../../red/api/editor/ui");
@@ -30,10 +28,13 @@ describe("api/editor/ui", function() {
before(function() {
ui.init({
events:events,
nodes: {
getNodeIconPath: function(module,icon) {
return path.resolve(__dirname+'/../../../../public/icons/arrow-in.png');
getIcon: function(opts) {
return new Promise(function(resolve,reject) {
fs.readFile(path.resolve(__dirname+'/../../../../public/icons/arrow-in.png'), function(err,data) {
resolve(data);
})
});
}
}
});