diff --git a/common/models/access-token.js b/common/models/access-token.js index 209057b1..830188b7 100644 --- a/common/models/access-token.js +++ b/common/models/access-token.js @@ -111,8 +111,8 @@ module.exports = function(AccessToken) { // replacement for deprecated req.param() id = req.params && req.params[param] !== undefined ? req.params[param] : req.body && req.body[param] !== undefined ? req.body[param] : - req.query && req.query[param] !== undefined ? req.query[param] : - undefined; + req.query && req.query[param] !== undefined ? req.query[param] : + undefined; if (typeof id === 'string') { return id; @@ -227,7 +227,7 @@ module.exports = function(AccessToken) { AccessToken.prototype.validate = function(cb) { try { assert( - this.created && typeof this.created.getTime === 'function', + this.created && typeof this.created.getTime === 'function', 'token.created must be a valid Date' ); assert(this.ttl !== 0, 'token.ttl must be not be 0'); diff --git a/common/models/acl.js b/common/models/acl.js index d5059490..4e365c09 100644 --- a/common/models/acl.js +++ b/common/models/acl.js @@ -332,8 +332,8 @@ module.exports = function(ACL) { * @param {AccessRequest} result The resolved access request. */ ACL.checkPermission = function checkPermission(principalType, principalId, - model, property, accessType, - callback) { + model, property, accessType, + callback) { if (!callback) callback = utils.createPromiseCallback(); if (principalId !== null && principalId !== undefined && (typeof principalId !== 'string')) { principalId = principalId.toString(); @@ -363,15 +363,15 @@ module.exports = function(ACL) { var self = this; this.find({where: {principalType: principalType, principalId: principalId, model: model, property: propertyQuery, accessType: accessTypeQuery}}, - function(err, dynACLs) { - if (err) { - return callback(err); - } - acls = acls.concat(dynACLs); - // resolved is an instance of AccessRequest - resolved = self.resolvePermission(acls, req); - return callback(null, resolved); - }); + function(err, dynACLs) { + if (err) { + return callback(err); + } + acls = acls.concat(dynACLs); + // resolved is an instance of AccessRequest + resolved = self.resolvePermission(acls, req); + return callback(null, resolved); + }); return callback.promise; }; diff --git a/common/models/key-value-model.js b/common/models/key-value-model.js index 462505f4..dd9e90eb 100644 --- a/common/models/key-value-model.js +++ b/common/models/key-value-model.js @@ -223,7 +223,7 @@ module.exports = function(KeyValueModel) { function throwNotAttached(modelName, methodName) { throw new Error(g.f( 'Cannot call %s.%s(). ' + - 'The %s method has not been setup. ' + + 'The %s method has not been setup. ' + 'The {{KeyValueModel}} has not been correctly attached ' + 'to a {{DataSource}}!', modelName, methodName, methodName)); diff --git a/common/models/role.js b/common/models/role.js index e807afa8..05baea16 100644 --- a/common/models/role.js +++ b/common/models/role.js @@ -539,10 +539,10 @@ module.exports = function(Role) { if (principalType && principalId) { roleMappingModel.findOne({where: {roleId: roleId, principalType: principalType, principalId: principalId}}, - function(err, result) { - debug('Role mapping found: %j', result); - done(!err && result); // The only arg is the result - }); + function(err, result) { + debug('Role mapping found: %j', result); + done(!err && result); // The only arg is the result + }); } else { process.nextTick(function() { done(false); diff --git a/common/models/user.js b/common/models/user.js index 163a9bd9..09d27a2d 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -749,9 +749,9 @@ module.exports = function(User) { displayPort + urlPath + '?' + qs.stringify({ - uid: '' + verifyOptions.user[pkName], - redirect: verifyOptions.redirect, - }); + uid: '' + verifyOptions.user[pkName], + redirect: verifyOptions.redirect, + }); verifyOptions.to = verifyOptions.to || user.email; verifyOptions.subject = verifyOptions.subject || g.f('Thanks for Registering'); diff --git a/lib/application.js b/lib/application.js index b597d497..977cc3a4 100644 --- a/lib/application.js +++ b/lib/application.js @@ -349,9 +349,9 @@ app.enableAuth = function(options) { var modelId = modelInstance && modelInstance.id || // replacement for deprecated req.param() (req.params && req.params.id !== undefined ? req.params.id : - req.body && req.body.id !== undefined ? req.body.id : - req.query && req.query.id !== undefined ? req.query.id : - undefined); + req.body && req.body.id !== undefined ? req.body.id : + req.query && req.query.id !== undefined ? req.query.id : + undefined); var modelName = Model.modelName; @@ -464,7 +464,7 @@ app._verifyAuthModelRelations = function() { console.warn( 'The app configuration follows the multiple user models setup ' + 'as described in http://ibm.biz/setup-loopback-auth', - 'The built-in role resolver $owner is not currently compatible ' + + 'The built-in role resolver $owner is not currently compatible ' + 'with this configuration and should not be used in production.'); } diff --git a/lib/model.js b/lib/model.js index b3b6ec69..589b9eea 100644 --- a/lib/model.js +++ b/lib/model.js @@ -845,7 +845,7 @@ module.exports = function(registry) { ], description: format('Counts %s of %s.', scopeName, this.modelName), accessType: 'READ', - returns: {arg: 'count', type: 'number'}, + returns: {arg: 'count', type: 'number'}, }); }; @@ -890,7 +890,7 @@ module.exports = function(registry) { acceptArgs = [ { arg: paramName, type: 'any', http: {source: 'path'}, - description: format('Foreign key for %s.', relation.name), + description: format('Foreign key for %s.', relation.name), required: true, }, ]; diff --git a/lib/persisted-model.js b/lib/persisted-model.js index 8bfb4b67..7b3cc03f 100644 --- a/lib/persisted-model.js +++ b/lib/persisted-model.js @@ -1485,7 +1485,7 @@ module.exports = function(registry) { function applyUpdate(Model, id, current, data, change, conflicts, options, cb) { var Change = Model.getChangeModel(); - var rev = current ? Change.revisionForInst(current) : null; + var rev = current ? Change.revisionForInst(current) : null; if (rev !== change.prev) { debug('Detected non-rectified change of %s %j', diff --git a/lib/registry.js b/lib/registry.js index de711838..19f4685f 100644 --- a/lib/registry.js +++ b/lib/registry.js @@ -230,7 +230,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) { // configuration, so that the datasource picks up updated relations if (config.dataSource) { assert(config.dataSource instanceof DataSource, - 'Cannot configure ' + ModelCtor.modelName + + 'Cannot configure ' + ModelCtor.modelName + ': config.dataSource must be an instance of DataSource'); ModelCtor.attachTo(config.dataSource); debug('Attached model `%s` to dataSource `%s`', @@ -398,7 +398,7 @@ Registry.prototype.memory = function(name) { name = name || 'default'; var memory = ( this._memoryDataSources || (this._memoryDataSources = {}) - )[name]; + )[name]; if (!memory) { memory = this._memoryDataSources[name] = this.createDataSource({ diff --git a/lib/server-app.js b/lib/server-app.js index 38aa64d0..bf6aad2b 100644 --- a/lib/server-app.js +++ b/lib/server-app.js @@ -226,7 +226,7 @@ proto._findLayerByHandler = function(handler) { if (this._router.stack[k].handle === handler || // NewRelic replaces the handle and keeps it as __NR_original this._router.stack[k].handle['__NR_original'] === handler - ) { + ) { return this._router.stack[k]; } else { // Aggressively check if the original handler has been wrapped diff --git a/package.json b/package.json index 0c6be42f..b21f0a4b 100644 --- a/package.json +++ b/package.json @@ -68,14 +68,16 @@ "cookie-parser": "^1.3.4", "coveralls": "^2.11.15", "dirty-chai": "^1.2.2", - "eslint-config-loopback": "^8.0.0", + "eslint": "^4.13.1", + "eslint-config-loopback": "^10.0.0", + "eslint-plugin-mocha": "^4.11.0", "express-session": "^1.14.0", "grunt": "^1.0.1", "grunt-browserify": "^5.0.0", "grunt-cli": "^1.2.0", "grunt-contrib-uglify": "^2.0.0", "grunt-contrib-watch": "^1.0.0", - "grunt-eslint": "^19.0.0", + "grunt-eslint": "^20.1.0", "grunt-karma": "^2.0.0", "grunt-mocha-test": "^0.12.7", "karma": "^1.1.2", diff --git a/server/middleware/token.js b/server/middleware/token.js index 0af1e24a..14b69d24 100644 --- a/server/middleware/token.js +++ b/server/middleware/token.js @@ -30,7 +30,7 @@ function rewriteUserLiteral(req, currentUserLiteral, next) { // Replace /me/ with /current-user-id/ var urlBeforeRewrite = req.url; req.url = req.url.replace(literalRegExp, - '/' + req.accessToken.userId + '$1'); + '/' + req.accessToken.userId + '$1'); if (req.url !== urlBeforeRewrite) { debug('req.url has been rewritten from %s to %s', urlBeforeRewrite, diff --git a/test/access-token.test.js b/test/access-token.test.js index 718f130f..5886061b 100644 --- a/test/access-token.test.js +++ b/test/access-token.test.js @@ -139,39 +139,39 @@ describe('loopback.token(options)', function() { }); it('does not search default keys when searchDefaultTokenKeys is false', - function(done) { - var tokenId = this.token.id; - var app = createTestApp( - this.token, - {token: {searchDefaultTokenKeys: false}}, - done); - var agent = request.agent(app); + function(done) { + var tokenId = this.token.id; + var app = createTestApp( + this.token, + {token: {searchDefaultTokenKeys: false}}, + done); + var agent = request.agent(app); - // Set the token cookie - agent.get('/token').expect(200).end(function(err, res) { - if (err) return done(err); + // Set the token cookie + agent.get('/token').expect(200).end(function(err, res) { + if (err) return done(err); - // Make a request that sets the token in all places searched by default - agent.get('/check-access?access_token=' + tokenId) - .set('X-Access-Token', tokenId) - .set('authorization', tokenId) + // Make a request that sets the token in all places searched by default + agent.get('/check-access?access_token=' + tokenId) + .set('X-Access-Token', tokenId) + .set('authorization', tokenId) // Expect 401 because there is no (non-default) place configured where // the middleware should load the token from - .expect(401) - .end(done); + .expect(401) + .end(done); + }); }); - }); it('populates req.token from an authorization header with bearer token with base64', - function(done) { - var token = this.token.id; - token = 'Bearer ' + new Buffer(token).toString('base64'); - createTestAppAndRequest(this.token, done) - .get('/') - .set('authorization', token) - .expect(200) - .end(done); - }); + function(done) { + var token = this.token.id; + token = 'Bearer ' + new Buffer(token).toString('base64'); + createTestAppAndRequest(this.token, done) + .get('/') + .set('authorization', token) + .expect(200) + .end(done); + }); it('populates req.token from an authorization header with bearer token', function(done) { var token = this.token.id; @@ -346,29 +346,29 @@ describe('loopback.token(options)', function() { describe('loading multiple instances of token middleware', function() { it('skips when req.token is already present and no further options are set', - function(done) { - var tokenStub = {id: 'stub id'}; - app.use(function(req, res, next) { - req.accessToken = tokenStub; + function(done) { + var tokenStub = {id: 'stub id'}; + app.use(function(req, res, next) { + req.accessToken = tokenStub; - next(); - }); - app.use(loopback.token({model: Token})); - app.get('/', function(req, res, next) { - res.send(req.accessToken); - }); - - request(app).get('/') - .set('Authorization', this.token.id) - .expect(200) - .end(function(err, res) { - if (err) return done(err); - - expect(res.body).to.eql(tokenStub); - - done(); + next(); }); - }); + app.use(loopback.token({model: Token})); + app.get('/', function(req, res, next) { + res.send(req.accessToken); + }); + + request(app).get('/') + .set('Authorization', this.token.id) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + + expect(res.body).to.eql(tokenStub); + + done(); + }); + }); it('does not overwrite valid existing token (has "id" property) ' + ' when overwriteExistingToken is falsy', @@ -509,21 +509,21 @@ describe('AccessToken', function() { }); it('allows eternal tokens when enabled by User.allowEternalTokens', - function(done) { - var Token = givenLocalTokenModel(); + function(done) { + var Token = givenLocalTokenModel(); - // Overwrite User settings - enable eternal tokens - Token.app.models.User.settings.allowEternalTokens = true; + // Overwrite User settings - enable eternal tokens + Token.app.models.User.settings.allowEternalTokens = true; - Token.create({userId: '123', ttl: -1}, function(err, token) { - if (err) return done(err); - token.validate(function(err, isValid) { + Token.create({userId: '123', ttl: -1}, function(err, token) { if (err) return done(err); - expect(isValid, 'isValid').to.equal(true); - done(); + token.validate(function(err, isValid) { + if (err) return done(err); + expect(isValid, 'isValid').to.equal(true); + done(); + }); }); }); - }); }); describe('.findForRequest()', function() { @@ -649,7 +649,7 @@ describe('app.enableAuth()', function() { }); }); - it('prevent remote call with app setting status on denied ACL', function(done) { + it('denies remote call with app setting status 403', function(done) { createTestAppAndRequest(this.token, {app: {aclErrorStatus: 403}}, done) .del('/tests/123') .expect(403) @@ -667,7 +667,7 @@ describe('app.enableAuth()', function() { }); }); - it('prevent remote call with app setting status on denied ACL', function(done) { + it('denies remote call with app setting status 404', function(done) { createTestAppAndRequest(this.token, {model: {aclErrorStatus: 404}}, done) .del('/tests/123') .expect(404) diff --git a/test/acl.test.js b/test/acl.test.js index c063513b..6c5d53ad 100644 --- a/test/acl.test.js +++ b/test/acl.test.js @@ -50,51 +50,51 @@ describe('security scopes', function() { it('should allow access to models for the given scope by wildcard', function() { Scope.create({name: 'userScope', description: 'access user information'}, - function(err, scope) { - ACL.create({ - principalType: ACL.SCOPE, principalId: scope.id, - model: 'User', property: ACL.ALL, - accessType: ACL.ALL, permission: ACL.ALLOW, - }, function(err, resource) { - Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult); - Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult); - Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult); + function(err, scope) { + ACL.create({ + principalType: ACL.SCOPE, principalId: scope.id, + model: 'User', property: ACL.ALL, + accessType: ACL.ALL, permission: ACL.ALLOW, + }, function(err, resource) { + Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult); + Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult); + Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult); + }); }); - }); }); it('should allow access to models for the given scope', function() { Scope.create({name: 'testModelScope', description: 'access testModel information'}, - function(err, scope) { - ACL.create({ - principalType: ACL.SCOPE, principalId: scope.id, - model: 'testModel', property: 'name', - accessType: ACL.READ, permission: ACL.ALLOW, - }, function(err, resource) { - ACL.create({principalType: ACL.SCOPE, principalId: scope.id, + function(err, scope) { + ACL.create({ + principalType: ACL.SCOPE, principalId: scope.id, model: 'testModel', property: 'name', - accessType: ACL.WRITE, permission: ACL.DENY, + accessType: ACL.READ, permission: ACL.ALLOW, }, function(err, resource) { + ACL.create({principalType: ACL.SCOPE, principalId: scope.id, + model: 'testModel', property: 'name', + accessType: ACL.WRITE, permission: ACL.DENY, + }, function(err, resource) { // console.log(resource); - Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL, - function(err, perm) { - assert(perm.permission === ACL.DENY); // because name.WRITE == DENY - }); - Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL, - function(err, perm) { - assert(perm.permission === ACL.DENY); // because name.WRITE == DENY - }); - Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); - Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL, + function(err, perm) { + assert(perm.permission === ACL.DENY); // because name.WRITE == DENY + }); + Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL, + function(err, perm) { + assert(perm.permission === ACL.DENY); // because name.WRITE == DENY + }); + Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ, + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); + Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE, + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); + }); }); }); - }); }); }); @@ -108,12 +108,12 @@ describe('security ACLs', function() { accessType: ACL.ALL, permission: ACL.ALLOW, }) - .then(function() { - return ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL); - }) - .then(function(access) { - assert(access.permission === ACL.ALLOW); - }); + .then(function() { + return ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL); + }) + .then(function(access) { + assert(access.permission === ACL.ALLOW); + }); }); it('supports checkAccessForContext() returning a promise', function() { @@ -129,9 +129,9 @@ describe('security ACLs', function() { model: 'testModel', accessType: ACL.ALL, }) - .then(function(access) { - assert(access.permission === ACL.ALLOW); - }); + .then(function(access) { + assert(access.permission === ACL.ALLOW); + }); }); it('should order ACL entries based on the matching score', function() { @@ -256,34 +256,34 @@ describe('security ACLs', function() { accessType: ACL.EXECUTE, permission: ACL.ALLOW, }, function(err, acl) { ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); }); }); }); @@ -311,9 +311,9 @@ describe('security ACLs', function() { Customer.settings.defaultPermission = ACL.DENY; ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function(err, perm) { assert(perm.permission === ACL.ALLOW); @@ -353,29 +353,29 @@ describe('security ACLs', function() { */ ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.READ, - function(err, perm) { - assert(perm.permission === ACL.ALLOW); - }); + function(err, perm) { + assert(perm.permission === ACL.ALLOW); + }); ACL.checkPermission(ACL.USER, 'u003', 'Customer', 'name', ACL.WRITE, - function(err, perm) { - assert(perm.permission === ACL.DENY); - }); + function(err, perm) { + assert(perm.permission === ACL.DENY); + }); }); it('should filter static ACLs by model/property', function() { @@ -451,39 +451,39 @@ describe('security ACLs', function() { log('Role: ', myRole.toObject()); myRole.principals.create({principalType: RoleMapping.USER, principalId: userId}, - function(err, p) { - log('Principal added to role: ', p.toObject()); + function(err, p) { + log('Principal added to role: ', p.toObject()); - ACL.create({ - principalType: ACL.ROLE, principalId: 'MyRole', - model: 'Customer', property: ACL.ALL, - accessType: ACL.READ, permission: ACL.DENY, - }, function(err, acl) { - log('ACL 2: ', acl.toObject()); + ACL.create({ + principalType: ACL.ROLE, principalId: 'MyRole', + model: 'Customer', property: ACL.ALL, + accessType: ACL.READ, permission: ACL.DENY, + }, function(err, acl) { + log('ACL 2: ', acl.toObject()); - ACL.checkAccessForContext({ - principals: [ - {type: ACL.USER, id: userId}, - ], - model: 'Customer', - property: 'name', - accessType: ACL.READ, - }, function(err, access) { - assert(!err && access.permission === ACL.ALLOW); - }); + ACL.checkAccessForContext({ + principals: [ + {type: ACL.USER, id: userId}, + ], + model: 'Customer', + property: 'name', + accessType: ACL.READ, + }, function(err, access) { + assert(!err && access.permission === ACL.ALLOW); + }); - ACL.checkAccessForContext({ - principals: [ - {type: ACL.ROLE, id: Role.EVERYONE}, - ], - model: 'Customer', - property: 'name', - accessType: ACL.READ, - }, function(err, access) { - assert(!err && access.permission === ACL.DENY); + ACL.checkAccessForContext({ + principals: [ + {type: ACL.ROLE, id: Role.EVERYONE}, + ], + model: 'Customer', + property: 'name', + accessType: ACL.READ, + }, function(err, access) { + assert(!err && access.permission === ACL.DENY); + }); }); }); - }); }); }); }); @@ -543,35 +543,35 @@ describe('authorized roles propagation in RemotingContext', function() { {permission: ACL.ALLOW, principalId: '$authenticated'}, {permission: ACL.ALLOW, principalId: 'myRole'}, ]) - .then(makeAuthorizedHttpRequestOnMyTestModel) - .then(function() { - var ctx = models.MyTestModel.lastRemotingContext; - expect(ctx.args.options.authorizedRoles).to.eql( - { - $everyone: true, - $authenticated: true, - myRole: true, - } - ); - }); + .then(makeAuthorizedHttpRequestOnMyTestModel) + .then(function() { + var ctx = models.MyTestModel.lastRemotingContext; + expect(ctx.args.options.authorizedRoles).to.eql( + { + $everyone: true, + $authenticated: true, + myRole: true, + } + ); + }); }); it('does not contain any denied role even if query is allowed', function() { return createACLs('MyTestModel', [ {permission: ACL.ALLOW, principalId: '$everyone'}, - {permission: ACL.DENY, principalId: '$authenticated'}, + {permission: ACL.DENY, principalId: '$authenticated'}, {permission: ACL.ALLOW, principalId: 'myRole'}, ]) - .then(makeAuthorizedHttpRequestOnMyTestModel) - .then(function() { - var ctx = models.MyTestModel.lastRemotingContext; - expect(ctx.args.options.authorizedRoles).to.eql( - { - $everyone: true, - myRole: true, - } - ); - }); + .then(makeAuthorizedHttpRequestOnMyTestModel) + .then(function() { + var ctx = models.MyTestModel.lastRemotingContext; + expect(ctx.args.options.authorizedRoles).to.eql( + { + $everyone: true, + myRole: true, + } + ); + }); }); it('honors default permission setting', function() { @@ -580,17 +580,17 @@ describe('authorized roles propagation in RemotingContext', function() { return createACLs('MyTestModel', [ {permission: ACL.DEFAULT, principalId: '$everyone'}, - {permission: ACL.DENY, principalId: '$authenticated'}, - {permission: ACL.ALLOW, principalId: 'myRole'}, + {permission: ACL.DENY, principalId: '$authenticated'}, + {permission: ACL.ALLOW, principalId: 'myRole'}, ]) - .then(makeAuthorizedHttpRequestOnMyTestModel) - .then(function() { - var ctx = models.MyTestModel.lastRemotingContext; - expect(ctx.args.options.authorizedRoles).to.eql( + .then(makeAuthorizedHttpRequestOnMyTestModel) + .then(function() { + var ctx = models.MyTestModel.lastRemotingContext; + expect(ctx.args.options.authorizedRoles).to.eql( // '$everyone' is not expected as default permission is DENY - {myRole: true} - ); - }); + {myRole: true} + ); + }); }); // helpers @@ -619,15 +619,15 @@ describe('authorized roles propagation in RemotingContext', function() { models.User.create({username: 'myUser', email: 'myuser@example.com', password: 'pass'}), models.Role.create({name: 'myRole'}), ]) - .spread(function(myUser, myRole) { - return Promise.all([ - myRole.principals.create({principalType: 'USER', principalId: myUser.id}), - models.User.login({username: 'myUser', password: 'pass'}), - ]); - }) - .spread(function(role, token) { - accessToken = token; - }); + .spread(function(myUser, myRole) { + return Promise.all([ + myRole.principals.create({principalType: 'USER', principalId: myUser.id}), + models.User.login({username: 'myUser', password: 'pass'}), + ]); + }) + .spread(function(role, token) { + accessToken = token; + }); } function createACLs(model, acls) { diff --git a/test/app.test.js b/test/app.test.js index 69a01c85..dd803f39 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -523,7 +523,7 @@ describe('app', function() { }); }); - it('scopes middleware to a list of scopes', function(done) { + it('scopes middleware from config to a list of scopes', function(done) { var steps = []; app.middlewareFromConfig( function factory() { diff --git a/test/change.test.js b/test/change.test.js index c493dbc7..48141a9e 100644 --- a/test/change.test.js +++ b/test/change.test.js @@ -157,12 +157,12 @@ describe('Change', function() { beforeEach(function(done) { var test = this; Change.findOrCreateChange(this.modelName, this.modelId) - .then(function(result) { - test.result = result; + .then(function(result) { + test.result = result; - done(); - }) - .catch(done); + done(); + }) + .catch(done); }); it('should create an entry', function(done) { @@ -352,12 +352,12 @@ describe('Change', function() { }); change.currentRevision() - .then(function(rev) { - assert.equal(rev, test.revisionForModel); + .then(function(rev) { + assert.equal(rev, test.revisionForModel); - done(); - }) - .catch(done); + done(); + }) + .catch(done); }); }); diff --git a/test/checkpoint.test.js b/test/checkpoint.test.js index 56549d2d..44e0d1d4 100644 --- a/test/checkpoint.test.js +++ b/test/checkpoint.test.js @@ -78,13 +78,13 @@ describe('Checkpoint', function() { }); it('Checkpoint.current() for non existing checkpoint should initialize checkpoint', - function(done) { - Checkpoint.current(function(err, seq) { - expect(seq).to.equal(1); + function(done) { + Checkpoint.current(function(err, seq) { + expect(seq).to.equal(1); - done(err); + done(err); + }); }); - }); it('bumpLastSeq() works when singleton instance does not exists yet', function(done) { Checkpoint.bumpLastSeq(function(err, cp) { diff --git a/test/hidden-properties.test.js b/test/hidden-properties.test.js index bb887ccb..b46cb044 100644 --- a/test/hidden-properties.test.js +++ b/test/hidden-properties.test.js @@ -44,17 +44,17 @@ describe('hidden properties', function() { it('should hide a property remotely', function(done) { request(this.app) - .get('/products') - .expect('Content-Type', /json/) - .expect(200) - .end(function(err, res) { - if (err) return done(err); + .get('/products') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); - var product = res.body[0]; - assert.equal(product.secret, undefined); + var product = res.body[0]; + assert.equal(product.secret, undefined); - done(); - }); + done(); + }); }); it('should hide a property of nested models', function(done) { diff --git a/test/key-value-model.test.js b/test/key-value-model.test.js index aef9c6fe..4c40b20c 100644 --- a/test/key-value-model.test.js +++ b/test/key-value-model.test.js @@ -58,23 +58,23 @@ describe('KeyValueModel', function() { }); it('provides "expire(key, ttl)" at "PUT /key/expire"', - function(done) { - CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) { - if (err) return done(err); - request.put('/CacheItems/expire-key/expire') - .send({ttl: 10}) - .end(function(err, res) { - if (err) return done(err); - setTimeout(function() { - CacheItem.get('set-key-ttl', function(err, value) { - if (err) return done(err); - expect(value).to.equal(null); - done(); - }); - }, 20); - }); + function(done) { + CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) { + if (err) return done(err); + request.put('/CacheItems/expire-key/expire') + .send({ttl: 10}) + .end(function(err, res) { + if (err) return done(err); + setTimeout(function() { + CacheItem.get('set-key-ttl', function(err, value) { + if (err) return done(err); + expect(value).to.equal(null); + done(); + }); + }, 20); + }); + }); }); - }); it('returns 404 when expiring a key that does not exist', function(done) { request.put('/CacheItems/key-does-not-exist/expire') @@ -96,32 +96,32 @@ describe('KeyValueModel', function() { }); it('returns 204 when getting TTL for a key that does not have TTL set', - function(done) { - request.put('/CacheItems/ttl-key') - .end(function(err, res) { - if (err) return done(err); - request.get('/CacheItems/ttl-key/ttl') - .expect(204, done); - }); - }); - - it('returns 404 when getting TTL for a key when TTL has expired', - function(done) { - request.put('/CacheItems/ttl-key?ttl=10') - .end(function(err, res) { - setTimeout(function() { + function(done) { + request.put('/CacheItems/ttl-key') + .end(function(err, res) { if (err) return done(err); request.get('/CacheItems/ttl-key/ttl') - .expect(404, done); - }, 20); - }); - }); + .expect(204, done); + }); + }); + + it('returns 404 when getting TTL for a key when TTL has expired', + function(done) { + request.put('/CacheItems/ttl-key?ttl=10') + .end(function(err, res) { + setTimeout(function() { + if (err) return done(err); + request.get('/CacheItems/ttl-key/ttl') + .expect(404, done); + }, 20); + }); + }); it('returns 404 when getting TTL for a key that does not exist', - function(done) { - request.get('/CacheItems/key-does-not-exist/ttl') - .expect(404, done); - }); + function(done) { + request.get('/CacheItems/key-does-not-exist/ttl') + .expect(404, done); + }); it('provides "keys(filter)" at "GET /keys"', function(done) { CacheItem.set('list-key', AN_OBJECT_VALUE, function(err) { diff --git a/test/model.application.test.js b/test/model.application.test.js index cde8c06d..3cff2fc6 100644 --- a/test/model.application.test.js +++ b/test/model.application.test.js @@ -15,7 +15,7 @@ describe('Application', function() { Application.attachTo(loopback.memory()); }); - it('honors `application.register` - promise variant', function(done) { + it('honors `application.register` - callback variant', function(done) { Application.register('rfeng', 'MyTestApp', {description: 'My test application'}, function(err, result) { var app = result; @@ -89,31 +89,31 @@ describe('Application', function() { serverApiKey: 'serverKey', }, }}, - function(err, result) { - var app = result; - assert.deepEqual(app.pushSettings.toObject(), { - apns: { - production: false, - certData: 'cert', - keyData: 'key', - pushOptions: { - gateway: 'gateway.sandbox.push.apple.com', - port: 2195, - }, - feedbackOptions: { - gateway: 'feedback.sandbox.push.apple.com', - port: 2196, - interval: 300, - batchFeedback: true, - }, + function(err, result) { + var app = result; + assert.deepEqual(app.pushSettings.toObject(), { + apns: { + production: false, + certData: 'cert', + keyData: 'key', + pushOptions: { + gateway: 'gateway.sandbox.push.apple.com', + port: 2195, }, - gcm: { - serverApiKey: 'serverKey', + feedbackOptions: { + gateway: 'feedback.sandbox.push.apple.com', + port: 2196, + interval: 300, + batchFeedback: true, }, - }); - - done(err, result); + }, + gcm: { + serverApiKey: 'serverKey', + }, }); + + done(err, result); + }); }); beforeEach(function(done) { @@ -164,32 +164,32 @@ describe('Application', function() { it('Reset keys - promise variant', function(done) { Application.resetKeys(registeredApp.id) - .then(function(result) { - var app = result; - assert.equal(app.owner, 'rfeng'); - assert.equal(app.name, 'MyApp2'); - assert.equal(app.description, 'My second mobile application'); - assert(app.clientKey); - assert(app.javaScriptKey); - assert(app.restApiKey); - assert(app.windowsKey); - assert(app.masterKey); + .then(function(result) { + var app = result; + assert.equal(app.owner, 'rfeng'); + assert.equal(app.name, 'MyApp2'); + assert.equal(app.description, 'My second mobile application'); + assert(app.clientKey); + assert(app.javaScriptKey); + assert(app.restApiKey); + assert(app.windowsKey); + assert(app.masterKey); - assert(app.clientKey !== registeredApp.clientKey); - assert(app.javaScriptKey !== registeredApp.javaScriptKey); - assert(app.restApiKey !== registeredApp.restApiKey); - assert(app.windowsKey !== registeredApp.windowsKey); - assert(app.masterKey !== registeredApp.masterKey); + assert(app.clientKey !== registeredApp.clientKey); + assert(app.javaScriptKey !== registeredApp.javaScriptKey); + assert(app.restApiKey !== registeredApp.restApiKey); + assert(app.windowsKey !== registeredApp.windowsKey); + assert(app.masterKey !== registeredApp.masterKey); - assert(app.created); - assert(app.modified); - registeredApp = app; + assert(app.created); + assert(app.modified); + registeredApp = app; - done(); - }) - .catch(function(err) { - done(err); - }); + done(); + }) + .catch(function(err) { + done(err); + }); }); it('Reset keys without create a new instance', function(done) { @@ -205,17 +205,17 @@ describe('Application', function() { it('Reset keys without create a new instance - promise variant', function(done) { Application.resetKeys(registeredApp.id) - .then(function(result) { - var app = result; - assert(app.id); - assert(app.id === registeredApp.id); - registeredApp = app; + .then(function(result) { + var app = result; + assert(app.id); + assert(app.id === registeredApp.id); + registeredApp = app; - done(); - }) - .catch(function(err) { - done(err); - }); + done(); + }) + .catch(function(err) { + done(err); + }); }); it('Authenticate with application id & clientKey', function(done) { @@ -231,15 +231,15 @@ describe('Application', function() { it('Authenticate with application id & clientKey - promise variant', function(done) { Application.authenticate(registeredApp.id, registeredApp.clientKey) - .then(function(result) { - assert.equal(result.application.id, registeredApp.id); - assert.equal(result.keyType, 'clientKey'); + .then(function(result) { + assert.equal(result.application.id, registeredApp.id); + assert.equal(result.keyType, 'clientKey'); - done(); - }) - .catch(function(err) { - done(err); - }); + done(); + }) + .catch(function(err) { + done(err); + }); }); it('Authenticate with application id & javaScriptKey', function(done) { @@ -293,15 +293,15 @@ describe('Application', function() { it('Fail to authenticate with application id - promise variant', function(done) { Application.authenticate(registeredApp.id, 'invalid-key') - .then(function(result) { - assert(!result); + .then(function(result) { + assert(!result); - done(); - }) - .catch(function(err) { - done(err); - throw new Error('Error should NOT be thrown'); - }); + done(); + }) + .catch(function(err) { + done(err); + throw new Error('Error should NOT be thrown'); + }); }); }); diff --git a/test/multiple-user-principal-types.test.js b/test/multiple-user-principal-types.test.js index e4a41f57..66347fc8 100644 --- a/test/multiple-user-principal-types.test.js +++ b/test/multiple-user-principal-types.test.js @@ -68,15 +68,15 @@ describe('Multiple users with custom principalType', function() { AnotherUser.create(commonCredentials), Role.create({name: 'userRole'}), ]) - .spread(function(u1, u2, r) { - userFromOneModel = u1; - userFromAnotherModel = u2; - userRole = r; - userOneBaseContext = { - principalType: OneUser.modelName, - principalId: userFromOneModel.id, - }; - }); + .spread(function(u1, u2, r) { + userFromOneModel = u1; + userFromAnotherModel = u2; + userRole = r; + userOneBaseContext = { + principalType: OneUser.modelName, + principalId: userFromOneModel.id, + }; + }); }); describe('User.login', function() { @@ -118,29 +118,29 @@ describe('Multiple users with custom principalType', function() { describe('User.logout', function() { it('logs out a user from user model 1 without logging out user from model 2', - function() { - var tokenOfOneUser; - return Promise.all([ - OneUser.login(commonCredentials), - AnotherUser.login(commonCredentials), - ]) - .spread(function(t1, t2) { - tokenOfOneUser = t1; - return OneUser.logout(tokenOfOneUser.id); - }) - .then(function() { - return AccessToken.find({}); - }) - .then(function(allTokens) { - var data = allTokens.map(function(token) { - return {userId: token.userId, principalType: token.principalType}; - }); - expect(data).to.eql([ - // no token for userFromAnotherModel - {userId: userFromAnotherModel.id, principalType: 'AnotherUser'}, - ]); + function() { + var tokenOfOneUser; + return Promise.all([ + OneUser.login(commonCredentials), + AnotherUser.login(commonCredentials), + ]) + .spread(function(t1, t2) { + tokenOfOneUser = t1; + return OneUser.logout(tokenOfOneUser.id); + }) + .then(function() { + return AccessToken.find({}); + }) + .then(function(allTokens) { + var data = allTokens.map(function(token) { + return {userId: token.userId, principalType: token.principalType}; + }); + expect(data).to.eql([ + // no token for userFromAnotherModel + {userId: userFromAnotherModel.id, principalType: 'AnotherUser'}, + ]); + }); }); - }); }); describe('Password Reset', function() { @@ -151,23 +151,23 @@ describe('Multiple users with custom principalType', function() { }; it('creates a temp accessToken to allow a user to change password', - function() { - return Promise.all([ - OneUser.resetPassword({email: options.email}), - waitForResetRequestAndVerify, - ]); - }); + function() { + return Promise.all([ + OneUser.resetPassword({email: options.email}), + waitForResetRequestAndVerify, + ]); + }); function waitForResetRequestAndVerify() { return waitForEvent(OneUser, 'resetPasswordRequest') - .then(function(info) { - assertGoodToken(info.accessToken, userFromOneModel); - return info.accessToken.user.getAsync(); - }) - .then(function(user) { - expect(user).to.have.property('id', userFromOneModel.id); - expect(user).to.have.property('email', userFromOneModel.email); - }); + .then(function(info) { + assertGoodToken(info.accessToken, userFromOneModel); + return info.accessToken.user.getAsync(); + }) + .then(function(user) { + expect(user).to.have.property('id', userFromOneModel.id); + expect(user).to.have.property('email', userFromOneModel.email); + }); } }); }); @@ -214,51 +214,51 @@ describe('Multiple users with custom principalType', function() { describe('getUser()', function() { it('returns user although principals contain non USER principals', - function() { - return Promise.try(function() { - addToAccessContext([ - {type: Principal.ROLE}, - {type: Principal.APP}, - {type: Principal.SCOPE}, - {type: OneUser.modelName, id: userFromOneModel.id}, - ]); - var user = accessContext.getUser(); - expect(user).to.eql({ - id: userFromOneModel.id, - principalType: OneUser.modelName, + function() { + return Promise.try(function() { + addToAccessContext([ + {type: Principal.ROLE}, + {type: Principal.APP}, + {type: Principal.SCOPE}, + {type: OneUser.modelName, id: userFromOneModel.id}, + ]); + var user = accessContext.getUser(); + expect(user).to.eql({ + id: userFromOneModel.id, + principalType: OneUser.modelName, + }); }); }); - }); it('returns user although principals contain invalid principals', - function() { - return Promise.try(function() { - addToAccessContext([ - {type: 'AccessToken'}, - {type: 'invalidModelName'}, - {type: OneUser.modelName, id: userFromOneModel.id}, - ]); - var user = accessContext.getUser(); - expect(user).to.eql({ - id: userFromOneModel.id, - principalType: OneUser.modelName, + function() { + return Promise.try(function() { + addToAccessContext([ + {type: 'AccessToken'}, + {type: 'invalidModelName'}, + {type: OneUser.modelName, id: userFromOneModel.id}, + ]); + var user = accessContext.getUser(); + expect(user).to.eql({ + id: userFromOneModel.id, + principalType: OneUser.modelName, + }); }); }); - }); it('supports any level of built-in User model inheritance', - function() { - ThirdUser = createUserModel(app, 'ThirdUser', {base: 'OneUser'}); - return ThirdUser.create(commonCredentials) - .then(function(userFromThirdModel) { - accessContext.addPrincipal(ThirdUser.modelName, userFromThirdModel.id); - var user = accessContext.getUser(); - expect(user).to.eql({ - id: userFromThirdModel.id, - principalType: ThirdUser.modelName, - }); + function() { + ThirdUser = createUserModel(app, 'ThirdUser', {base: 'OneUser'}); + return ThirdUser.create(commonCredentials) + .then(function(userFromThirdModel) { + accessContext.addPrincipal(ThirdUser.modelName, userFromThirdModel.id); + var user = accessContext.getUser(); + expect(user).to.eql({ + id: userFromThirdModel.id, + principalType: ThirdUser.modelName, + }); + }); }); - }); }); // helper @@ -347,7 +347,7 @@ describe('Multiple users with custom principalType', function() { it('supports getRoles()', function() { return Role.getRoles( - userOneBaseContext) + userOneBaseContext) .then(function(roles) { expect(roles).to.eql([ Role.AUTHENTICATED, @@ -390,18 +390,18 @@ describe('Multiple users with custom principalType', function() { app.model(Album, {dataSource: 'db'}); return Album.create({name: 'album', userId: userFromOneModel.id}) - .then(function(album) { - var validContext = { - principalType: OneUser.modelName, - principalId: userFromOneModel.id, - model: Album, - id: album.id, - }; - return Role.isInRole(Role.OWNER, validContext); - }) - .then(function(isOwner) { - expect(isOwner).to.be.true(); - }); + .then(function(album) { + var validContext = { + principalType: OneUser.modelName, + principalId: userFromOneModel.id, + model: Album, + id: album.id, + }; + return Role.isInRole(Role.OWNER, validContext); + }) + .then(function(isOwner) { + expect(isOwner).to.be.true(); + }); }); // With multiple users config, we cannot resolve a user based just on @@ -419,18 +419,18 @@ describe('Multiple users with custom principalType', function() { userId: userFromOneModel.id, owner: userFromOneModel.id, }) - .then(function(album) { - var authContext = { - principalType: OneUser.modelName, - principalId: userFromOneModel.id, - model: Album, - id: album.id, - }; - return Role.isInRole(Role.OWNER, authContext); - }) - .then(function(isOwner) { - expect(isOwner).to.be.false(); - }); + .then(function(album) { + var authContext = { + principalType: OneUser.modelName, + principalId: userFromOneModel.id, + model: Album, + id: album.id, + }; + return Role.isInRole(Role.OWNER, authContext); + }) + .then(function(isOwner) { + expect(isOwner).to.be.false(); + }); }); it('legacy behavior resolves false if owner has incorrect principalType', function() { @@ -449,106 +449,106 @@ describe('Multiple users with custom principalType', function() { app.model(Album, {dataSource: 'db'}); return Album.create({name: 'album', userId: userFromOneModel.id}) - .then(function(album) { - var invalidPrincipalTypes = [ - 'invalidContextName', - 'USER', - AnotherUser.modelName, - ]; - var invalidContexts = invalidPrincipalTypes.map(principalType => { - return { - principalType, - principalId: userFromOneModel.id, - model: Album, - id: album.id, - }; + .then(function(album) { + var invalidPrincipalTypes = [ + 'invalidContextName', + 'USER', + AnotherUser.modelName, + ]; + var invalidContexts = invalidPrincipalTypes.map(principalType => { + return { + principalType, + principalId: userFromOneModel.id, + model: Album, + id: album.id, + }; + }); + return Promise.map(invalidContexts, context => { + return Role.isInRole(Role.OWNER, context) + .then(isOwner => { + return { + principalType: context.principalType, + isOwner, + }; + }); + }); + }) + .then(result => { + expect(result).to.eql([ + {principalType: 'invalidContextName', isOwner: false}, + {principalType: 'USER', isOwner: false}, + {principalType: AnotherUser.modelName, isOwner: false}, + ]); }); - return Promise.map(invalidContexts, context => { - return Role.isInRole(Role.OWNER, context) - .then(isOwner => { - return { - principalType: context.principalType, - isOwner, - }; - }); - }); - }) - .then(result => { - expect(result).to.eql([ - {principalType: 'invalidContextName', isOwner: false}, - {principalType: 'USER', isOwner: false}, - {principalType: AnotherUser.modelName, isOwner: false}, - ]); - }); }); it.skip('resolves the owner using the corrent belongsTo relation', - function() { + function() { // passing {ownerRelations: true} will enable the new $owner role resolver // with any belongsTo relation allowing to resolve truthy - var Message = createModelWithOptions( - 'ModelWithAllRelations', - {ownerRelations: true} - ); + var Message = createModelWithOptions( + 'ModelWithAllRelations', + {ownerRelations: true} + ); - var messages = [ - {content: 'firstMessage', customerId: userFromOneModel.id}, - { - content: 'secondMessage', - customerId: userFromOneModel.id, - shopKeeperId: userFromAnotherModel.id, - }, + var messages = [ + {content: 'firstMessage', customerId: userFromOneModel.id}, + { + content: 'secondMessage', + customerId: userFromOneModel.id, + shopKeeperId: userFromAnotherModel.id, + }, - // this is the incriminated message where two foreignKeys have the - // same id but points towards two different user models. Although - // customers should come from userFromOneModel and shopKeeperIds should - // come from userFromAnotherModel. The inverted situation still resolves - // isOwner true for both the customer and the shopKeeper - { - content: 'thirdMessage', - customerId: userFromAnotherModel.id, - shopKeeperId: userFromOneModel.id, - }, + // this is the incriminated message where two foreignKeys have the + // same id but points towards two different user models. Although + // customers should come from userFromOneModel and shopKeeperIds should + // come from userFromAnotherModel. The inverted situation still resolves + // isOwner true for both the customer and the shopKeeper + { + content: 'thirdMessage', + customerId: userFromAnotherModel.id, + shopKeeperId: userFromOneModel.id, + }, - {content: 'fourthMessage', customerId: userFromAnotherModel.id}, - {content: 'fifthMessage'}, - ]; - return Promise.map(messages, msg => { - return Message.create(msg); - }) - .then(messages => { - return Promise.all([ - isOwnerForMessage(userFromOneModel, messages[0]), - isOwnerForMessage(userFromAnotherModel, messages[0]), - isOwnerForMessage(userFromOneModel, messages[1]), - isOwnerForMessage(userFromAnotherModel, messages[1]), + {content: 'fourthMessage', customerId: userFromAnotherModel.id}, + {content: 'fifthMessage'}, + ]; + return Promise.map(messages, msg => { + return Message.create(msg); + }) + .then(messages => { + return Promise.all([ + isOwnerForMessage(userFromOneModel, messages[0]), + isOwnerForMessage(userFromAnotherModel, messages[0]), + isOwnerForMessage(userFromOneModel, messages[1]), + isOwnerForMessage(userFromAnotherModel, messages[1]), - isOwnerForMessage(userFromOneModel, messages[2]), - isOwnerForMessage(userFromAnotherModel, messages[2]), + isOwnerForMessage(userFromOneModel, messages[2]), + isOwnerForMessage(userFromAnotherModel, messages[2]), - isOwnerForMessage(userFromAnotherModel, messages[3]), - isOwnerForMessage(userFromOneModel, messages[4]), - ]); - }) - .then(result => { - expect(result).to.eql([ - {userFrom: 'OneUser', msg: 'firstMessage', isOwner: true}, - {userFrom: 'AnotherUser', msg: 'firstMessage', isOwner: false}, - {userFrom: 'OneUser', msg: 'secondMessage', isOwner: true}, - {userFrom: 'AnotherUser', msg: 'secondMessage', isOwner: true}, + isOwnerForMessage(userFromAnotherModel, messages[3]), + isOwnerForMessage(userFromOneModel, messages[4]), + ]); + }) + .then(result => { + expect(result).to.eql([ + {userFrom: 'OneUser', msg: 'firstMessage', isOwner: true}, + {userFrom: 'AnotherUser', msg: 'firstMessage', isOwner: false}, + {userFrom: 'OneUser', msg: 'secondMessage', isOwner: true}, + {userFrom: 'AnotherUser', msg: 'secondMessage', isOwner: true}, - // these 2 tests fail because we cannot resolve ownership with - // multiple owners on a single model instance with a classic - // belongsTo relation, we need to use belongsTo with polymorphic - // discriminator to distinguish between the 2 models - {userFrom: 'OneUser', msg: 'thirdMessage', isOwner: false}, - {userFrom: 'AnotherUser', msg: 'thirdMessage', isOwner: false}, + // these 2 tests fail because we cannot resolve ownership with + // multiple owners on a single model instance with a classic + // belongsTo relation, we need to use belongsTo with polymorphic + // discriminator to distinguish between the 2 models + {userFrom: 'OneUser', msg: 'thirdMessage', isOwner: false}, + {userFrom: 'AnotherUser', msg: 'thirdMessage', isOwner: false}, - {userFrom: 'AnotherUser', msg: 'fourthMessage', isOwner: false}, - {userFrom: 'OneUser', msg: 'fifthMessage', isOwner: false}, - ]); + {userFrom: 'AnotherUser', msg: 'fourthMessage', isOwner: false}, + {userFrom: 'OneUser', msg: 'fifthMessage', isOwner: false}, + ]); + }); }); - }); }); // helpers @@ -608,26 +608,26 @@ describe('Multiple users with custom principalType', function() { }); it('throws error with code \'INVALID_PRINCIPAL_TYPE\' when principalType is incorrect', - function() { - return ACL.resolvePrincipal('incorrectPrincipalType', userFromOneModel.id) - .then( - function onSuccess() { - throw new Error('ACL.resolvePrincipal() should have failed'); - }, - function onError(err) { - expect(err).to.have.property('statusCode', 400); - expect(err).to.have.property('code', 'INVALID_PRINCIPAL_TYPE'); - } - ); - }); + function() { + return ACL.resolvePrincipal('incorrectPrincipalType', userFromOneModel.id) + .then( + function onSuccess() { + throw new Error('ACL.resolvePrincipal() should have failed'); + }, + function onError(err) { + expect(err).to.have.property('statusCode', 400); + expect(err).to.have.property('code', 'INVALID_PRINCIPAL_TYPE'); + } + ); + }); it('reports isMappedToRole by user.username using custom user principalType', - function() { - return ACL.isMappedToRole(OneUser.modelName, userFromOneModel.username, 'userRole') - .then(function(isMappedToRole) { - expect(isMappedToRole).to.be.true(); - }); - }); + function() { + return ACL.isMappedToRole(OneUser.modelName, userFromOneModel.username, 'userRole') + .then(function(isMappedToRole) { + expect(isMappedToRole).to.be.true(); + }); + }); }); }); @@ -669,7 +669,7 @@ describe('Multiple users with custom principalType', function() { OneUser.resetPassword({email: commonCredentials.email}), waitForEvent(OneUser, 'resetPasswordRequest'), ]) - .spread((reset, info) => resetToken = info.accessToken); + .spread((reset, info) => resetToken = info.accessToken); } }); diff --git a/test/relations.integration.js b/test/relations.integration.js index ab68dc77..54e0bd4b 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -63,15 +63,15 @@ describe('relations - integration', function() { test.team = team; app.models.Reader.create({name: 'Reader 1'}, - function(err, reader) { - if (err) return done(err); + function(err, reader) { + if (err) return done(err); - test.reader = reader; - reader.pictures.create({name: 'Picture 1'}); - reader.pictures.create({name: 'Picture 2'}); - reader.team(test.team); - reader.save(done); - }); + test.reader = reader; + reader.pictures.create({name: 'Picture 1'}); + reader.pictures.create({name: 'Picture 2'}); + reader.team(test.team); + reader.save(done); + }); } ); }); @@ -157,9 +157,9 @@ describe('relations - integration', function() { beforeEach(function() { debug('GET /api/stores/:id/widgets response: %s' + '\nheaders: %j\nbody string: %s', - this.res.statusCode, - this.res.headers, - this.res.text); + this.res.statusCode, + this.res.headers, + this.res.text); this.widgets = this.res.body; this.widget = this.res.body && this.res.body[0]; }); @@ -661,8 +661,8 @@ describe('relations - integration', function() { this.app.remotes()._typeRegistry._options.warnWhenOverridingType = false; var product = app.registry.createModel( - 'product', - {id: 'string', name: 'string'} + 'product', + {id: 'string', name: 'string'} ); var category = app.registry.createModel( 'category', @@ -996,7 +996,7 @@ describe('relations - integration', function() { }); }); - it('returns the embedded models', function(done) { + it('includes the created embedded model', function(done) { var url = '/api/todo-lists/' + this.todoList.id + '/items'; this.get(url) @@ -1096,7 +1096,7 @@ describe('relations - integration', function() { var ingredient = app.registry.createModel( 'ingredient', - {name: 'string'} + {name: 'string'} ); app.model(ingredient, {dataSource: 'db'}); @@ -1311,7 +1311,7 @@ describe('relations - integration', function() { }); }); - it('returns the referenced models - verify', function(done) { + it('returns the referenced models without the deleted one', function(done) { var url = '/api/recipes/' + this.recipe.id + '/ingredients'; var test = this; @@ -1370,7 +1370,7 @@ describe('relations - integration', function() { }); }); - it('returns the referenced models - verify', function(done) { + it('returns the referenced models without the unlinked one', function(done) { var url = '/api/recipes/' + this.recipe.id + '/ingredients'; var test = this; @@ -1529,17 +1529,17 @@ describe('relations - integration', function() { test.book = book; book.pages.create({name: 'Page 1'}, - function(err, page) { - if (err) return done(err); + function(err, page) { + if (err) return done(err); - test.page = page; - page.notes.create({text: 'Page Note 1'}, - function(err, note) { - test.note = note; + test.page = page; + page.notes.create({text: 'Page Note 1'}, + function(err, note) { + test.note = note; - done(); + done(); + }); }); - }); }); }); diff --git a/test/remoting.integration.js b/test/remoting.integration.js index a28da3f3..f3802220 100644 --- a/test/remoting.integration.js +++ b/test/remoting.integration.js @@ -228,33 +228,33 @@ describe('With model.settings.replaceOnPUT false', function() { }); it('should have expected remote methods', - function() { - var storeClass = findClass('storeWithReplaceOnPUTfalse'); - var methods = getFormattedMethodsExcludingRelations(storeClass.methods); + function() { + var storeClass = findClass('storeWithReplaceOnPUTfalse'); + var methods = getFormattedMethodsExcludingRelations(storeClass.methods); - var expectedMethods = [ - 'create(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating', - 'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating', - 'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating', - 'replaceOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/replaceOrCreate', - 'upsertWithWhere(where:object,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/upsertWithWhere', - 'exists(id:any):boolean GET /stores-updating/:id/exists', - 'exists(id:any):boolean HEAD /stores-updating/:id', - 'findById(id:any,filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/:id', - 'replaceById(id:any,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/:id/replace', - 'find(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating', - 'findOne(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/findOne', - 'updateAll(where:object,data:object:storeWithReplaceOnPUTfalse):object POST /stores-updating/update', - 'deleteById(id:any):object DELETE /stores-updating/:id', - 'count(where:object):number GET /stores-updating/count', - 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating/:id', - 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating/:id', - 'createChangeStream(options:object):ReadableStream POST /stores-updating/change-stream', - 'createChangeStream(options:object):ReadableStream GET /stores-updating/change-stream', - ]; + var expectedMethods = [ + 'create(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating', + 'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating', + 'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating', + 'replaceOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/replaceOrCreate', + 'upsertWithWhere(where:object,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/upsertWithWhere', + 'exists(id:any):boolean GET /stores-updating/:id/exists', + 'exists(id:any):boolean HEAD /stores-updating/:id', + 'findById(id:any,filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/:id', + 'replaceById(id:any,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/:id/replace', + 'find(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating', + 'findOne(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/findOne', + 'updateAll(where:object,data:object:storeWithReplaceOnPUTfalse):object POST /stores-updating/update', + 'deleteById(id:any):object DELETE /stores-updating/:id', + 'count(where:object):number GET /stores-updating/count', + 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating/:id', + 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating/:id', + 'createChangeStream(options:object):ReadableStream POST /stores-updating/change-stream', + 'createChangeStream(options:object):ReadableStream GET /stores-updating/change-stream', + ]; - expect(methods).to.eql(expectedMethods); - }); + expect(methods).to.eql(expectedMethods); + }); }); describe('With model.settings.replaceOnPUT true', function() { @@ -265,21 +265,21 @@ describe('With model.settings.replaceOnPUT true', function() { }); it('should have expected remote methods', - function() { - var storeClass = findClass('storeWithReplaceOnPUTtrue'); - var methods = getFormattedMethodsExcludingRelations(storeClass.methods); + function() { + var storeClass = findClass('storeWithReplaceOnPUTtrue'); + var methods = getFormattedMethodsExcludingRelations(storeClass.methods); - var expectedMethods = [ - 'patchOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing', - 'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/replaceOrCreate', - 'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing', - 'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/:id/replace', - 'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing/:id', - 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing/:id', - ]; + var expectedMethods = [ + 'patchOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing', + 'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/replaceOrCreate', + 'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing', + 'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/:id/replace', + 'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing/:id', + 'prototype.patchAttributes(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing/:id', + ]; - expect(methods).to.include.members(expectedMethods); - }); + expect(methods).to.include.members(expectedMethods); + }); }); function formatReturns(m) { @@ -332,12 +332,12 @@ function getFormattedMethodsExcludingRelations(methods) { return methods.filter(function(m) { return m.name.indexOf('__') === -1; }) - .map(function(m) { - return formatMethod(m); - }) - .reduce(function(p, c) { - return p.concat(c); - }); + .map(function(m) { + return formatMethod(m); + }) + .reduce(function(p, c) { + return p.concat(c); + }); } function getCreateMethod(methods) { @@ -350,22 +350,22 @@ function getFormattedScopeMethods(methods) { return methods.filter(function(m) { return m.name.indexOf('__') === 0; }) - .map(function(m) { - return formatMethod(m); - }) - .reduce(function(p, c) { - return p.concat(c); - }); + .map(function(m) { + return formatMethod(m); + }) + .reduce(function(p, c) { + return p.concat(c); + }); } function getFormattedPrototypeMethods(methods) { return methods.filter(function(m) { return m.name.indexOf('prototype.__') === 0; }) - .map(function(m) { - return formatMethod(m); - }) - .reduce(function(p, c) { - return p.concat(c); - }); + .map(function(m) { + return formatMethod(m); + }) + .reduce(function(p, c) { + return p.concat(c); + }); } diff --git a/test/replication.rest.test.js b/test/replication.rest.test.js index 70723924..3599f2bb 100644 --- a/test/replication.rest.test.js +++ b/test/replication.rest.test.js @@ -72,8 +72,8 @@ describe('Replication over REST', function() { it('allows PETER to WRITE', function(done) { createCar() - .set('Authorization', peterToken) - .expect(200, done); + .set('Authorization', peterToken) + .expect(200, done); }); function listCars() { @@ -597,7 +597,7 @@ describe('Replication over REST', function() { function(next) { ServerCar.create( [ - {id: 'Ford-Mustang', maker: 'Ford', model: 'Mustang'}, + {id: 'Ford-Mustang', maker: 'Ford', model: 'Mustang'}, {id: 'Audi-R8', maker: 'Audi', model: 'R8'}, ], function(err, cars) { diff --git a/test/replication.test.js b/test/replication.test.js index e09cff8c..37ab38f9 100644 --- a/test/replication.test.js +++ b/test/replication.test.js @@ -170,66 +170,66 @@ describe('Replication / Change APIs', function() { }); it('rectifyOnDelete for Delete should call rectifyChange instead of rectifyAllChanges', - function(done) { - var calls = mockTargetModelRectify(); - async.waterfall([ - function(callback) { - SourceModel.destroyAll({name: 'John'}, callback); - }, - function(data, callback) { - SourceModel.replicate(TargetModel, callback); + function(done) { + var calls = mockTargetModelRectify(); + async.waterfall([ + function(callback) { + SourceModel.destroyAll({name: 'John'}, callback); + }, + function(data, callback) { + SourceModel.replicate(TargetModel, callback); // replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation - }, - ], function(err, results) { - if (err) return done(err); + }, + ], function(err, results) { + if (err) return done(err); - expect(calls).to.eql(['rectifyChange']); + expect(calls).to.eql(['rectifyChange']); - done(); + done(); + }); }); - }); it('rectifyOnSave for Update should call rectifyChange instead of rectifyAllChanges', - function(done) { - var calls = mockTargetModelRectify(); - var newData = {'name': 'Janie'}; - async.waterfall([ - function(callback) { - SourceModel.update({name: 'Jane'}, newData, callback); - }, - function(data, callback) { - SourceModel.replicate(TargetModel, callback); + function(done) { + var calls = mockTargetModelRectify(); + var newData = {'name': 'Janie'}; + async.waterfall([ + function(callback) { + SourceModel.update({name: 'Jane'}, newData, callback); + }, + function(data, callback) { + SourceModel.replicate(TargetModel, callback); // replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation - }, - ], function(err, result) { - if (err) return done(err); + }, + ], function(err, result) { + if (err) return done(err); - expect(calls).to.eql(['rectifyChange']); + expect(calls).to.eql(['rectifyChange']); - done(); + done(); + }); }); - }); it('rectifyOnSave for Create should call rectifyChange instead of rectifyAllChanges', - function(done) { - var calls = mockTargetModelRectify(); - var newData = [{name: 'Janie', surname: 'Doe'}]; - async.waterfall([ - function(callback) { - SourceModel.create(newData, callback); - }, - function(data, callback) { - SourceModel.replicate(TargetModel, callback); + function(done) { + var calls = mockTargetModelRectify(); + var newData = [{name: 'Janie', surname: 'Doe'}]; + async.waterfall([ + function(callback) { + SourceModel.create(newData, callback); + }, + function(data, callback) { + SourceModel.replicate(TargetModel, callback); // replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation - }, - ], function(err, result) { - if (err) return done(err); + }, + ], function(err, result) { + if (err) return done(err); - expect(calls).to.eql(['rectifyChange']); + expect(calls).to.eql(['rectifyChange']); - done(); + done(); + }); }); - }); function mockSourceModelRectify() { var calls = []; @@ -305,12 +305,12 @@ describe('Replication / Change APIs', function() { if (err) return done(err); test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel, - options, function(err, conflicts) { - if (err) return done(err); + options, function(err, conflicts) { + if (err) return done(err); - assertTargetModelEqualsSourceModel(conflicts, test.SourceModel, - test.TargetModel, done); - }); + assertTargetModelEqualsSourceModel(conflicts, test.SourceModel, + test.TargetModel, done); + }); }); }); @@ -322,7 +322,7 @@ describe('Replication / Change APIs', function() { if (err) return done(err); test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel, - options) + options) .then(function(conflicts) { assertTargetModelEqualsSourceModel(conflicts, test.SourceModel, test.TargetModel, done); @@ -1280,7 +1280,7 @@ describe('Replication / Change APIs', function() { var ClientA, Server, ClientB; beforeEach(function() { - ClientA = SourceModel; + ClientA = SourceModel; Server = TargetModel; ClientB = AnotherModel; @@ -1625,13 +1625,13 @@ describe('Replication / Change APIs', function() { updates[0].change = data; OptionsSourceModel.bulkUpdate(updates, options, callback); }], - function(err, result) { - if (err) return done(err); + function(err, result) { + if (err) return done(err); - expect(syncPropertyExists).to.eql(true); + expect(syncPropertyExists).to.eql(true); - done(); - } + done(); + } ); }); }); @@ -1875,7 +1875,7 @@ describe('Replication / Change APIs', function() { } function assertTargetModelEqualsSourceModel(conflicts, sourceModel, - targetModel, done) { + targetModel, done) { var sourceData, targetData; assert(conflicts.length === 0); diff --git a/test/rest.middleware.test.js b/test/rest.middleware.test.js index ea64da03..f6547214 100644 --- a/test/rest.middleware.test.js +++ b/test/rest.middleware.test.js @@ -239,12 +239,12 @@ describe('loopback.rest', function() { describe('with specific definitions in model-config.json', function() { it('should not be exposed when the definition value is false', - function(done) { - var app = require(getFixturePath('model-config-defined-false')); - request(app) - .get('/todos') - .expect(404, done); - }); + function(done) { + var app = require(getFixturePath('model-config-defined-false')); + request(app) + .get('/todos') + .expect(404, done); + }); it('should be exposed when the definition value is true', function(done) { var app = require(getFixturePath('model-config-defined-true')); @@ -256,12 +256,12 @@ describe('loopback.rest', function() { describe('with default definitions in model-config.json', function() { it('should not be exposed when the definition value is false', - function(done) { - var app = require(getFixturePath('model-config-default-false')); - request(app) - .get('/todos') - .expect(404, done); - }); + function(done) { + var app = require(getFixturePath('model-config-default-false')); + request(app) + .get('/todos') + .expect(404, done); + }); it('should be exposed when the definition value is true', function(done) { var app = require(getFixturePath('model-config-default-true')); @@ -286,30 +286,30 @@ describe('loopback.rest', function() { describe('with specific definitions in config.json', function() { it('should not be exposed when the definition value is false', - function(done) { - var app = require(getFixturePath('config-defined-false')); - request(app) - .get('/todos') - .expect(404, done); - }); + function(done) { + var app = require(getFixturePath('config-defined-false')); + request(app) + .get('/todos') + .expect(404, done); + }); it('should be exposed when the definition value is true', - function(done) { - var app = require(getFixturePath('config-defined-true')); - request(app) - .get('/todos') - .expect(200, done); - }); + function(done) { + var app = require(getFixturePath('config-defined-true')); + request(app) + .get('/todos') + .expect(200, done); + }); }); describe('with default definitions in config.json', function() { it('should not be exposed when the definition value is false', - function(done) { - var app = require(getFixturePath('config-default-false')); - request(app) - .get('/todos') - .expect(404, done); - }); + function(done) { + var app = require(getFixturePath('config-default-false')); + request(app) + .get('/todos') + .expect(404, done); + }); it('should be exposed when the definition value is true', function(done) { var app = require(getFixturePath('config-default-true')); @@ -337,21 +337,21 @@ describe('loopback.rest', function() { // a side effect since tests share the same loopback instance. As a // consequence, this causes the tests in user.integration to fail. describe.skip('with definitions in both config.json and model-config.json', - function() { - it('should prioritize the settings in model-config.json', function(done) { - var app = require(getFixturePath('both-configs-set')); - request(app) - .del('/todos') - .expect(404, done); - }); - - it('should fall back to config.json settings if setting is not found in' + - 'model-config.json', function(done) { - var app = require(getFixturePath('both-configs-set')); - request(app) - .get('/todos') - .expect(404, done); - }); + function() { + it('should prioritize the settings in model-config.json', function(done) { + var app = require(getFixturePath('both-configs-set')); + request(app) + .del('/todos') + .expect(404, done); }); + + it('should fall back to config.json settings if setting is not found in' + + 'model-config.json', function(done) { + var app = require(getFixturePath('both-configs-set')); + request(app) + .get('/todos') + .expect(404, done); + }); + }); }); }); diff --git a/test/role-mapping.test.js b/test/role-mapping.test.js index afc794b0..e04deb4d 100644 --- a/test/role-mapping.test.js +++ b/test/role-mapping.test.js @@ -31,11 +31,11 @@ describe('role-mapping model', function() { models.Application.create({name: 'anApp'}), models.Role.create({name: 'aRole'}), ]) - .spread(function(u, a, r) { - oneUser = u; - anApp = a; - aRole = r; - }); + .spread(function(u, a, r) { + oneUser = u; + anApp = a; + aRole = r; + }); // helper function setupModel(modelName) { diff --git a/test/role.test.js b/test/role.test.js index e2a262c4..af67cc0f 100644 --- a/test/role.test.js +++ b/test/role.test.js @@ -111,36 +111,36 @@ describe('role model', function() { Role.create({name: 'userRole'}, function(err, role) { if (err) return done(err); role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, - function(err, p) { - if (err) return done(err); - async.parallel([ - function(next) { - Role.find(function(err, roles) { - if (err) return next(err); - assert.equal(roles.length, 1); - assert.equal(roles[0].name, 'userRole'); - next(); - }); - }, - function(next) { - role.principals(function(err, principals) { - if (err) return next(err); - assert.equal(principals.length, 1); - assert.equal(principals[0].principalType, RoleMapping.USER); - assert.equal(principals[0].principalId, user.id); - next(); - }); - }, - function(next) { - role.users(function(err, users) { - if (err) return next(err); - assert.equal(users.length, 1); - assert.equal(users[0].id, user.id); - next(); - }); - }, - ], done); - }); + function(err, p) { + if (err) return done(err); + async.parallel([ + function(next) { + Role.find(function(err, roles) { + if (err) return next(err); + assert.equal(roles.length, 1); + assert.equal(roles[0].name, 'userRole'); + next(); + }); + }, + function(next) { + role.principals(function(err, principals) { + if (err) return next(err); + assert.equal(principals.length, 1); + assert.equal(principals[0].principalType, RoleMapping.USER); + assert.equal(principals[0].principalId, user.id); + next(); + }); + }, + function(next) { + role.users(function(err, users) { + if (err) return next(err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + next(); + }); + }, + ], done); + }); }); }); }); @@ -168,38 +168,38 @@ describe('role model', function() { if (err) return done(err); assert(role.id); role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, - function(err, p) { - if (err) return done(err); - assert(p.id); - assert.equal(p.roleId, role.id); - async.parallel([ - function(next) { - Role.find(function(err, roles) { - if (err) return next(err); - assert.equal(roles.length, 1); - assert.equal(roles[0].name, 'userRole'); + function(err, p) { + if (err) return done(err); + assert(p.id); + assert.equal(p.roleId, role.id); + async.parallel([ + function(next) { + Role.find(function(err, roles) { + if (err) return next(err); + assert.equal(roles.length, 1); + assert.equal(roles[0].name, 'userRole'); + next(); + }); + }, + function(next) { + role.principals(function(err, principals) { + if (err) return next(err); + assert.equal(principals.length, 1); + assert.equal(principals[0].principalType, RoleMapping.USER); + assert.equal(principals[0].principalId, user.id); + next(); + }); + }, + function(next) { + role.users(function(err, users) { + if (err) return next(err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + }); next(); - }); - }, - function(next) { - role.principals(function(err, principals) { - if (err) return next(err); - assert.equal(principals.length, 1); - assert.equal(principals[0].principalType, RoleMapping.USER); - assert.equal(principals[0].principalId, user.id); - next(); - }); - }, - function(next) { - role.users(function(err, users) { - if (err) return next(err); - assert.equal(users.length, 1); - assert.equal(users[0].id, user.id); - }); - next(); - }, - ], done); - }); + }, + ], done); + }); }); }); }); @@ -210,106 +210,106 @@ describe('role model', function() { Role.create({name: 'userRole'}, function(err, role) { if (err) return done(err); role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, - function(err, p) { - if (err) return done(err); - async.series([ - function(next) { - Role.isInRole( - 'userRole', - {principalType: RoleMapping.USER, principalId: user.id}, - function(err, inRole) { - if (err) return next(err); - // NOTE(bajtos) Apparently isRole is not a boolean, - // but the matchin role object instead - assert(!!inRole); - next(); - }); - }, - function(next) { - Role.isInRole( - 'userRole', - {principalType: RoleMapping.APP, principalId: user.id}, - function(err, inRole) { - if (err) return next(err); - assert(!inRole); - next(); - }); - }, - function(next) { - Role.isInRole( - 'userRole', - {principalType: RoleMapping.USER, principalId: 100}, - function(err, inRole) { - if (err) return next(err); - assert(!inRole); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.USER, principalId: user.id}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.AUTHENTICATED, - Role.EVERYONE, - role.id, - ]); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.USER, principalId: user.id}, - {returnOnlyRoleNames: true}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.AUTHENTICATED, - Role.EVERYONE, - role.name, - ]); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.APP, principalId: user.id}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.AUTHENTICATED, - Role.EVERYONE, - ]); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.USER, principalId: 100}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.AUTHENTICATED, - Role.EVERYONE, - ]); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.USER, principalId: null}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.UNAUTHENTICATED, - Role.EVERYONE, - ]); - next(); - }); - }, - ], done); - }); + function(err, p) { + if (err) return done(err); + async.series([ + function(next) { + Role.isInRole( + 'userRole', + {principalType: RoleMapping.USER, principalId: user.id}, + function(err, inRole) { + if (err) return next(err); + // NOTE(bajtos) Apparently isRole is not a boolean, + // but the matchin role object instead + assert(!!inRole); + next(); + }); + }, + function(next) { + Role.isInRole( + 'userRole', + {principalType: RoleMapping.APP, principalId: user.id}, + function(err, inRole) { + if (err) return next(err); + assert(!inRole); + next(); + }); + }, + function(next) { + Role.isInRole( + 'userRole', + {principalType: RoleMapping.USER, principalId: 100}, + function(err, inRole) { + if (err) return next(err); + assert(!inRole); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.USER, principalId: user.id}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + role.id, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.USER, principalId: user.id}, + {returnOnlyRoleNames: true}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + role.name, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.APP, principalId: user.id}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.USER, principalId: 100}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.USER, principalId: null}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.UNAUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + ], done); + }); }); }); }); @@ -380,44 +380,44 @@ describe('role model', function() { Role.create({name: 'userRole'}, function(err, role) { if (err) return done(err); role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, - function(err, p) { - if (err) return done(err); - async.series([ - function(next) { - Role.isInRole( - 'userRole', - {principalType: RoleMapping.USER, principalId: user.id}, - function(err, inRole) { - if (err) return next(err); - assert(!!inRole); - next(); - }); - }, - function(next) { - Role.isInRole( - 'userRole', - {principalType: RoleMapping.APP, principalId: user.id}, - function(err, inRole) { - if (err) return next(err); - assert(!inRole); - next(); - }); - }, - function(next) { - Role.getRoles( - {principalType: RoleMapping.USER, principalId: user.id}, - function(err, roles) { - if (err) return next(err); - expect(roles).to.eql([ - Role.AUTHENTICATED, - Role.EVERYONE, - role.id, - ]); - next(); - }); - }, - ], done); - }); + function(err, p) { + if (err) return done(err); + async.series([ + function(next) { + Role.isInRole( + 'userRole', + {principalType: RoleMapping.USER, principalId: user.id}, + function(err, inRole) { + if (err) return next(err); + assert(!!inRole); + next(); + }); + }, + function(next) { + Role.isInRole( + 'userRole', + {principalType: RoleMapping.APP, principalId: user.id}, + function(err, inRole) { + if (err) return next(err); + assert(!inRole); + next(); + }); + }, + function(next) { + Role.getRoles( + {principalType: RoleMapping.USER, principalId: user.id}, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + role.id, + ]); + next(); + }); + }, + ], done); + }); }); }); }); @@ -566,19 +566,19 @@ describe('role model', function() { app.model(Album, {dataSource: 'db'}); return User.create({email: 'test@example.com', password: 'pass'}) - .then(u => { - user = u; - return Album.create({name: 'Album 1', userId: user.id}); - }) - .then(album => { - return Role.isInRole(Role.OWNER, { - principalType: ACL.USER, - principalId: user.id, - model: Album, - id: album.id, - }); - }) - .then(isInRole => expect(isInRole).to.be.true()); + .then(u => { + user = u; + return Album.create({name: 'Album 1', userId: user.id}); + }) + .then(album => { + return Role.isInRole(Role.OWNER, { + principalType: ACL.USER, + principalId: user.id, + model: Album, + id: album.id, + }); + }) + .then(isInRole => expect(isInRole).to.be.true()); }); it('resolves the owner via property "owner"', function() { @@ -590,9 +590,73 @@ describe('role model', function() { app.model(Album, {dataSource: 'db'}); return User.create({email: 'test@example.com', password: 'pass'}) + .then(u => { + user = u; + return Album.create({name: 'Album 1', owner: user.id}); + }) + .then(album => { + return Role.isInRole(Role.OWNER, { + principalType: ACL.USER, + principalId: user.id, + model: Album, + id: album.id, + }); + }) + .then(isInRole => expect(isInRole).to.be.true()); + }); + + it('resolves the owner via a belongsTo relation', function() { + // passing no options will result calling + // the legacy $owner role resolver behavior + var Message = givenModelWithSenderReceiverRelations('ModelWithNoOptions'); + + return givenUsers() + .then(() => { + var messages = [ + {content: 'firstMessage', senderId: sender.id}, + {content: 'secondMessage', receiverId: receiver.id}, + {content: 'thirdMessage'}, + ]; + return Promise.map(messages, msg => { + return Message.create(msg); + }); + }) + .then(messages => { + return Promise.all([ + isOwnerForMessage(sender, messages[0]), + isOwnerForMessage(receiver, messages[1]), + isOwnerForMessage(receiver, messages[2]), + ]); + }) + .then(result => { + expect(result).to.eql([ + {user: 'sender', msg: 'firstMessage', isOwner: true}, + {user: 'receiver', msg: 'secondMessage', isOwner: false}, + {user: 'receiver', msg: 'thirdMessage', isOwner: false}, + ]); + }); + }); + }); + + it('resolves as false without belongsTo relation', function() { + var user; + var Album = app.registry.createModel( + 'Album', + { + name: String, + userId: Number, + owner: Number, + }, + // passing {ownerRelations: true} will enable the new $owner role resolver + // and hence resolve false when no belongsTo relation is defined + {ownerRelations: true} + ); + app.model(Album, {dataSource: 'db'}); + + return User.create({email: 'test@example.com', password: 'pass'}) .then(u => { user = u; - return Album.create({name: 'Album 1', owner: user.id}); + return Album.create({name: 'Album 1', userId: user.id, owner: user.id}); }) .then(album => { return Role.isInRole(Role.OWNER, { @@ -602,15 +666,18 @@ describe('role model', function() { id: album.id, }); }) - .then(isInRole => expect(isInRole).to.be.true()); - }); + .then(isInRole => expect(isInRole).to.be.false()); + }); - it('resolves the owner via a belongsTo relation', function() { - // passing no options will result calling - // the legacy $owner role resolver behavior - var Message = givenModelWithSenderReceiverRelations('ModelWithNoOptions'); + it('resolves the owner using the corrent belongsTo relation', function() { + // passing {ownerRelations: true} will enable the new $owner role resolver + // with any belongsTo relation allowing to resolve truthy + var Message = givenModelWithSenderReceiverRelations( + 'ModelWithAllRelations', + {ownerRelations: true} + ); - return givenUsers() + return givenUsers() .then(() => { var messages = [ {content: 'firstMessage', senderId: sender.id}, @@ -631,124 +698,57 @@ describe('role model', function() { .then(result => { expect(result).to.eql([ {user: 'sender', msg: 'firstMessage', isOwner: true}, - {user: 'receiver', msg: 'secondMessage', isOwner: false}, + {user: 'receiver', msg: 'secondMessage', isOwner: true}, {user: 'receiver', msg: 'thirdMessage', isOwner: false}, ]); }); - }); - }); - - it('resolves as false without belongsTo relation', function() { - var user; - var Album = app.registry.createModel( - 'Album', - { - name: String, - userId: Number, - owner: Number, - }, - // passing {ownerRelations: true} will enable the new $owner role resolver - // and hence resolve false when no belongsTo relation is defined - {ownerRelations: true} - ); - app.model(Album, {dataSource: 'db'}); - - return User.create({email: 'test@example.com', password: 'pass'}) - .then(u => { - user = u; - return Album.create({name: 'Album 1', userId: user.id, owner: user.id}); - }) - .then(album => { - return Role.isInRole(Role.OWNER, { - principalType: ACL.USER, - principalId: user.id, - model: Album, - id: album.id, - }); - }) - .then(isInRole => expect(isInRole).to.be.false()); - }); - - it('resolves the owner using the corrent belongsTo relation', function() { - // passing {ownerRelations: true} will enable the new $owner role resolver - // with any belongsTo relation allowing to resolve truthy - var Message = givenModelWithSenderReceiverRelations( - 'ModelWithAllRelations', - {ownerRelations: true} - ); - - return givenUsers() - .then(() => { - var messages = [ - {content: 'firstMessage', senderId: sender.id}, - {content: 'secondMessage', receiverId: receiver.id}, - {content: 'thirdMessage'}, - ]; - return Promise.map(messages, msg => { - return Message.create(msg); - }); - }) - .then(messages => { - return Promise.all([ - isOwnerForMessage(sender, messages[0]), - isOwnerForMessage(receiver, messages[1]), - isOwnerForMessage(receiver, messages[2]), - ]); - }) - .then(result => { - expect(result).to.eql([ - {user: 'sender', msg: 'firstMessage', isOwner: true}, - {user: 'receiver', msg: 'secondMessage', isOwner: true}, - {user: 'receiver', msg: 'thirdMessage', isOwner: false}, - ]); - }); }); it('allows fine-grained control of which relations grant ownership', - function() { + function() { // passing {ownerRelations: true} will enable the new $owner role resolver // with a specified list of belongsTo relations allowing to resolve truthy - var Message = givenModelWithSenderReceiverRelations( - 'ModelWithCoercedRelations', - {ownerRelations: ['receiver']} - ); + var Message = givenModelWithSenderReceiverRelations( + 'ModelWithCoercedRelations', + {ownerRelations: ['receiver']} + ); - return givenUsers() - .then(() => { - var messages = [ - {content: 'firstMessage', senderId: sender.id}, - {content: 'secondMessage', receiverId: receiver.id}, - {content: 'thirdMessage'}, - ]; - return Promise.map(messages, msg => { - return Message.create(msg); - }); - }) - .then(messages => { - return Promise.all([ - isOwnerForMessage(sender, messages[0]), - isOwnerForMessage(receiver, messages[1]), - isOwnerForMessage(receiver, messages[2]), - ]); - }) - .then(result => { - expect(result).to.eql([ - {user: 'sender', msg: 'firstMessage', isOwner: false}, - {user: 'receiver', msg: 'secondMessage', isOwner: true}, - {user: 'receiver', msg: 'thirdMessage', isOwner: false}, - ]); + return givenUsers() + .then(() => { + var messages = [ + {content: 'firstMessage', senderId: sender.id}, + {content: 'secondMessage', receiverId: receiver.id}, + {content: 'thirdMessage'}, + ]; + return Promise.map(messages, msg => { + return Message.create(msg); + }); + }) + .then(messages => { + return Promise.all([ + isOwnerForMessage(sender, messages[0]), + isOwnerForMessage(receiver, messages[1]), + isOwnerForMessage(receiver, messages[2]), + ]); + }) + .then(result => { + expect(result).to.eql([ + {user: 'sender', msg: 'firstMessage', isOwner: false}, + {user: 'receiver', msg: 'secondMessage', isOwner: true}, + {user: 'receiver', msg: 'thirdMessage', isOwner: false}, + ]); + }); }); - }); // helpers function givenUsers() { return Promise.map(users, user => { return User.create(user); }) - .then(users => { - sender = users[0]; - receiver = users[1]; - }); + .then(users => { + sender = users[0]; + receiver = users[1]; + }); } function isOwnerForMessage(user, msg) { @@ -977,16 +977,6 @@ describe('role model', function() { done(); }); }); - - it('should report isMappedToRole by app.name', function(done) { - ACL.isMappedToRole(ACL.APP, app.name, 'admin', function(err, flag) { - if (err) return done(err); - - expect(flag).to.eql(true); - - done(); - }); - }); }); describe('listByPrincipalType', function() { @@ -1019,18 +1009,18 @@ describe('role model', function() { Role.create({name: uniqueRoleName}, function(err, role) { if (err) return done(err); role.principals.create({principalType: principalType, principalId: model.id}, - function(err, p) { - if (err) return done(err); - var pluralName = Model.pluralModelName.toLowerCase(); - role[pluralName](function(err, models) { + function(err, p) { if (err) return done(err); - assert.equal(models.length, 1); + var pluralName = Model.pluralModelName.toLowerCase(); + role[pluralName](function(err, models) { + if (err) return done(err); + assert.equal(models.length, 1); - if (++runs === mappings.length) { - done(); - } + if (++runs === mappings.length) { + done(); + } + }); }); - }); }); }); }); @@ -1052,13 +1042,13 @@ describe('role model', function() { // Create models function(next) { Model.create([ - {name: 'test', email: 'x@y.com', password: 'foobar'}, - {name: 'test2', email: 'f@v.com', password: 'bargoo'}, - {name: 'test3', email: 'd@t.com', password: 'bluegoo'}], - function(err, models) { - if (err) return next(err); - next(null, models); - }); + {name: 'test', email: 'x@y.com', password: 'foobar'}, + {name: 'test2', email: 'f@v.com', password: 'bargoo'}, + {name: 'test3', email: 'd@t.com', password: 'bluegoo'}], + function(err, models) { + if (err) return next(err); + next(null, models); + }); }, // Create Roles @@ -1066,12 +1056,12 @@ describe('role model', function() { var uniqueRoleName = 'testRoleFor' + principalType; var otherUniqueRoleName = 'otherTestRoleFor' + principalType; Role.create([ - {name: uniqueRoleName}, - {name: otherUniqueRoleName}], - function(err, roles) { - if (err) return next(err); - next(null, models, roles); - }); + {name: uniqueRoleName}, + {name: otherUniqueRoleName}], + function(err, roles) { + if (err) return next(err); + next(null, models, roles); + }); }, // Create principles @@ -1120,19 +1110,19 @@ describe('role model', function() { Role.create({name: 'userRole'}, function(err, role) { if (err) return done(err); role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, - function(err, p) { - if (err) return done(err); - var query = {fields: ['id', 'name']}; - sandbox.spy(User, 'find'); - role.users(query, function(err, users) { + function(err, p) { if (err) return done(err); - assert.equal(users.length, 1); - assert.equal(users[0].id, user.id); - assert(User.find.calledWith(query)); + var query = {fields: ['id', 'name']}; + sandbox.spy(User, 'find'); + role.users(query, function(err, users) { + if (err) return done(err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + assert(User.find.calledWith(query)); - done(); + done(); + }); }); - }); }); }); }); diff --git a/test/user-password.test.js b/test/user-password.test.js index d4b35799..531703da 100644 --- a/test/user-password.test.js +++ b/test/user-password.test.js @@ -207,7 +207,7 @@ describe('User.password', () => { User.resetPassword({email: credentials.email}), waitForEvent(User, 'resetPasswordRequest'), ]) - .spread((reset, info) => resetToken = info.accessToken); + .spread((reset, info) => resetToken = info.accessToken); } function changeName(token) { diff --git a/test/user.integration.js b/test/user.integration.js index e669bfb8..1deed403 100644 --- a/test/user.integration.js +++ b/test/user.integration.js @@ -313,6 +313,6 @@ describe('users - integration', function() { User.resetPassword({email: email}), waitForEvent(app.models.User, 'resetPasswordRequest'), ]) - .spread((reset, info) => info); + .spread((reset, info) => info); } }); diff --git a/test/user.test.js b/test/user.test.js index 91c5d1ed..94fcd782 100644 --- a/test/user.test.js +++ b/test/user.test.js @@ -216,7 +216,7 @@ describe('User', function() { it('Requires a unique username', function(done) { User.create({email: 'a@b.com', username: 'abc', password: 'foobar'}, function() { - User.create({email: 'b@b.com', username: 'abc', password: 'batbaz'}, function(err) { + User.create({email: 'b@b.com', username: 'abc', password: 'batbaz'}, function(err) { assert(err, 'should error because the username is not unique!'); done(); @@ -270,7 +270,7 @@ describe('User', function() { }); }, function(next) { - User.findById(usersId, function(err, userFound) { + User.findById(usersId, function(err, userFound) { if (err) return next(err); expect(userFound).to.equal(null); AccessToken.find({where: {userId: usersId}}, function(err, tokens) { @@ -322,7 +322,7 @@ describe('User', function() { }); }, function(next) { - User.find({where: {name: 'myname'}}, function(err, userFound) { + User.find({where: {name: 'myname'}}, function(err, userFound) { if (err) return next(err); expect(userFound.length).to.equal(0); AccessToken.find({where: {userId: {inq: userIds}}}, function(err, tokens) { @@ -471,7 +471,7 @@ describe('User', function() { it('accepts passwords that are exactly 72 characters long', function(done) { User.create({email: 'b@c.com', password: pass72Char}, function(err, user) { if (err) return done(err); - User.findById(user.pk, function(err, userFound) { + User.findById(user.pk, function(err, userFound) { if (err) return done(err); assert(userFound); done(); @@ -867,21 +867,21 @@ describe('User', function() { }); it('allows login with password too long but created in old LB version', - function(done) { - var bcrypt = require('bcryptjs'); - var longPassword = new Array(80).join('a'); - var oldHash = bcrypt.hashSync(longPassword, bcrypt.genSaltSync(1)); + function(done) { + var bcrypt = require('bcryptjs'); + var longPassword = new Array(80).join('a'); + var oldHash = bcrypt.hashSync(longPassword, bcrypt.genSaltSync(1)); - User.create({email: 'b@c.com', password: oldHash}, function(err) { - if (err) return done(err); - User.login({email: 'b@c.com', password: longPassword}, function(err, accessToken) { + User.create({email: 'b@c.com', password: oldHash}, function(err) { if (err) return done(err); - assert(accessToken.id); - // we are logged in, the test passed - done(); + User.login({email: 'b@c.com', password: longPassword}, function(err, accessToken) { + if (err) return done(err); + assert(accessToken.id); + // we are logged in, the test passed + done(); + }); }); }); - }); }); function assertGoodToken(accessToken, user) { @@ -919,21 +919,21 @@ describe('User', function() { }); it('requires valid and complete credentials for email verification - promise variant', - function(done) { - User.login({email: validCredentialsEmail}) - .then(function(accessToken) { - done(); - }) - .catch(function(err) { - // strongloop/loopback#931 - // error message should be "login failed" and not "login failed as the email has not been verified" - assert(err && !/verified/.test(err.message), - 'expecting "login failed" error message, received: "' + err.message + '"'); - assert.equal(err.code, 'LOGIN_FAILED'); - assert.equal(err.details, undefined); - done(); + function(done) { + User.login({email: validCredentialsEmail}) + .then(function(accessToken) { + done(); + }) + .catch(function(err) { + // strongloop/loopback#931 + // error message should be "login failed" and not "login failed as the email has not been verified" + assert(err && !/verified/.test(err.message), + 'expecting "login failed" error message, received: "' + err.message + '"'); + assert.equal(err.code, 'LOGIN_FAILED'); + assert.equal(err.details, undefined); + done(); + }); }); - }); it('does not login a user with unverified email but provides userId', function() { return User.login(validCredentials).then( @@ -1234,21 +1234,21 @@ describe('User', function() { }); it('Logout a user by providing the current accessToken id (using node) - promise variant', - function(done) { - login(logout); + function(done) { + login(logout); - function login(fn) { - User.login(validCredentials, fn); - } + function login(fn) { + User.login(validCredentials, fn); + } - function logout(err, accessToken) { - User.logout(accessToken.id) - .then(function() { - verify(accessToken.id, done); - }) - .catch(done(err)); - } - }); + function logout(err, accessToken) { + User.logout(accessToken.id) + .then(function() { + verify(accessToken.id, done); + }) + .catch(done(err)); + } + }); it('Logout a user by providing the current accessToken id (over rest)', function(done) { login(logout); @@ -2056,23 +2056,23 @@ describe('User', function() { }); it('verifies that verifyOptions.templateFn receives verifyOptions.verificationToken', - function() { - let actualVerificationToken; + function() { + let actualVerificationToken; - Object.assign(verifyOptions, { - redirect: '#/some-path?a=1&b=2', - templateFn: (verifyOptions, cb) => { - actualVerificationToken = verifyOptions.verificationToken; - cb(null, 'dummy body'); - }, - }); - - return user.verify(verifyOptions) - .then(() => actualVerificationToken) - .then(token => { - expect(token).to.exist(); + Object.assign(verifyOptions, { + redirect: '#/some-path?a=1&b=2', + templateFn: (verifyOptions, cb) => { + actualVerificationToken = verifyOptions.verificationToken; + cb(null, 'dummy body'); + }, }); - }); + + return user.verify(verifyOptions) + .then(() => actualVerificationToken) + .then(token => { + expect(token).to.exist(); + }); + }); it('forwards the "options" argument to user.save() ' + 'when adding verification token', function() { @@ -2722,10 +2722,10 @@ describe('User', function() { function(err, accessToken2) { if (err) return next(err); User.login({email: 'user3@example.com', password: 'u3pass'}, - function(err, accessToken3) { - if (err) return next(err); - next(); - }); + function(err, accessToken3) { + if (err) return next(err); + next(); + }); }); }); }, @@ -2760,12 +2760,12 @@ describe('User', function() { async.series([ function createSpecialUser(next) { User.create( - {email: 'special@example.com', password: 'pass1', name: 'Special'}, - function(err, specialInstance) { - if (err) return next(err); - userSpecial = specialInstance; - next(); - }); + {email: 'special@example.com', password: 'pass1', name: 'Special'}, + function(err, specialInstance) { + if (err) return next(err); + userSpecial = specialInstance; + next(); + }); }, function loginSpecialUser(next) { User.login({email: 'special@example.com', password: 'pass1'}, function(err, ats) { @@ -2775,11 +2775,11 @@ describe('User', function() { }, function updateSpecialUser(next) { User.updateAll( - {name: 'Special'}, - {email: 'superspecial@example.com'}, function(err, info) { - if (err) return next(err); - next(); - }); + {name: 'Special'}, + {email: 'superspecial@example.com'}, function(err, info) { + if (err) return next(err); + next(); + }); }, function verifyTokensOfSpecialUser(next) { AccessToken.find({where: {userId: userSpecial.pk}}, function(err, tokens1) { @@ -2942,48 +2942,48 @@ describe('User', function() { beforeEach(createOriginalUser); it('sets verification to false after email update if verification is required', - function(done) { - User.settings.emailVerificationRequired = true; - async.series([ - function updateUser(next) { - userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) { - if (err) return next(err); - assert.equal(info.email, NEW_EMAIL); - next(); - }); - }, - function findUser(next) { - User.findById(userInstance.pk, function(err, info) { - if (err) return next(err); - assert.equal(info.email, NEW_EMAIL); - assert.equal(info.emailVerified, false); - next(); - }); - }, - ], done); - }); + function(done) { + User.settings.emailVerificationRequired = true; + async.series([ + function updateUser(next) { + userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) { + if (err) return next(err); + assert.equal(info.email, NEW_EMAIL); + next(); + }); + }, + function findUser(next) { + User.findById(userInstance.pk, function(err, info) { + if (err) return next(err); + assert.equal(info.email, NEW_EMAIL); + assert.equal(info.emailVerified, false); + next(); + }); + }, + ], done); + }); it('leaves verification as is after email update if verification is not required', - function(done) { - User.settings.emailVerificationRequired = false; - async.series([ - function updateUser(next) { - userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) { - if (err) return next(err); - assert.equal(info.email, NEW_EMAIL); - next(); - }); - }, - function findUser(next) { - User.findById(userInstance.pk, function(err, info) { - if (err) return next(err); - assert.equal(info.email, NEW_EMAIL); - assert.equal(info.emailVerified, true); - next(); - }); - }, - ], done); - }); + function(done) { + User.settings.emailVerificationRequired = false; + async.series([ + function updateUser(next) { + userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) { + if (err) return next(err); + assert.equal(info.email, NEW_EMAIL); + next(); + }); + }, + function findUser(next) { + User.findById(userInstance.pk, function(err, info) { + if (err) return next(err); + assert.equal(info.email, NEW_EMAIL); + assert.equal(info.emailVerified, true); + next(); + }); + }, + ], done); + }); it('should not set verification to false after something other than email is updated', function(done) { @@ -3023,39 +3023,39 @@ describe('User', function() { describe('password reset with/without email verification', function() { it('allows resetPassword by email if email verification is required and done', - function(done) { - User.settings.emailVerificationRequired = true; - var email = validCredentialsEmailVerified.email; + function(done) { + User.settings.emailVerificationRequired = true; + var email = validCredentialsEmailVerified.email; - User.resetPassword({email: email}, function(err, info) { - if (err) return done(err); - done(); + User.resetPassword({email: email}, function(err, info) { + if (err) return done(err); + done(); + }); }); - }); it('disallows resetPassword by email if email verification is required and not done', - function(done) { - User.settings.emailVerificationRequired = true; - var email = validCredentialsEmail; + function(done) { + User.settings.emailVerificationRequired = true; + var email = validCredentialsEmail; - User.resetPassword({email: email}, function(err) { - assert(err); - assert.equal(err.code, 'RESET_FAILED_EMAIL_NOT_VERIFIED'); - assert.equal(err.statusCode, 401); - done(); + User.resetPassword({email: email}, function(err) { + assert(err); + assert.equal(err.code, 'RESET_FAILED_EMAIL_NOT_VERIFIED'); + assert.equal(err.statusCode, 401); + done(); + }); }); - }); it('allows resetPassword by email if email verification is not required', - function(done) { - User.settings.emailVerificationRequired = false; - var email = validCredentialsEmail; + function(done) { + User.settings.emailVerificationRequired = false; + var email = validCredentialsEmail; - User.resetPassword({email: email}, function(err) { - if (err) return done(err); - done(); + User.resetPassword({email: email}, function(err) { + if (err) return done(err); + done(); + }); }); - }); }); describe('ctor', function() { @@ -3085,6 +3085,6 @@ describe('User', function() { User.resetPassword({email: email}), waitForEvent(User, 'resetPasswordRequest'), ]) - .spread((reset, info) => info); + .spread((reset, info) => info); } }); diff --git a/test/util/model-tests.js b/test/util/model-tests.js index 0692ad51..0c9c6368 100644 --- a/test/util/model-tests.js +++ b/test/util/model-tests.js @@ -96,7 +96,7 @@ module.exports = function defineModelTestsWithDataSource(options) { var foo = new User({domain: 'www'}); var bar = new User({domain: 'billing'}); var bat = new User({domain: 'admin'}); - assert(foo.isValid() === false); + assert(foo.isValid() === false); assert(bar.isValid() === false); assert(bat.isValid() === false); assert(foo.errors.domain, 'model should have a domain error'); @@ -139,13 +139,13 @@ module.exports = function defineModelTestsWithDataSource(options) { describe('Model.create([data], [callback])', function() { it('Create an instance of Model with given data and save to the attached data source', - function(done) { - User.create({first: 'Joe', last: 'Bob'}, function(err, user) { - assert(user instanceof User); + function(done) { + User.create({first: 'Joe', last: 'Bob'}, function(err, user) { + assert(user instanceof User); - done(); + done(); + }); }); - }); }); describe('model.save([options], [callback])', function() {