Merge branch 'release/2.8.8' into production
This commit is contained in:
commit
0417e272e8
54
CHANGES.md
54
CHANGES.md
|
@ -1,3 +1,27 @@
|
||||||
|
2015-01-07, Version 2.8.8
|
||||||
|
=========================
|
||||||
|
|
||||||
|
* Fix context middleware to preserve domains (Pham Anh Tuan)
|
||||||
|
|
||||||
|
* Additional password reset unit tests for API and REST - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Small formatting update to have consistency with identical logic in other areas. - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Simplify the API test for invalidCredentials (removed create), move above REST calls for better grouping of tests - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Force request to send body as string, this ensures headers aren't automatically set to application/json - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Ensure error checking logic is in place for all REST calls, expand formatting for consistency with existing instances. - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Correct invalidCredentials so that it differs from validCredentialsEmailVerified, unit test now passes as desired. - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* Update to demonstrate unit test is actually failing due to incorrect values of invalidCredentials - strongloop/loopback#944 (Ron Edgecomb)
|
||||||
|
|
||||||
|
* fix jscs warning (Clark Wang)
|
||||||
|
|
||||||
|
* fix nestRemoting is nesting hooks from other relations (Clark Wang)
|
||||||
|
|
||||||
|
|
||||||
2015-01-06, Version 2.8.7
|
2015-01-06, Version 2.8.7
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -671,6 +695,10 @@
|
||||||
|
|
||||||
* Enhance the error message (Raymond Feng)
|
* Enhance the error message (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
|
2014-07-16, Version 2.0.0-beta7
|
||||||
|
===============================
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
* Bump version (Raymond Feng)
|
||||||
|
|
||||||
* 2.0.0-beta6 (Miroslav Bajtoš)
|
* 2.0.0-beta6 (Miroslav Bajtoš)
|
||||||
|
@ -811,13 +839,6 @@
|
||||||
2014-07-16, Version 1.10.0
|
2014-07-16, Version 1.10.0
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-07-16, Version 2.0.0-beta7
|
|
||||||
===============================
|
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
|
||||||
|
|
||||||
* Remove unused dep (Raymond Feng)
|
* Remove unused dep (Raymond Feng)
|
||||||
|
|
||||||
* Bump version and update deps (Raymond Feng)
|
* Bump version and update deps (Raymond Feng)
|
||||||
|
@ -1264,14 +1285,6 @@
|
||||||
|
|
||||||
* 2.0.0-beta1 (Ritchie Martori)
|
* 2.0.0-beta1 (Ritchie Martori)
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
|
||||||
|
|
||||||
* Add postgresql to the keywords (Raymond Feng)
|
|
||||||
|
|
||||||
* updated package.json with SOAP and framework keywords (altsang)
|
|
||||||
|
|
||||||
* updated package.json with keywords and updated description (Raymond Feng)
|
|
||||||
|
|
||||||
* Make app.datasources unique per app instance (Miroslav Bajtoš)
|
* Make app.datasources unique per app instance (Miroslav Bajtoš)
|
||||||
|
|
||||||
* Add RC version (Ritchie Martori)
|
* Add RC version (Ritchie Martori)
|
||||||
|
@ -1337,11 +1350,6 @@
|
||||||
* Add Change model (Ritchie Martori)
|
* Add Change model (Ritchie Martori)
|
||||||
|
|
||||||
|
|
||||||
2014-05-27, Version 1.8.4
|
|
||||||
=========================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-05-27, Version 1.8.5
|
2014-05-27, Version 1.8.5
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -1353,8 +1361,14 @@
|
||||||
|
|
||||||
* updated package.json with keywords and updated description (Raymond Feng)
|
* updated package.json with keywords and updated description (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
|
2014-05-27, Version 1.8.4
|
||||||
|
=========================
|
||||||
|
|
||||||
* Add more keywords (Raymond Feng)
|
* Add more keywords (Raymond Feng)
|
||||||
|
|
||||||
|
* Bump version (Raymond Feng)
|
||||||
|
|
||||||
* app: flatten model config (Miroslav Bajtoš)
|
* app: flatten model config (Miroslav Bajtoš)
|
||||||
|
|
||||||
* Fix the test for mocha 1.19.0 (Raymond Feng)
|
* Fix the test for mocha 1.19.0 (Raymond Feng)
|
||||||
|
|
12
lib/model.js
12
lib/model.js
|
@ -654,7 +654,7 @@ Model.nestRemoting = function(relationName, options, cb) {
|
||||||
opts.returns = [].concat(method.returns || []);
|
opts.returns = [].concat(method.returns || []);
|
||||||
opts.description = method.description;
|
opts.description = method.description;
|
||||||
opts.rest = extend({}, method.rest || {});
|
opts.rest = extend({}, method.rest || {});
|
||||||
opts.rest.delegateTo = method.name;
|
opts.rest.delegateTo = method;
|
||||||
|
|
||||||
opts.http = [];
|
opts.http = [];
|
||||||
var routes = [].concat(method.http || []);
|
var routes = [].concat(method.http || []);
|
||||||
|
@ -718,18 +718,18 @@ Model.nestRemoting = function(relationName, options, cb) {
|
||||||
|
|
||||||
sharedClass.methods().forEach(function(method) {
|
sharedClass.methods().forEach(function(method) {
|
||||||
var delegateTo = method.rest && method.rest.delegateTo;
|
var delegateTo = method.rest && method.rest.delegateTo;
|
||||||
if (delegateTo) {
|
if (delegateTo && delegateTo.ctor == relation.modelTo) {
|
||||||
var before = method.isStatic ? beforeListeners : beforeListeners['prototype'];
|
var before = method.isStatic ? beforeListeners : beforeListeners['prototype'];
|
||||||
var after = method.isStatic ? afterListeners : afterListeners['prototype'];
|
var after = method.isStatic ? afterListeners : afterListeners['prototype'];
|
||||||
var m = method.isStatic ? method.name : 'prototype.' + method.name;
|
var m = method.isStatic ? method.name : 'prototype.' + method.name;
|
||||||
if (before && before[delegateTo]) {
|
if (before && before[delegateTo.name]) {
|
||||||
self.beforeRemote(m, function(ctx, result, next) {
|
self.beforeRemote(m, function(ctx, result, next) {
|
||||||
before[delegateTo]._listeners.call(null, ctx, next);
|
before[delegateTo.name]._listeners.call(null, ctx, next);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (after && after[delegateTo]) {
|
if (after && after[delegateTo.name]) {
|
||||||
self.afterRemote(m, function(ctx, result, next) {
|
self.afterRemote(m, function(ctx, result, next) {
|
||||||
after[delegateTo]._listeners.call(null, ctx, next);
|
after[delegateTo.name]._listeners.call(null, ctx, next);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "loopback",
|
"name": "loopback",
|
||||||
"version": "2.8.7",
|
"version": "2.8.8",
|
||||||
"description": "LoopBack: Open Source Framework for Node.js",
|
"description": "LoopBack: Open Source Framework for Node.js",
|
||||||
"homepage": "http://loopback.io",
|
"homepage": "http://loopback.io",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -102,6 +102,6 @@
|
||||||
"url": "https://github.com/strongloop/loopback/blob/master/LICENSE"
|
"url": "https://github.com/strongloop/loopback/blob/master/LICENSE"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"sl-blip": "http://blip.strongloop.com/loopback@2.8.7"
|
"sl-blip": "http://blip.strongloop.com/loopback@2.8.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ var loopback = require('../../lib/loopback');
|
||||||
var juggler = require('loopback-datasource-juggler');
|
var juggler = require('loopback-datasource-juggler');
|
||||||
var remoting = require('strong-remoting');
|
var remoting = require('strong-remoting');
|
||||||
var cls = require('continuation-local-storage');
|
var cls = require('continuation-local-storage');
|
||||||
|
var domain = require('domain');
|
||||||
|
|
||||||
module.exports = context;
|
module.exports = context;
|
||||||
|
|
||||||
|
@ -44,6 +45,13 @@ function context(options) {
|
||||||
var scope = options.name || name;
|
var scope = options.name || name;
|
||||||
var enableHttpContext = options.enableHttpContext || false;
|
var enableHttpContext = options.enableHttpContext || false;
|
||||||
var ns = createContext(scope);
|
var ns = createContext(scope);
|
||||||
|
|
||||||
|
var currentDomain = process.domain = domain.create();
|
||||||
|
currentDomain.oldBind = currentDomain.bind;
|
||||||
|
currentDomain.bind = function(callback, context) {
|
||||||
|
return currentDomain.oldBind(ns.bind(callback, context), context);
|
||||||
|
};
|
||||||
|
|
||||||
// Return the middleware
|
// Return the middleware
|
||||||
return function contextHandler(req, res, next) {
|
return function contextHandler(req, res, next) {
|
||||||
if (req.loopbackContext) {
|
if (req.loopbackContext) {
|
||||||
|
@ -53,7 +61,12 @@ function context(options) {
|
||||||
// Bind req/res event emitters to the given namespace
|
// Bind req/res event emitters to the given namespace
|
||||||
ns.bindEmitter(req);
|
ns.bindEmitter(req);
|
||||||
ns.bindEmitter(res);
|
ns.bindEmitter(res);
|
||||||
|
|
||||||
|
currentDomain.add(req);
|
||||||
|
currentDomain.add(res);
|
||||||
|
|
||||||
// Create namespace for the request context
|
// Create namespace for the request context
|
||||||
|
currentDomain.run(function() {
|
||||||
ns.run(function processRequestInContext(context) {
|
ns.run(function processRequestInContext(context) {
|
||||||
// Run the code in the context of the namespace
|
// Run the code in the context of the namespace
|
||||||
if (enableHttpContext) {
|
if (enableHttpContext) {
|
||||||
|
@ -61,6 +74,7 @@ function context(options) {
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
var it = require('./util/it');
|
var it = require('./util/it');
|
||||||
|
var describe = require('./util/describe');
|
||||||
|
var Domain = require('domain');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
describe('loopback', function() {
|
describe('loopback', function() {
|
||||||
var nameCounter = 0;
|
var nameCounter = 0;
|
||||||
|
@ -388,4 +391,72 @@ describe('loopback', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.onServer('loopback.getCurrentContext', function() {
|
||||||
|
var runInOtherDomain;
|
||||||
|
var runnerInterval;
|
||||||
|
|
||||||
|
before(function setupRunInOtherDomain() {
|
||||||
|
var emitterInOtherDomain = new EventEmitter();
|
||||||
|
Domain.create().add(emitterInOtherDomain);
|
||||||
|
|
||||||
|
runInOtherDomain = function(fn) {
|
||||||
|
emitterInOtherDomain.once('run', fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
runnerInterval = setInterval(function() {
|
||||||
|
emitterInOtherDomain.emit('run');
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function tearDownRunInOtherDomain() {
|
||||||
|
clearInterval(runnerInterval);
|
||||||
|
});
|
||||||
|
|
||||||
|
// See the following two items for more details:
|
||||||
|
// https://github.com/strongloop/loopback/issues/809
|
||||||
|
// https://github.com/strongloop/loopback/pull/337#issuecomment-61680577
|
||||||
|
it('preserves callback domain', function(done) {
|
||||||
|
var app = loopback();
|
||||||
|
app.use(loopback.rest());
|
||||||
|
app.dataSource('db', { connector: 'memory' });
|
||||||
|
|
||||||
|
var TestModel = loopback.createModel({ name: 'TestModel' });
|
||||||
|
app.model(TestModel, { dataSource: 'db', public: true });
|
||||||
|
|
||||||
|
// function for remote method
|
||||||
|
TestModel.test = function(inst, cb) {
|
||||||
|
var tmpCtx = loopback.getCurrentContext();
|
||||||
|
if (tmpCtx) tmpCtx.set('data', 'a value stored in context');
|
||||||
|
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
|
||||||
|
runInOtherDomain(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// remote method
|
||||||
|
TestModel.remoteMethod('test', {
|
||||||
|
accepts: { arg: 'inst', type: uniqueModelName },
|
||||||
|
returns: { root: true },
|
||||||
|
http: { path: '/test', verb: 'get' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// after remote hook
|
||||||
|
TestModel.afterRemote('**', function(ctxx, inst, next) {
|
||||||
|
var tmpCtx = loopback.getCurrentContext();
|
||||||
|
if (tmpCtx) {
|
||||||
|
ctxx.result.data = tmpCtx.get('data');
|
||||||
|
}else {
|
||||||
|
ctxx.result.data = 'context not available';
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
request(app)
|
||||||
|
.get('/TestModels/test')
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) return done(err);
|
||||||
|
expect(res.body.data).to.equal('a value stored in context');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1164,8 +1164,15 @@ describe('relations - integration', function() {
|
||||||
{ properties: { text: 'string' }, dataSource: 'db',
|
{ properties: { text: 'string' }, dataSource: 'db',
|
||||||
plural: 'notes' }
|
plural: 'notes' }
|
||||||
);
|
);
|
||||||
|
var Chapter = app.model(
|
||||||
|
'Chapter',
|
||||||
|
{ properties: { name: 'string' }, dataSource: 'db',
|
||||||
|
plural: 'chapters' }
|
||||||
|
);
|
||||||
Book.hasMany(Page);
|
Book.hasMany(Page);
|
||||||
|
Book.hasMany(Chapter);
|
||||||
Page.hasMany(Note);
|
Page.hasMany(Note);
|
||||||
|
Chapter.hasMany(Note);
|
||||||
Image.belongsTo(Book);
|
Image.belongsTo(Book);
|
||||||
|
|
||||||
// fake a remote method that match the filter in Model.nestRemoting()
|
// fake a remote method that match the filter in Model.nestRemoting()
|
||||||
|
@ -1176,6 +1183,7 @@ describe('relations - integration', function() {
|
||||||
Page.remoteMethod('__throw__errors', { isStatic: false, http: { path: '/throws', verb: 'get' } });
|
Page.remoteMethod('__throw__errors', { isStatic: false, http: { path: '/throws', verb: 'get' } });
|
||||||
|
|
||||||
Book.nestRemoting('pages');
|
Book.nestRemoting('pages');
|
||||||
|
Book.nestRemoting('chapters');
|
||||||
Image.nestRemoting('book');
|
Image.nestRemoting('book');
|
||||||
|
|
||||||
expect(Book.prototype['__findById__pages__notes']).to.be.a.function;
|
expect(Book.prototype['__findById__pages__notes']).to.be.a.function;
|
||||||
|
@ -1212,6 +1220,19 @@ describe('relations - integration', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
before(function createChapters(done) {
|
||||||
|
var test = this;
|
||||||
|
test.book.chapters.create({ name: 'Chapter 1' },
|
||||||
|
function(err, chapter) {
|
||||||
|
if (err) return done(err);
|
||||||
|
test.chapter = chapter;
|
||||||
|
chapter.notes.create({ text: 'Chapter Note 1' }, function(err, note) {
|
||||||
|
test.cnote = note;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
before(function createCover(done) {
|
before(function createCover(done) {
|
||||||
var test = this;
|
var test = this;
|
||||||
app.models.Image.create({ name: 'Cover 1', book: test.book },
|
app.models.Image.create({ name: 'Cover 1', book: test.book },
|
||||||
|
@ -1300,6 +1321,16 @@ describe('relations - integration', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should nest remote hooks of ModelTo - hasMany findById', function(done) {
|
||||||
|
var test = this;
|
||||||
|
this.get('/api/books/' + test.book.id + '/chapters/' + test.chapter.id + '/notes/' + test.cnote.id)
|
||||||
|
.expect(200, function(err, res) {
|
||||||
|
expect(res.headers['x-before']).to.empty();
|
||||||
|
expect(res.headers['x-after']).to.empty();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should have proper http.path for remoting', function() {
|
it('should have proper http.path for remoting', function() {
|
||||||
[app.models.Book, app.models.Image].forEach(function(Model) {
|
[app.models.Book, app.models.Image].forEach(function(Model) {
|
||||||
Model.sharedClass.methods().forEach(function(method) {
|
Model.sharedClass.methods().forEach(function(method) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe('User', function() {
|
||||||
var validCredentialsEmailVerified = {email: 'foo1@bar.com', password: 'bar1', emailVerified: true};
|
var validCredentialsEmailVerified = {email: 'foo1@bar.com', password: 'bar1', emailVerified: true};
|
||||||
var validCredentialsEmailVerifiedOverREST = {email: 'foo2@bar.com', password: 'bar2', emailVerified: true};
|
var validCredentialsEmailVerifiedOverREST = {email: 'foo2@bar.com', password: 'bar2', emailVerified: true};
|
||||||
var validCredentialsWithTTL = {email: 'foo@bar.com', password: 'bar', ttl: 3600};
|
var validCredentialsWithTTL = {email: 'foo@bar.com', password: 'bar', ttl: 3600};
|
||||||
var invalidCredentials = {email: 'foo1@bar.com', password: 'bar1'};
|
var invalidCredentials = {email: 'foo1@bar.com', password: 'invalid'};
|
||||||
var incompleteCredentials = {password: 'bar1'};
|
var incompleteCredentials = {password: 'bar1'};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -142,6 +142,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send(validCredentialsEmailVerifiedOverREST)
|
.send(validCredentialsEmailVerifiedOverREST)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
assert(!res.body.emailVerified);
|
assert(!res.body.emailVerified);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -197,6 +200,14 @@ describe('User', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Login should only allow correct credentials', function(done) {
|
||||||
|
User.login(invalidCredentials, function(err, accessToken) {
|
||||||
|
assert(err);
|
||||||
|
assert(!accessToken);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Login a user over REST by providing credentials', function(done) {
|
it('Login a user over REST by providing credentials', function(done) {
|
||||||
request(app)
|
request(app)
|
||||||
.post('/users/login')
|
.post('/users/login')
|
||||||
|
@ -204,7 +215,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send(validCredentials)
|
.send(validCredentials)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var accessToken = res.body;
|
var accessToken = res.body;
|
||||||
|
|
||||||
assert(accessToken.userId);
|
assert(accessToken.userId);
|
||||||
|
@ -223,6 +236,9 @@ describe('User', function() {
|
||||||
.expect(401)
|
.expect(401)
|
||||||
.send(invalidCredentials)
|
.send(invalidCredentials)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -234,6 +250,9 @@ describe('User', function() {
|
||||||
.expect(400)
|
.expect(400)
|
||||||
.send(incompleteCredentials)
|
.send(incompleteCredentials)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -244,8 +263,11 @@ describe('User', function() {
|
||||||
.set('Content-Type', null)
|
.set('Content-Type', null)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(400)
|
.expect(400)
|
||||||
.send(validCredentials)
|
.send(JSON.stringify(validCredentials))
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -257,7 +279,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var token = res.body;
|
var token = res.body;
|
||||||
expect(token.user, 'body.user').to.not.equal(undefined);
|
expect(token.user, 'body.user').to.not.equal(undefined);
|
||||||
expect(token.user, 'body.user')
|
expect(token.user, 'body.user')
|
||||||
|
@ -273,7 +297,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var token = res.body;
|
var token = res.body;
|
||||||
expect(token.user, 'body.user').to.not.equal(undefined);
|
expect(token.user, 'body.user').to.not.equal(undefined);
|
||||||
expect(token.user, 'body.user')
|
expect(token.user, 'body.user')
|
||||||
|
@ -282,15 +308,6 @@ describe('User', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Login should only allow correct credentials', function(done) {
|
|
||||||
User.create({email: 'foo22@bar.com', password: 'bar'}, function(user, err) {
|
|
||||||
User.login({email: 'foo44@bar.com', password: 'bar'}, function(err, accessToken) {
|
|
||||||
assert(err);
|
|
||||||
assert(!accessToken);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertGoodToken(accessToken) {
|
function assertGoodToken(accessToken) {
|
||||||
|
@ -329,7 +346,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send(validCredentialsEmailVerified)
|
.send(validCredentialsEmailVerified)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var accessToken = res.body;
|
var accessToken = res.body;
|
||||||
|
|
||||||
assertGoodToken(accessToken);
|
assertGoodToken(accessToken);
|
||||||
|
@ -346,6 +365,9 @@ describe('User', function() {
|
||||||
.expect(401)
|
.expect(401)
|
||||||
.send(validCredentials)
|
.send(validCredentials)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -535,7 +557,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send({email: 'foo@bar.com', password: 'bar'})
|
.send({email: 'foo@bar.com', password: 'bar'})
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var accessToken = res.body;
|
var accessToken = res.body;
|
||||||
|
|
||||||
assert(accessToken.userId);
|
assert(accessToken.userId);
|
||||||
|
@ -558,7 +582,9 @@ describe('User', function() {
|
||||||
assert(token);
|
assert(token);
|
||||||
|
|
||||||
return function(err) {
|
return function(err) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
AccessToken.findById(token, function(err, accessToken) {
|
AccessToken.findById(token, function(err, accessToken) {
|
||||||
assert(!accessToken, 'accessToken should not exist after logging out');
|
assert(!accessToken, 'accessToken should not exist after logging out');
|
||||||
|
@ -647,7 +673,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send({email: 'bar@bat.com', password: 'bar'})
|
.send({email: 'bar@bat.com', password: 'bar'})
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -678,7 +706,9 @@ describe('User', function() {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.send({email: 'bar@bat.com', password: 'bar'})
|
.send({email: 'bar@bat.com', password: 'bar'})
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -761,7 +791,9 @@ describe('User', function() {
|
||||||
+ '&redirect=' + encodeURIComponent(options.redirect))
|
+ '&redirect=' + encodeURIComponent(options.redirect))
|
||||||
.expect(400)
|
.expect(400)
|
||||||
.end(function(err, res) {
|
.end(function(err, res) {
|
||||||
if (err) return done(err);
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
assert(res.body.error);
|
assert(res.body.error);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -772,9 +804,17 @@ describe('User', function() {
|
||||||
|
|
||||||
describe('Password Reset', function() {
|
describe('Password Reset', function() {
|
||||||
describe('User.resetPassword(options, cb)', function() {
|
describe('User.resetPassword(options, cb)', function() {
|
||||||
|
var email = 'foo@bar.com';
|
||||||
|
|
||||||
|
it('Requires email address to reset password', function(done) {
|
||||||
|
User.resetPassword({ }, function(err) {
|
||||||
|
assert(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Creates a temp accessToken to allow a user to change password', function(done) {
|
it('Creates a temp accessToken to allow a user to change password', function(done) {
|
||||||
var calledBack = false;
|
var calledBack = false;
|
||||||
var email = 'foo@bar.com';
|
|
||||||
|
|
||||||
User.resetPassword({
|
User.resetPassword({
|
||||||
email: email
|
email: email
|
||||||
|
@ -794,6 +834,35 @@ describe('User', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Password reset over REST rejected without email address', function(done) {
|
||||||
|
request(app)
|
||||||
|
.post('/users/reset')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(400)
|
||||||
|
.send({ })
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Password reset over REST requires email address', function(done) {
|
||||||
|
request(app)
|
||||||
|
.post('/users/reset')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(204)
|
||||||
|
.send({ email: email })
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
assert.deepEqual(res.body, { });
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue