2018-01-03 04:05:53 +00:00
|
|
|
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
|
2016-05-03 22:50:21 +00:00
|
|
|
// Node module: loopback
|
|
|
|
// This file is licensed under the MIT License.
|
|
|
|
// License text available at https://opensource.org/licenses/MIT
|
|
|
|
|
2016-11-15 21:46:23 +00:00
|
|
|
'use strict';
|
2015-12-31 23:41:18 +00:00
|
|
|
var _describe = {};
|
|
|
|
var _it = {};
|
|
|
|
var _beforeEach = {};
|
|
|
|
var helpers = {
|
|
|
|
describe: _describe,
|
|
|
|
it: _it,
|
2016-04-01 09:14:26 +00:00
|
|
|
beforeEach: _beforeEach,
|
2015-12-31 23:41:18 +00:00
|
|
|
};
|
|
|
|
module.exports = helpers;
|
|
|
|
|
|
|
|
var assert = require('assert');
|
|
|
|
var request = require('supertest');
|
2016-04-27 11:15:24 +00:00
|
|
|
var chai = require('chai');
|
|
|
|
var expect = chai.expect;
|
|
|
|
var sinon = require('sinon');
|
|
|
|
chai.use(require('sinon-chai'));
|
2015-12-31 23:41:18 +00:00
|
|
|
|
|
|
|
_beforeEach.withApp = function(app) {
|
|
|
|
if (app.models.User) {
|
|
|
|
// Speed up the password hashing algorithm
|
|
|
|
app.models.User.settings.saltWorkFactor = 4;
|
|
|
|
}
|
|
|
|
|
2016-01-01 00:52:31 +00:00
|
|
|
beforeEach(function(done) {
|
2015-12-31 23:41:18 +00:00
|
|
|
this.app = app;
|
|
|
|
var _request = this.request = request(app);
|
|
|
|
this.post = _request.post;
|
|
|
|
this.get = _request.get;
|
|
|
|
this.put = _request.put;
|
|
|
|
this.del = _request.del;
|
2017-01-13 10:03:06 +00:00
|
|
|
this.patch = _request.patch;
|
2016-01-01 00:52:31 +00:00
|
|
|
|
|
|
|
if (app.booting) {
|
|
|
|
return app.once('booted', done);
|
|
|
|
}
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2016-01-01 00:52:31 +00:00
|
|
|
done();
|
2015-12-31 23:41:18 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.withArgs = function() {
|
|
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
|
|
beforeEach(function() {
|
|
|
|
this.args = args;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.givenModel = function(modelName, attrs, optionalHandler) {
|
|
|
|
var modelKey = modelName;
|
|
|
|
|
|
|
|
if (typeof attrs === 'function') {
|
|
|
|
optionalHandler = attrs;
|
|
|
|
attrs = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof optionalHandler === 'string') {
|
|
|
|
modelKey = optionalHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
attrs = attrs || {};
|
|
|
|
|
|
|
|
beforeEach(function(done) {
|
|
|
|
var test = this;
|
|
|
|
var app = this.app;
|
|
|
|
var model = app.models[modelName];
|
2016-05-24 20:46:32 +00:00
|
|
|
|
2016-11-15 21:46:23 +00:00
|
|
|
app.set('remoting', {errorHandler: {debug: true, log: false}});
|
2015-12-31 23:41:18 +00:00
|
|
|
assert(model, 'cannot get model of name ' + modelName + ' from app.models');
|
|
|
|
assert(model.dataSource, 'cannot test model ' + modelName +
|
|
|
|
' without attached dataSource');
|
|
|
|
assert(
|
|
|
|
typeof model.create === 'function',
|
|
|
|
modelName + ' does not have a create method'
|
|
|
|
);
|
|
|
|
|
|
|
|
model.create(attrs, function(err, result) {
|
|
|
|
if (err) {
|
|
|
|
console.error(err.message);
|
|
|
|
if (err.details) console.error(err.details);
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
done(err);
|
|
|
|
} else {
|
|
|
|
test[modelKey] = result;
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
done();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
if (typeof optionalHandler === 'function') {
|
|
|
|
beforeEach(optionalHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
afterEach(function(done) {
|
|
|
|
this[modelKey].destroy(done);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.givenUser = function(attrs, optionalHandler) {
|
|
|
|
_beforeEach.givenModel('user', attrs, optionalHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.givenLoggedInUser = function(credentials, optionalHandler) {
|
|
|
|
_beforeEach.givenUser(credentials, function(done) {
|
|
|
|
var test = this;
|
|
|
|
this.user.constructor.login(credentials, function(err, token) {
|
|
|
|
if (err) {
|
|
|
|
done(err);
|
|
|
|
} else {
|
|
|
|
test.loggedInAccessToken = token;
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
done();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(function(done) {
|
|
|
|
var test = this;
|
|
|
|
this.loggedInAccessToken.destroy(function(err) {
|
|
|
|
if (err) return done(err);
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
test.loggedInAccessToken = undefined;
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.givenAnUnauthenticatedToken = function(attrs, optionalHandler) {
|
|
|
|
_beforeEach.givenModel('accessToken', attrs, optionalHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
_beforeEach.givenAnAnonymousToken = function(attrs, optionalHandler) {
|
2016-11-15 21:46:23 +00:00
|
|
|
_beforeEach.givenModel('accessToken', {id: '$anonymous'}, optionalHandler);
|
2015-12-31 23:41:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
_describe.whenCalledRemotely = function(verb, url, data, cb) {
|
|
|
|
if (cb === undefined) {
|
|
|
|
cb = data;
|
|
|
|
data = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
var urlStr = url;
|
|
|
|
if (typeof url === 'function') {
|
|
|
|
urlStr = '/<dynamic>';
|
|
|
|
}
|
|
|
|
|
|
|
|
describe(verb.toUpperCase() + ' ' + urlStr, function() {
|
|
|
|
beforeEach(function(cb) {
|
|
|
|
if (typeof url === 'function') {
|
|
|
|
this.url = url.call(this);
|
|
|
|
}
|
|
|
|
this.remotely = true;
|
|
|
|
this.verb = verb.toUpperCase();
|
|
|
|
this.url = this.url || url;
|
|
|
|
var methodForVerb = verb.toLowerCase();
|
|
|
|
if (methodForVerb === 'delete') methodForVerb = 'del';
|
|
|
|
|
|
|
|
if (this.request === undefined) {
|
2016-04-01 09:14:26 +00:00
|
|
|
var msg = 'App is not specified. ' +
|
|
|
|
'Please use lt.beforeEach.withApp to specify the app.';
|
|
|
|
throw new Error(msg);
|
2015-12-31 23:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.http = this.request[methodForVerb](this.url);
|
|
|
|
delete this.url;
|
|
|
|
this.http.set('Accept', 'application/json');
|
|
|
|
if (this.loggedInAccessToken) {
|
|
|
|
this.http.set('authorization', this.loggedInAccessToken.id);
|
|
|
|
}
|
|
|
|
if (data) {
|
|
|
|
var payload = data;
|
|
|
|
if (typeof data === 'function')
|
|
|
|
payload = data.call(this);
|
|
|
|
this.http.send(payload);
|
|
|
|
}
|
|
|
|
this.req = this.http.req;
|
|
|
|
var test = this;
|
|
|
|
this.http.end(function(err) {
|
|
|
|
test.req = test.http.req;
|
2017-02-09 15:17:10 +00:00
|
|
|
test.res = test.http.response;
|
2015-12-31 23:41:18 +00:00
|
|
|
delete test.url;
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
cb();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
cb();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_describe.whenLoggedInAsUser = function(credentials, cb) {
|
|
|
|
describe('when logged in as user', function() {
|
|
|
|
_beforeEach.givenLoggedInUser(credentials);
|
2016-05-05 04:09:06 +00:00
|
|
|
|
2015-12-31 23:41:18 +00:00
|
|
|
cb();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_describe.whenCalledByUser = function(credentials, verb, url, data, cb) {
|
|
|
|
describe('when called by logged in user', function() {
|
|
|
|
_beforeEach.givenLoggedInUser(credentials);
|
|
|
|
_describe.whenCalledRemotely(verb, url, data, cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_describe.whenCalledAnonymously = function(verb, url, data, cb) {
|
|
|
|
describe('when called anonymously', function() {
|
|
|
|
_beforeEach.givenAnAnonymousToken();
|
|
|
|
_describe.whenCalledRemotely(verb, url, data, cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_describe.whenCalledUnauthenticated = function(verb, url, data, cb) {
|
|
|
|
describe('when called with unauthenticated token', function() {
|
|
|
|
_beforeEach.givenAnAnonymousToken();
|
|
|
|
_describe.whenCalledRemotely(verb, url, data, cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeAllowed = function() {
|
|
|
|
it('should be allowed', function() {
|
|
|
|
assert(this.req);
|
|
|
|
assert(this.res);
|
|
|
|
// expect success - status 2xx or 3xx
|
|
|
|
expect(this.res.statusCode).to.be.within(100, 399);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeDenied = function() {
|
|
|
|
it('should not be allowed', function() {
|
|
|
|
assert(this.res);
|
|
|
|
var expectedStatus = this.aclErrorStatus ||
|
|
|
|
this.app && this.app.get('aclErrorStatus') ||
|
|
|
|
401;
|
|
|
|
expect(this.res.statusCode).to.equal(expectedStatus);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldNotBeFound = function() {
|
|
|
|
it('should not be found', function() {
|
|
|
|
assert(this.res);
|
|
|
|
assert.equal(this.res.statusCode, 404);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeAllowedWhenCalledAnonymously =
|
|
|
|
function(verb, url, data) {
|
|
|
|
_describe.whenCalledAnonymously(verb, url, data, function() {
|
|
|
|
_it.shouldBeAllowed();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeDeniedWhenCalledAnonymously =
|
|
|
|
function(verb, url) {
|
|
|
|
_describe.whenCalledAnonymously(verb, url, function() {
|
|
|
|
_it.shouldBeDenied();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeAllowedWhenCalledUnauthenticated =
|
|
|
|
function(verb, url, data) {
|
|
|
|
_describe.whenCalledUnauthenticated(verb, url, data, function() {
|
|
|
|
_it.shouldBeAllowed();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeDeniedWhenCalledUnauthenticated =
|
|
|
|
function(verb, url) {
|
|
|
|
_describe.whenCalledUnauthenticated(verb, url, function() {
|
|
|
|
_it.shouldBeDenied();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeAllowedWhenCalledByUser =
|
|
|
|
function(credentials, verb, url, data) {
|
|
|
|
_describe.whenCalledByUser(credentials, verb, url, data, function() {
|
|
|
|
_it.shouldBeAllowed();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
_it.shouldBeDeniedWhenCalledByUser =
|
|
|
|
function(credentials, verb, url) {
|
|
|
|
_describe.whenCalledByUser(credentials, verb, url, function() {
|
|
|
|
_it.shouldBeDenied();
|
|
|
|
});
|
|
|
|
};
|