Merge branch 'release/2.8.2' into production

This commit is contained in:
Miroslav Bajtoš 2014-11-27 10:01:13 +01:00
commit 465deefd8e
30 changed files with 1065 additions and 1020 deletions

View File

@ -9,5 +9,25 @@
"nonew": true,
"sub": true,
"laxcomma": true,
"laxbreak": true
"laxbreak": true,
"globals": {
"after": true,
"afterEach": true,
"assert": true,
"before": true,
"beforeEach": true,
"describe": true,
"expect": true,
"it": true,
/* loopback */
"app": true,
"assertValidDataSource": true,
"GeoPoint": true,
"loopback": true,
"memoryConnector": true,
"request": true,
"TaskEmitter": true
}
}

View File

@ -1,3 +1,21 @@
2014-11-27, Version 2.8.2
=========================
* Prepend slash for nested remoting paths (Clark Wang)
* fix jscs errors (Rob Halff)
* enable jshint for tests (Rob Halff)
* permit some globals (Rob Halff)
* 'done' is not defined (Rob Halff)
* 'memory' is already defined (Rob Halff)
* singlequote, semicolon & /*jshint -W030 */ (Rob Halff)
2014-11-25, Version 2.8.1
=========================

View File

@ -38,18 +38,17 @@ module.exports = function(grunt) {
},
server: {
src: ['server/**/*.js']
},
test: {
src: ['test/**/*.js']
}
// TODO tests don't pass yet
// test: {
// src: ['test/**/*.js']
// }
},
jscs: {
gruntfile: 'Gruntfile.js',
lib: ['lib/**/*.js'],
common: ['common/**/*.js'],
server: ['server/**/*.js']
// TODO(bajtos) - test/**/*.js
server: ['server/**/*.js'],
test: ['test/**/*.js']
},
watch: {
gruntfile: {

View File

@ -619,6 +619,10 @@ Model.nestRemoting = function(relationName, options, cb) {
acceptArgs = [];
}
if (httpPath[0] !== '/') {
httpPath = '/' + httpPath;
}
// A method should return the method name to use, if it is to be
// included as a nested method - a falsy return value will skip.
var filter = cb || options.filterMethod || function(method, relation) {

View File

@ -1,6 +1,6 @@
{
"name": "loopback",
"version": "2.8.1",
"version": "2.8.2",
"description": "LoopBack: Open Source Framework for Node.js",
"homepage": "http://loopback.io",
"keywords": [

View File

@ -1,3 +1,5 @@
/*jshint -W030 */
var loopback = require('../');
var lt = require('loopback-testing');
var path = require('path');
@ -8,19 +10,19 @@ var USER = {email: 'test@test.test', password: 'test'};
var CURRENT_USER = {email: 'current@test.test', password: 'test'};
var debug = require('debug')('loopback:test:access-control.integration');
describe('access control - integration', function () {
describe('access control - integration', function() {
lt.beforeEach.withApp(app);
/*
describe('accessToken', function() {
// it('should be a sublcass of AccessToken', function () {
// it('should be a sublcass of AccessToken', function() {
// assert(app.models.accessToken.prototype instanceof loopback.AccessToken);
// });
it('should have a validate method', function () {
it('should have a validate method', function() {
var token = new app.models.accessToken;
assert.equal(typeof token.validate, 'function');
assert.equal(typeof token.validate, 'function');
});
});
@ -58,17 +60,17 @@ describe('access control - integration', function () {
});
*/
describe('/users', function () {
describe('/users', function() {
lt.beforeEach.givenModel('user', USER, 'randomUser');
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/users');
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/users');
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', '/api/users');
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', urlForUser);
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', urlForUser);
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER,'GET', urlForUser);
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', urlForUser);
lt.it.shouldBeAllowedWhenCalledAnonymously(
'POST', '/api/users', newUserData());
@ -131,7 +133,7 @@ describe('access control - integration', function () {
}
});
describe('/banks', function () {
describe('/banks', function() {
lt.beforeEach.givenModel('bank');
lt.it.shouldBeAllowedWhenCalledAnonymously('GET', '/api/banks');
@ -159,13 +161,13 @@ describe('access control - integration', function () {
}
});
describe('/accounts', function () {
describe('/accounts', function() {
var count = 0;
before(function() {
var roleModel = loopback.getModelByType(loopback.Role);
roleModel.registerResolver('$dummy', function (role, context, callback) {
process.nextTick(function () {
if(context.remotingContext) {
roleModel.registerResolver('$dummy', function(role, context, callback) {
process.nextTick(function() {
if (context.remotingContext) {
count++;
}
callback && callback(null, false); // Always true
@ -224,5 +226,5 @@ describe('access control - integration', function () {
return '/api/accounts/' + this.account.id;
}
});
});

View File

@ -6,14 +6,14 @@ var ACL = loopback.ACL;
describe('loopback.token(options)', function() {
beforeEach(createTestingToken);
it('should populate req.token from the query string', function (done) {
it('should populate req.token from the query string', function(done) {
createTestAppAndRequest(this.token, done)
.get('/?access_token=' + this.token.id)
.expect(200)
.end(done);
});
it('should populate req.token from an authorization header', function (done) {
it('should populate req.token from an authorization header', function(done) {
createTestAppAndRequest(this.token, done)
.get('/')
.set('authorization', this.token.id)
@ -21,7 +21,7 @@ describe('loopback.token(options)', function() {
.end(done);
});
it('should populate req.token from an X-Access-Token header', function (done) {
it('should populate req.token from an X-Access-Token header', function(done) {
createTestAppAndRequest(this.token, done)
.get('/')
.set('X-Access-Token', this.token.id)
@ -29,9 +29,9 @@ describe('loopback.token(options)', function() {
.end(done);
});
it('should populate req.token from an authorization header with bearer token', function (done) {
it('should populate req.token from an authorization header with bearer token', function(done) {
var token = this.token.id;
token = 'Bearer '+ new Buffer(token).toString('base64');
token = 'Bearer ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
.set('authorization', this.token.id)
@ -39,7 +39,7 @@ describe('loopback.token(options)', function() {
.end(done);
});
it('should populate req.token from a secure cookie', function (done) {
it('should populate req.token from a secure cookie', function(done) {
var app = createTestApp(this.token, done);
request(app)
@ -52,7 +52,7 @@ describe('loopback.token(options)', function() {
});
});
it('should populate req.token from a header or a secure cookie', function (done) {
it('should populate req.token from a header or a secure cookie', function(done) {
var app = createTestApp(this.token, done);
var id = this.token.id;
request(app)
@ -88,20 +88,20 @@ describe('loopback.token(options)', function() {
});
});
describe('AccessToken', function () {
describe('AccessToken', function() {
beforeEach(createTestingToken);
it('should auto-generate id', function () {
it('should auto-generate id', function() {
assert(this.token.id);
assert.equal(this.token.id.length, 64);
});
it('should auto-generate created date', function () {
it('should auto-generate created date', function() {
assert(this.token.created);
assert(Object.prototype.toString.call(this.token.created), '[object Date]');
});
it('should be validateable', function (done) {
it('should be validateable', function(done) {
this.token.validate(function(err, isValid) {
assert(isValid);
done();
@ -144,7 +144,7 @@ describe('AccessToken', function () {
describe('app.enableAuth()', function() {
beforeEach(createTestingToken);
it('prevents remote call with 401 status on denied ACL', function (done) {
it('prevents remote call with 401 status on denied ACL', function(done) {
createTestAppAndRequest(this.token, done)
.del('/tests/123')
.expect(401)
@ -152,7 +152,7 @@ describe('app.enableAuth()', function() {
.end(done);
});
it('prevent remote call with app setting status on denied ACL', function (done) {
it('prevent remote call with app setting status on denied ACL', function(done) {
createTestAppAndRequest(this.token, {app:{aclErrorStatus:403}}, done)
.del('/tests/123')
.expect(403)
@ -160,7 +160,7 @@ describe('app.enableAuth()', function() {
.end(done);
});
it('prevent remote call with app setting status on denied ACL', function (done) {
it('prevent remote call with app setting status on denied ACL', function(done) {
createTestAppAndRequest(this.token, {model:{aclErrorStatus:404}}, done)
.del('/tests/123')
.expect(404)
@ -168,7 +168,7 @@ describe('app.enableAuth()', function() {
.end(done);
});
it('prevent remote call if the accessToken is missing and required', function (done) {
it('prevent remote call if the accessToken is missing and required', function(done) {
createTestAppAndRequest(null, done)
.del('/tests/123')
.expect(401)
@ -210,8 +210,8 @@ describe('app.enableAuth()', function() {
function createTestingToken(done) {
var test = this;
Token.create({}, function (err, token) {
if(err) return done(err);
Token.create({}, function(err, token) {
if (err) return done(err);
test.token = token;
done();
});
@ -223,8 +223,8 @@ function createTestAppAndRequest(testToken, settings, done) {
}
function createTestApp(testToken, settings, done) {
done = arguments[arguments.length-1];
if(settings == done) settings = {};
done = arguments[arguments.length - 1];
if (settings == done) settings = {};
settings = settings || {};
var appSettings = settings.app || {};
@ -238,11 +238,11 @@ function createTestApp(testToken, settings, done) {
res.cookie('authorization', testToken.id, {signed: true});
res.end();
});
app.get('/', function (req, res) {
app.get('/', function(req, res) {
try {
assert(req.accessToken, 'req should have accessToken');
assert(req.accessToken.id === testToken.id);
} catch(e) {
} catch (e) {
return done(e);
}
res.send('ok');
@ -250,15 +250,15 @@ function createTestApp(testToken, settings, done) {
app.use(loopback.rest());
app.enableAuth();
Object.keys(appSettings).forEach(function(key){
Object.keys(appSettings).forEach(function(key) {
app.set(key, appSettings[key]);
});
var modelOptions = {
acls: [
{
principalType: "ROLE",
principalId: "$everyone",
principalType: 'ROLE',
principalId: '$everyone',
accessType: ACL.ALL,
permission: ACL.DENY,
property: 'deleteById'
@ -266,7 +266,7 @@ function createTestApp(testToken, settings, done) {
]
};
Object.keys(modelSettings).forEach(function(key){
Object.keys(modelSettings).forEach(function(key) {
modelOptions[key] = modelSettings[key];
});

View File

@ -17,7 +17,7 @@ before(function() {
ds = loopback.createDataSource({connector: loopback.Memory});
});
describe('security scopes', function () {
describe('security scopes', function() {
beforeEach(function() {
var ds = this.ds = loopback.createDataSource({connector: loopback.Memory});
testModel = loopback.PersistedModel.extend('testModel');
@ -29,11 +29,11 @@ describe('security scopes', function () {
testModel.attachTo(ds);
});
it("should allow access to models for the given scope by wildcard", function () {
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
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) {
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);
@ -42,25 +42,25 @@ describe('security scopes', function () {
});
it("should allow access to models for the given scope", function () {
Scope.create({name: 'testModelScope', description: 'access testModel information'}, function (err, scope) {
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) {
function(err, resource) {
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
model: 'testModel', property: 'name', accessType: ACL.WRITE, permission: ACL.DENY},
function (err, resource) {
function(err, resource) {
// console.log(resource);
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL, function (err, perm) {
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) {
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) {
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) {
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
});
@ -71,29 +71,29 @@ describe('security scopes', function () {
});
describe('security ACLs', function () {
describe('security ACLs', function() {
it('should order ACL entries based on the matching score', function() {
var acls = [
{
"model": "account",
"accessType": "*",
"permission": "DENY",
"principalType": "ROLE",
"principalId": "$everyone"
'model': 'account',
'accessType': '*',
'permission': 'DENY',
'principalType': 'ROLE',
'principalId': '$everyone'
},
{
"model": "account",
"accessType": "*",
"permission": "ALLOW",
"principalType": "ROLE",
"principalId": "$owner"
'model': 'account',
'accessType': '*',
'permission': 'ALLOW',
'principalType': 'ROLE',
'principalId': '$owner'
},
{
"model": "account",
"accessType": "READ",
"permission": "ALLOW",
"principalType": "ROLE",
"principalId": "$everyone"
'model': 'account',
'accessType': 'READ',
'permission': 'ALLOW',
'principalType': 'ROLE',
'principalId': '$everyone'
}];
var req = {
model: 'account',
@ -101,7 +101,7 @@ describe('security ACLs', function () {
accessType: 'WRITE'
};
acls = acls.map(function(a) { return new ACL(a)});
acls = acls.map(function(a) { return new ACL(a); });
var perm = ACL.resolvePermission(acls, req);
assert.deepEqual(perm, { model: 'account',
@ -111,18 +111,18 @@ describe('security ACLs', function () {
methodNames: []});
});
it("should allow access to models for the given principal by wildcard", function () {
it('should allow access to models for the given principal by wildcard', function() {
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
accessType: ACL.ALL, permission: ACL.ALLOW}, function (err, acl) {
accessType: ACL.ALL, permission: ACL.ALLOW}, function(err, acl) {
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
accessType: ACL.READ, permission: ACL.DENY}, function (err, acl) {
accessType: ACL.READ, permission: ACL.DENY}, function(err, acl) {
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.READ, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.READ, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.ALL, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.ALL, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
@ -132,26 +132,26 @@ describe('security ACLs', function () {
});
it("should allow access to models by exception", function () {
it('should allow access to models by exception', function() {
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
accessType: ACL.ALL, permission: ACL.DENY}, function (err, acl) {
accessType: ACL.ALL, permission: ACL.DENY}, function(err, acl) {
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
accessType: ACL.READ, permission: ACL.ALLOW}, function (err, acl) {
accessType: ACL.READ, permission: ACL.ALLOW}, function(err, acl) {
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ, function(err, perm) {
assert(perm.permission === ACL.ALLOW);
});
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ, function(err, perm) {
assert(perm.permission === ACL.ALLOW);
});
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
@ -161,7 +161,7 @@ describe('security ACLs', function () {
});
it("should honor defaultPermission from the model", function () {
it('should honor defaultPermission from the model', function() {
var Customer = ds.createModel('Customer', {
name: {
type: String,
@ -178,21 +178,21 @@ describe('security ACLs', function () {
Customer.settings.defaultPermission = ACL.DENY;
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function(err, perm) {
assert(perm.permission === ACL.ALLOW);
});
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.WRITE, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.WRITE, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
});
it("should honor static ACLs from the model", function () {
it('should honor static ACLs from the model', function() {
var Customer = ds.createModel('Customer', {
name: {
type: String,
@ -213,21 +213,21 @@ describe('security ACLs', function () {
];
*/
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function(err, perm) {
assert(perm.permission === ACL.DENY);
});
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function(err, perm) {
assert(perm.permission === ACL.ALLOW);
});
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL, function (err, perm) {
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL, function(err, perm) {
assert(perm.permission === ACL.ALLOW);
});
});
it("should filter static ACLs by model/property", function() {
it('should filter static ACLs by model/property', function() {
var Model1 = ds.createModel('Model1', {
name: {
type: String,
@ -254,12 +254,12 @@ describe('security ACLs', function () {
assert(staticACLs.length === 1);
});
it("should check access against LDL, ACL, and Role", function () {
it('should check access against LDL, ACL, and Role', function() {
// var log = console.log;
var log = function() {};
// Create
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
log('User: ', user.toObject());
@ -282,19 +282,19 @@ describe('security ACLs', function () {
});
ACL.create({principalType: ACL.USER, principalId: userId, model: 'Customer', property: ACL.ALL,
accessType: ACL.ALL, permission: ACL.ALLOW}, function (err, acl) {
accessType: ACL.ALL, permission: ACL.ALLOW}, function(err, acl) {
log('ACL 1: ', acl.toObject());
Role.create({name: 'MyRole'}, function (err, myRole) {
Role.create({name: 'MyRole'}, function(err, myRole) {
log('Role: ', myRole.toObject());
myRole.principals.create({principalType: RoleMapping.USER, principalId: userId}, function (err, p) {
myRole.principals.create({principalType: RoleMapping.USER, principalId: userId}, 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) {
accessType: ACL.READ, permission: ACL.DENY}, function(err, acl) {
log('ACL 2: ', acl.toObject());
@ -327,6 +327,3 @@ describe('security ACLs', function () {
});
});
});

View File

@ -1,3 +1,5 @@
/*jshint -W030 */
var async = require('async');
var path = require('path');
@ -39,7 +41,7 @@ describe('app', function() {
});
});
it('supports "before:" and "after:" prefixes', function(done) {
it('supports `before:` and `after:` prefixes', function(done) {
app.middleware('routes:before', namedHandler('routes:before'));
app.middleware('routes:after', namedHandler('routes:after'));
app.use(namedHandler('main'));
@ -247,7 +249,7 @@ describe('app', function() {
app = loopback();
});
it('adds the phase just before "routes" by default', function(done) {
it('adds the phase just before `routes` by default', function(done) {
app.defineMiddlewarePhases('custom');
verifyMiddlewarePhases(['custom', 'routes'], done);
});
@ -305,13 +307,14 @@ describe('app', function() {
});
describe('app.model(Model)', function() {
var app, db;
var app;
var db;
beforeEach(function() {
app = loopback();
db = loopback.createDataSource({connector: loopback.Memory});
});
it("Expose a `Model` to remote clients", function() {
it('Expose a `Model` to remote clients', function() {
var Color = PersistedModel.extend('color', {name: String});
app.model(Color);
Color.attachTo(db);
@ -330,7 +333,7 @@ describe('app', function() {
var Color = PersistedModel.extend('color', {name: String});
app.model(Color);
Color.attachTo(db);
var classes = app.remotes().classes().map(function(c) {return c.name});
var classes = app.remotes().classes().map(function(c) {return c.name;});
expect(classes).to.contain('color');
});
@ -343,7 +346,7 @@ describe('app', function() {
expect(app.models.Color).to.equal(Color);
});
it("emits a `modelRemoted` event", function() {
it('emits a `modelRemoted` event', function() {
var Color = PersistedModel.extend('color', {name: String});
Color.shared = true;
var remotedClass;
@ -376,7 +379,7 @@ describe('app', function() {
});
describe('app.model(name, config)', function () {
describe('app.model(name, config)', function() {
var app;
beforeEach(function() {
@ -386,7 +389,7 @@ describe('app', function() {
});
});
it('Sugar for defining a fully built model', function () {
it('Sugar for defining a fully built model', function() {
app.model('foo', {
dataSource: 'db'
});
@ -493,7 +496,7 @@ describe('app', function() {
.expect(200, done);
});
it('updates port on "listening" event', function(done) {
it('updates port on `listening` event', function(done) {
var app = loopback();
app.set('port', 0);
@ -503,7 +506,7 @@ describe('app', function() {
});
});
it('updates "url" on "listening" event', function(done) {
it('updates `url` on `listening` event', function(done) {
var app = loopback();
app.set('port', 0);
app.set('host', undefined);
@ -559,15 +562,15 @@ describe('app', function() {
});
});
describe.onServer('app.get("/", loopback.status())', function () {
it('should return the status of the application', function (done) {
describe.onServer('app.get(\'/\', loopback.status())', function() {
it('should return the status of the application', function(done) {
var app = loopback();
app.get('/', loopback.status());
request(app)
.get('/')
.expect(200)
.end(function(err, res) {
if(err) return done(err);
if (err) return done(err);
assert.equal(typeof res.body, 'object');
assert(res.body.started);
@ -649,7 +652,8 @@ describe('app', function() {
});
describe('normalizeHttpPath option', function() {
var app, db;
var app;
var db;
beforeEach(function() {
app = loopback();
db = loopback.createDataSource({ connector: loopback.Memory });

View File

@ -1,7 +1,7 @@
var Change;
var TestModel;
describe('Change', function(){
describe('Change', function() {
beforeEach(function() {
var memory = loopback.createDataSource({
connector: loopback.Memory
@ -20,7 +20,7 @@ describe('Change', function(){
foo: 'bar'
};
TestModel.create(test.data, function(err, model) {
if(err) return done(err);
if (err) return done(err);
test.model = model;
test.modelId = model.id;
test.revisionForModel = Change.revisionForInst(model);
@ -28,8 +28,8 @@ describe('Change', function(){
});
});
describe('change.id', function () {
it('should be a hash of the modelName and modelId', function () {
describe('change.id', function() {
it('should be a hash of the modelName and modelId', function() {
var change = new Change({
rev: 'abc',
modelName: 'foo',
@ -42,17 +42,17 @@ describe('Change', function(){
});
});
describe('Change.rectifyModelChanges(modelName, modelIds, callback)', function () {
describe('using an existing untracked model', function () {
describe('Change.rectifyModelChanges(modelName, modelIds, callback)', function() {
describe('using an existing untracked model', function() {
beforeEach(function(done) {
var test = this;
Change.rectifyModelChanges(this.modelName, [this.modelId], function(err, trackedChanges) {
if(err) return done(err);
if (err) return done(err);
done();
});
});
it('should create an entry', function (done) {
it('should create an entry', function(done) {
var test = this;
Change.find(function(err, trackedChanges) {
assert.equal(trackedChanges[0].modelId, test.modelId.toString());
@ -60,7 +60,7 @@ describe('Change', function(){
});
});
it('should only create one change', function (done) {
it('should only create one change', function(done) {
Change.count(function(err, count) {
assert.equal(count, 1);
done();
@ -69,19 +69,19 @@ describe('Change', function(){
});
});
describe('Change.findOrCreateChange(modelName, modelId, callback)', function () {
describe('when a change doesnt exist', function () {
describe('Change.findOrCreateChange(modelName, modelId, callback)', function() {
describe('when a change doesnt exist', function() {
beforeEach(function(done) {
var test = this;
Change.findOrCreateChange(this.modelName, this.modelId, function(err, result) {
if(err) return done(err);
if (err) return done(err);
test.result = result;
done();
});
});
it('should create an entry', function (done) {
it('should create an entry', function(done) {
var test = this;
Change.findById(this.result.id, function(err, change) {
if (err) return done(err);
@ -91,7 +91,7 @@ describe('Change', function(){
});
});
describe('when a change does exist', function () {
describe('when a change does exist', function() {
beforeEach(function(done) {
var test = this;
Change.create({
@ -106,22 +106,22 @@ describe('Change', function(){
beforeEach(function(done) {
var test = this;
Change.findOrCreateChange(this.modelName, this.modelId, function(err, result) {
if(err) return done(err);
if (err) return done(err);
test.result = result;
done();
});
});
it('should find the entry', function (done) {
var test = this;
it('should find the entry', function(done) {
var test = this;
assert.equal(test.existingChange.id, test.result.id);
done();
});
});
});
describe('change.rectify(callback)', function () {
it('should create a new change with the correct revision', function (done) {
describe('change.rectify(callback)', function() {
it('should create a new change with the correct revision', function(done) {
var test = this;
var change = new Change({
modelName: this.modelName,
@ -135,8 +135,8 @@ describe('Change', function(){
});
});
describe('change.currentRevision(callback)', function () {
it('should get the correct revision', function (done) {
describe('change.currentRevision(callback)', function() {
it('should get the correct revision', function(done) {
var test = this;
var change = new Change({
modelName: this.modelName,
@ -150,9 +150,9 @@ describe('Change', function(){
});
});
describe('Change.hash(str)', function () {
describe('Change.hash(str)', function() {
// todo(ritch) test other hashing algorithms
it('should hash the given string', function () {
it('should hash the given string', function() {
var str = 'foo';
var hash = Change.hash(str);
assert(hash !== str);
@ -160,8 +160,8 @@ describe('Change', function(){
});
});
describe('Change.revisionForInst(inst)', function () {
it('should return the same revision for the same data', function () {
describe('Change.revisionForInst(inst)', function() {
it('should return the same revision for the same data', function() {
var a = {
b: {
b: ['c', 'd'],
@ -181,34 +181,34 @@ describe('Change', function(){
});
});
describe('change.type()', function () {
it('CREATE', function () {
describe('change.type()', function() {
it('CREATE', function() {
var change = new Change({
rev: this.revisionForModel
});
assert.equal(Change.CREATE, change.type());
});
it('UPDATE', function () {
it('UPDATE', function() {
var change = new Change({
rev: this.revisionForModel,
prev: this.revisionForModel
});
assert.equal(Change.UPDATE, change.type());
});
it('DELETE', function () {
it('DELETE', function() {
var change = new Change({
prev: this.revisionForModel
});
assert.equal(Change.DELETE, change.type());
});
it('UNKNOWN', function () {
it('UNKNOWN', function() {
var change = new Change();
assert.equal(Change.UNKNOWN, change.type());
});
});
describe('change.getModelCtor()', function () {
it('should get the correct model class', function () {
describe('change.getModelCtor()', function() {
it('should get the correct model class', function() {
var change = new Change({
modelName: this.modelName
});
@ -217,8 +217,8 @@ describe('Change', function(){
});
});
describe('change.equals(otherChange)', function () {
it('should return true when the change is equal', function () {
describe('change.equals(otherChange)', function() {
it('should return true when the change is equal', function() {
var change = new Change({
rev: this.revisionForModel
});
@ -230,7 +230,7 @@ describe('Change', function(){
assert.equal(change.equals(otherChange), true);
});
it('should return true when both changes are deletes', function () {
it('should return true when both changes are deletes', function() {
var REV = 'foo';
var change = new Change({
rev: null,
@ -249,8 +249,8 @@ describe('Change', function(){
});
});
describe('change.isBasedOn(otherChange)', function () {
it('should return true when the change is based on the other', function () {
describe('change.isBasedOn(otherChange)', function() {
it('should return true when the change is based on the other', function() {
var change = new Change({
prev: this.revisionForModel
});
@ -263,7 +263,7 @@ describe('Change', function(){
});
});
describe('Change.diff(modelName, since, remoteChanges, callback)', function () {
describe('Change.diff(modelName, since, remoteChanges, callback)', function() {
beforeEach(function(done) {
Change.create([
{rev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
@ -272,7 +272,7 @@ describe('Change', function(){
], done);
});
it('should return delta and conflict lists', function (done) {
it('should return delta and conflict lists', function(done) {
var remoteChanges = [
// an update => should result in a delta
{rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},

View File

@ -1,16 +1,16 @@
describe('DataSource', function() {
var memory;
beforeEach(function(){
beforeEach(function() {
memory = loopback.createDataSource({
connector: loopback.Memory
});
assertValidDataSource(memory);
});
describe('dataSource.createModel(name, properties, settings)', function() {
it("Define a model and attach it to a `DataSource`", function() {
it('Define a model and attach it to a `DataSource`', function() {
var Color = memory.createModel('color', {name: String});
assert.isFunc(Color, 'find');
assert.isFunc(Color, 'findById');
@ -31,23 +31,23 @@ describe('DataSource', function() {
assert.isFunc(Color.prototype, 'destroy');
assert.isFunc(Color.prototype, 'updateAttribute');
assert.isFunc(Color.prototype, 'updateAttributes');
assert.isFunc(Color.prototype, 'reload');
assert.isFunc(Color.prototype, 'reload');
});
it("should honor settings.base", function() {
it('should honor settings.base', function() {
var Base = memory.createModel('base');
var Color = memory.createModel('color', {name: String}, {base: Base});
assert(Color.prototype instanceof Base);
assert.equal(Color.base, Base);
});
it("should use loopback.PersistedModel as the base for DBs", function() {
it('should use loopback.PersistedModel as the base for DBs', function() {
var Color = memory.createModel('color', {name: String});
assert(Color.prototype instanceof loopback.PersistedModel);
assert.equal(Color.base, loopback.PersistedModel);
});
it("should use loopback.Model as the base for non DBs", function() {
it('should use loopback.Model as the base for non DBs', function() {
// Mock up a non-DB connector
var Connector = function() {
};
@ -67,10 +67,10 @@ describe('DataSource', function() {
});
describe.skip('PersistedModel Methods', function() {
it("List the enabled and disabled methods", function() {
it('List the enabled and disabled methods', function() {
var TestModel = loopback.PersistedModel.extend('TestPersistedModel');
TestModel.attachTo(loopback.memory());
// assert the defaults
// - true: the method should be remote enabled
// - false: the method should not be remote enabled
@ -97,7 +97,7 @@ describe('DataSource', function() {
existsAndShared('updateAttributes', true);
existsAndShared('updateAll', true);
existsAndShared('reload', false);
function existsAndShared(Model, name, isRemoteEnabled, isProto) {
var scope = isProto ? Model.prototype : Model;
var fn = scope[name];

View File

@ -14,22 +14,22 @@ describe('RemoteConnector', function() {
TestModel.attachTo(ds);
});
it('should be able to call create', function (done) {
it('should be able to call create', function(done) {
TestModel.create({
foo: 'bar'
}, function(err, inst) {
if(err) return done(err);
if (err) return done(err);
assert(inst.id);
done();
});
});
it('should be able to call save', function (done) {
it('should be able to call save', function(done) {
var m = new TestModel({
foo: 'bar'
});
m.save(function(err, data) {
if(err) return done(err);
if (err) return done(err);
assert(data.foo === 'bar');
done();
});

View File

@ -19,14 +19,14 @@ describe('Replication', function() {
LocalTestModel.attachTo(memory);
});
it('should replicate local data to the remote', function (done) {
it('should replicate local data to the remote', function(done) {
var RANDOM = Math.random();
LocalTestModel.create({
n: RANDOM
}, function(err, created) {
LocalTestModel.replicate(0, TestModel, function() {
if(err) return done(err);
if (err) return done(err);
TestModel.findOne({n: RANDOM}, function(err, found) {
assert.equal(created.id, found.id);
done();

View File

@ -3,30 +3,29 @@ var MyEmail;
var assert = require('assert');
var MailConnector = require('../lib/connectors/mail');
describe('Email connector', function () {
it('should set up SMTP', function () {
describe('Email connector', function() {
it('should set up SMTP', function() {
var connector = new MailConnector({transports: [
{type: 'smtp', service: 'gmail'}
]});
assert(connector.transportForName('smtp'));
});
it('should set up DIRECT', function () {
it('should set up DIRECT', function() {
var connector = new MailConnector({transports: [
{type: 'direct', name: 'localhost'}
]});
assert(connector.transportForName('direct'));
});
it('should set up STUB', function () {
it('should set up STUB', function() {
var connector = new MailConnector({transports: [
{type: 'stub', service: 'gmail'}
]});
assert(connector.transportForName('stub'));
});
it('should set up a single transport for SMTP' , function () {
it('should set up a single transport for SMTP' , function() {
var connector = new MailConnector({transport:
{type: 'smtp', service: 'gmail'}
});
@ -34,22 +33,21 @@ describe('Email connector', function () {
assert(connector.transportForName('smtp'));
});
});
describe('Email and SMTP', function () {
describe('Email and SMTP', function() {
beforeEach(function() {
MyEmail = loopback.Email.extend('my-email');
loopback.autoAttach();
});
it('should have a send method', function () {
it('should have a send method', function() {
assert(typeof MyEmail.send === 'function');
assert(typeof MyEmail.prototype.send === 'function');
});
describe('MyEmail', function () {
it('MyEmail.send(options, callback)', function (done) {
describe('MyEmail', function() {
it('MyEmail.send(options, callback)', function(done) {
var options = {
to: 'to@to.com',
from: 'from@from.com',
@ -67,7 +65,7 @@ describe('Email and SMTP', function () {
});
});
it('myEmail.send(callback)', function (done) {
it('myEmail.send(callback)', function(done) {
var message = new MyEmail({
to: 'to@to.com',
from: 'from@from.com',
@ -76,7 +74,7 @@ describe('Email and SMTP', function () {
html: '<h1>html</h1>'
});
message.send(function (err, mail) {
message.send(function(err, mail) {
assert(mail.response);
assert(mail.envelope);
assert(mail.messageId);
@ -85,5 +83,3 @@ describe('Email and SMTP', function () {
});
});
});

View File

@ -1,6 +1,6 @@
describe('GeoPoint', function() {
describe('geoPoint.distanceTo(geoPoint, options)', function() {
it("Get the distance to another `GeoPoint`", function() {
it('Get the distance to another `GeoPoint`', function() {
var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
var distance = here.distanceTo(there, {type: 'meters'});
@ -10,16 +10,16 @@ describe('GeoPoint', function() {
});
describe('GeoPoint.distanceBetween(a, b, options)', function() {
it("Get the distance between two points", function() {
it('Get the distance between two points', function() {
var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
var distance = GeoPoint.distanceBetween(here, there, {type: 'feet'});
assert.equal(Math.floor(distance), 2568169);
});
});
describe('GeoPoint()', function(){
describe('GeoPoint()', function() {
it('Create from string', function() {
var point = new GeoPoint('1.234,5.678');
assert.equal(point.lng, 1.234);
@ -45,11 +45,11 @@ describe('GeoPoint', function() {
var Model = loopback.createModel('geo-model', {
geo: {type: 'GeoPoint'}
});
var m = new Model({
geo: '1.222,3.444'
});
assert(m.geo instanceof GeoPoint);
assert.equal(m.geo.lng, 1.222);
assert.equal(m.geo.lat, 3.444);

View File

@ -1,22 +1,22 @@
var loopback = require('../');
describe('hidden properties', function () {
beforeEach(function (done) {
describe('hidden properties', function() {
beforeEach(function(done) {
var app = this.app = loopback();
var Product = this.Product = loopback.PersistedModel.extend('product',
{},
{hidden: ['secret']}
);
Product.attachTo(loopback.memory());
var Category = this.Category = loopback.PersistedModel.extend('category');
Category.attachTo(loopback.memory());
Category.hasMany(Product);
app.model(Product);
app.model(Category);
app.use(loopback.rest());
Category.create({
name: 'my category'
}, function(err, category) {
@ -32,29 +32,29 @@ describe('hidden properties', function () {
this.Category.destroyAll(function() {
Product.destroyAll(done);
});
})
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);
var product = res.body[0];
assert.equal(product.secret, undefined);
done();
});
});
it('should hide a property of nested models', function (done) {
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);
var product = res.body[0];
assert.equal(product.secret, undefined);
done();
});
});
it('should hide a property of nested models', function(done) {
var app = this.app;
request(app)
.get('/categories?filter[include]=products')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
var category = res.body[0];
var product = category.products[0];
assert.equal(product.secret, undefined);

View File

@ -36,7 +36,7 @@ describe('loopback', function() {
});
describe('data source created by loopback', function() {
it('should create model extending Model by default', function () {
it('should create model extending Model by default', function() {
var dataSource = loopback.createDataSource({
connector: loopback.Memory
});
@ -52,8 +52,8 @@ describe('loopback', function() {
});
});
describe('loopback.autoAttach', function () {
it('doesn\'t overwrite model with datasource configured', function () {
describe('loopback.autoAttach', function() {
it('doesn\'t overwrite model with datasource configured', function() {
var ds1 = loopback.createDataSource('db1', {
connector: loopback.Memory
});
@ -79,12 +79,12 @@ describe('loopback', function() {
});
describe('loopback.remoteMethod(Model, fn, [options]);', function() {
it("Setup a remote method.", function() {
it('Setup a remote method.', function() {
var Product = loopback.createModel('product', {price: Number});
Product.stats = function(fn) {
// ...
}
};
loopback.remoteMethod(
Product.stats,
@ -102,9 +102,9 @@ describe('loopback', function() {
});
});
describe('loopback.createModel(name, properties, options)', function () {
describe('options.base', function () {
it('should extend from options.base', function () {
describe('loopback.createModel(name, properties, options)', function() {
describe('options.base', function() {
it('should extend from options.base', function() {
var MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat'
@ -122,8 +122,8 @@ describe('loopback', function() {
});
});
describe('loopback.getModel and getModelByType', function () {
it('should be able to get model by name', function () {
describe('loopback.getModel and getModelByType', function() {
it('should be able to get model by name', function() {
var MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat'
@ -139,7 +139,7 @@ describe('loopback', function() {
assert(loopback.getModel('MyCustomModel') === MyCustomModel);
assert(loopback.findModel('Invalid') === undefined);
});
it('should be able to get model by type', function () {
it('should be able to get model by type', function() {
var MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat'

View File

@ -1,4 +1,4 @@
describe('Memory Connector', function(){
describe('Memory Connector', function() {
it('Create a model using the memory connector', function(done) {
// use the built in memory function
// to create a memory data source
@ -6,30 +6,30 @@ describe('Memory Connector', function(){
// or create it using the standard
// data source creation api
var memory = loopback.createDataSource({
memory = loopback.createDataSource({
connector: loopback.Memory
});
// create a model using the
// memory data source
var properties = {
name: String,
price: Number
};
var Product = memory.createModel('product', properties);
Product.create([
{name: 'apple', price: 0.79},
{name: 'pear', price: 1.29},
{name: 'orange', price: 0.59},
], count);
function count() {
Product.count(function (err, count) {
Product.count(function(err, count) {
assert.equal(count, 3);
done();
});
}
});
});
});

View File

@ -2,13 +2,13 @@ var loopback = require(('../'));
var assert = require('assert');
var Application = loopback.Application;
describe('Application', function () {
describe('Application', function() {
var registeredApp = null;
it('Create a new application', function (done) {
it('Create a new application', function(done) {
Application.create({owner: 'rfeng',
name: 'MyApp1',
description: 'My first mobile application'}, function (err, result) {
description: 'My first mobile application'}, function(err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp1');
@ -25,7 +25,7 @@ describe('Application', function () {
});
});
it('Create a new application with push settings', function (done) {
it('Create a new application with push settings', function(done) {
Application.create({owner: 'rfeng',
name: 'MyAppWithPush',
description: 'My push mobile application',
@ -49,7 +49,7 @@ describe('Application', function () {
serverApiKey: 'serverKey'
}
}},
function (err, result) {
function(err, result) {
var app = result;
assert.deepEqual(app.pushSettings.toObject(), {
apns: {
@ -75,9 +75,9 @@ describe('Application', function () {
});
});
beforeEach(function (done) {
beforeEach(function(done) {
Application.register('rfeng', 'MyApp2',
{description: 'My second mobile application'}, function (err, result) {
{description: 'My second mobile application'}, function(err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2');
@ -94,8 +94,8 @@ describe('Application', function () {
});
});
it('Reset keys', function (done) {
Application.resetKeys(registeredApp.id, function (err, result) {
it('Reset keys', function(done) {
Application.resetKeys(registeredApp.id, function(err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2');
@ -119,67 +119,67 @@ describe('Application', function () {
});
});
it('Authenticate with application id & clientKey', function (done) {
it('Authenticate with application id & clientKey', function(done) {
Application.authenticate(registeredApp.id, registeredApp.clientKey,
function (err, result) {
function(err, result) {
assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'clientKey');
done(err, result);
});
});
it('Authenticate with application id & javaScriptKey', function (done) {
it('Authenticate with application id & javaScriptKey', function(done) {
Application.authenticate(registeredApp.id, registeredApp.javaScriptKey,
function (err, result) {
function(err, result) {
assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'javaScriptKey');
done(err, result);
});
});
it('Authenticate with application id & restApiKey', function (done) {
it('Authenticate with application id & restApiKey', function(done) {
Application.authenticate(registeredApp.id, registeredApp.restApiKey,
function (err, result) {
function(err, result) {
assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'restApiKey');
done(err, result);
});
});
it('Authenticate with application id & masterKey', function (done) {
it('Authenticate with application id & masterKey', function(done) {
Application.authenticate(registeredApp.id, registeredApp.masterKey,
function (err, result) {
function(err, result) {
assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'masterKey');
done(err, result);
});
});
it('Authenticate with application id & windowsKey', function (done) {
it('Authenticate with application id & windowsKey', function(done) {
Application.authenticate(registeredApp.id, registeredApp.windowsKey,
function (err, result) {
function(err, result) {
assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'windowsKey');
done(err, result);
});
});
it('Fail to authenticate with application id & invalid key', function (done) {
it('Fail to authenticate with application id & invalid key', function(done) {
Application.authenticate(registeredApp.id, 'invalid-key',
function (err, result) {
function(err, result) {
assert(!result);
done(err, result);
});
});
});
describe('Application subclass', function () {
it('should use subclass model name', function (done) {
describe('Application subclass', function() {
it('should use subclass model name', function(done) {
var MyApp = Application.extend('MyApp');
var ds = loopback.createDataSource({connector: loopback.Memory});
MyApp.attachTo(ds);
MyApp.register('rfeng', 'MyApp123',
{description: 'My 123 mobile application'}, function (err, result) {
{description: 'My 123 mobile application'}, function(err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp123');
@ -192,12 +192,12 @@ describe('Application subclass', function () {
assert(app.created);
assert(app.modified);
// Remove all instances from Application model to avoid left-over data
Application.destroyAll(function () {
MyApp.findById(app.id, function (err, myApp) {
Application.destroyAll(function() {
MyApp.findById(app.id, function(err, myApp) {
assert(!err);
assert(myApp);
Application.findById(app.id, function (err, myApp) {
Application.findById(app.id, function(err, myApp) {
assert(!err);
assert(myApp === null);
done(err, myApp);
@ -207,4 +207,3 @@ describe('Application subclass', function () {
});
});
});

View File

@ -15,7 +15,7 @@ describe('Model / PersistedModel', function() {
});
describe('Model.validatesUniquenessOf(property, options)', function() {
it("Ensure the value for `property` is unique", function(done) {
it('Ensure the value for `property` is unique', function(done) {
var User = PersistedModel.extend('user', {
'first': String,
'last': String,
@ -31,17 +31,17 @@ describe('Model / PersistedModel', function() {
});
User.attachTo(dataSource);
User.validatesUniquenessOf('email', {message: 'email is not unique'});
var joe = new User({email: 'joe@joe.com'});
var joe2 = new User({email: 'joe@joe.com'});
joe.save(function () {
joe2.save(function (err) {
joe.save(function() {
joe2.save(function(err) {
assert(err, 'should get a validation error');
assert(joe2.errors.email, 'model should have email error');
done();
});
});
@ -49,14 +49,14 @@ describe('Model / PersistedModel', function() {
});
describe('Model.attachTo(dataSource)', function() {
it("Attach a model to a [DataSource](#data-source)", function() {
it('Attach a model to a [DataSource](#data-source)', function() {
var MyModel = loopback.createModel('my-model', {name: String});
var dataSource = loopback.createDataSource({
connector: loopback.Memory
});
MyModel.attachTo(dataSource);
MyModel.find(function(err, results) {
assert(results.length === 0, 'should have data access methods after attaching to a data source');
});
@ -64,13 +64,13 @@ describe('Model / PersistedModel', function() {
});
});
describe.onServer('Remote Methods', function(){
describe.onServer('Remote Methods', function() {
var User;
var dataSource;
var app;
beforeEach(function () {
beforeEach(function() {
User = PersistedModel.extend('user', {
'first': String,
'last': String,
@ -89,13 +89,13 @@ describe.onServer('Remote Methods', function(){
User.attachTo(dataSource);
User.login = function (username, password, fn) {
if(username === 'foo' && password === 'bar') {
User.login = function(username, password, fn) {
if (username === 'foo' && password === 'bar') {
fn(null, 123);
} else {
throw new Error('bad username and password!');
}
}
};
loopback.remoteMethod(
User.login,
@ -113,19 +113,19 @@ describe.onServer('Remote Methods', function(){
app.use(loopback.rest());
app.model(User);
});
describe('Model.destroyAll(callback)', function() {
it("Delete all Model instances from data source", function(done) {
it('Delete all Model instances from data source', function(done) {
(new TaskEmitter())
.task(User, 'create', {first: 'jill'})
.task(User, 'create', {first: 'bob'})
.task(User, 'create', {first: 'jan'})
.task(User, 'create', {first: 'sam'})
.task(User, 'create', {first: 'suzy'})
.on('done', function () {
User.count(function (err, count) {
User.destroyAll(function () {
User.count(function (err, count) {
.on('done', function() {
User.count(function(err, count) {
User.destroyAll(function() {
User.count(function(err, count) {
assert.equal(count, 0);
done();
});
@ -135,14 +135,14 @@ describe.onServer('Remote Methods', function(){
});
});
describe('Example Remote Method', function () {
describe('Example Remote Method', function() {
it('Call the method using HTTP / REST', function(done) {
request(app)
.get('/users/sign-in?username=foo&password=bar')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
assert.equal(res.body, 123);
done();
});
@ -156,15 +156,15 @@ describe.onServer('Remote Methods', function(){
});
});
describe('Model.beforeRemote(name, fn)', function(){
describe('Model.beforeRemote(name, fn)', function() {
it('Run a function before a remote method is called by a client', function(done) {
var hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
next();
});
// invoke save
request(app)
.post('/users')
@ -172,18 +172,18 @@ describe.onServer('Remote Methods', function(){
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if(err) return done(err);
if (err) return done(err);
assert(hookCalled, 'hook wasnt called');
done();
});
});
});
describe('Model.afterRemote(name, fn)', function(){
describe('Model.afterRemote(name, fn)', function() {
it('Run a function after a remote method is called by a client', function(done) {
var beforeCalled = false;
var afterCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
assert(!afterCalled);
beforeCalled = true;
@ -194,7 +194,7 @@ describe.onServer('Remote Methods', function(){
afterCalled = true;
next();
});
// invoke save
request(app)
.post('/users')
@ -202,7 +202,7 @@ describe.onServer('Remote Methods', function(){
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if(err) return done(err);
if (err) return done(err);
assert(beforeCalled, 'before hook was not called');
assert(afterCalled, 'after hook was not called');
done();
@ -210,11 +210,11 @@ describe.onServer('Remote Methods', function(){
});
});
describe('Remote Method invoking context', function () {
describe('Remote Method invoking context', function() {
describe('ctx.req', function() {
it("The express ServerRequest object", function(done) {
it('The express ServerRequest object', function(done) {
var hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
assert(ctx.req);
@ -225,7 +225,7 @@ describe.onServer('Remote Methods', function(){
assert(ctx.res.end);
next();
});
// invoke save
request(app)
.post('/users')
@ -233,7 +233,7 @@ describe.onServer('Remote Methods', function(){
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if(err) return done(err);
if (err) return done(err);
assert(hookCalled);
done();
});
@ -241,9 +241,9 @@ describe.onServer('Remote Methods', function(){
});
describe('ctx.res', function() {
it("The express ServerResponse object", function(done) {
it('The express ServerResponse object', function(done) {
var hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
assert(ctx.req);
@ -254,7 +254,7 @@ describe.onServer('Remote Methods', function(){
assert(ctx.res.end);
next();
});
// invoke save
request(app)
.post('/users')
@ -262,28 +262,28 @@ describe.onServer('Remote Methods', function(){
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if(err) return done(err);
if (err) return done(err);
assert(hookCalled);
done();
});
});
});
})
});
describe('Model.hasMany(Model)', function() {
it("Define a one to many relationship", function(done) {
it('Define a one to many relationship', function(done) {
var Book = dataSource.createModel('book', {title: String, author: String});
var Chapter = dataSource.createModel('chapter', {title: String});
// by referencing model
Book.hasMany(Chapter);
Book.create({title: 'Into the Wild', author: 'Jon Krakauer'}, function(err, book) {
// using 'chapters' scope for build:
var c = book.chapters.build({title: 'Chapter 1'});
book.chapters.create({title: 'Chapter 2'}, function () {
c.save(function () {
Chapter.count({bookId: book.id}, function (err, count) {
book.chapters.create({title: 'Chapter 2'}, function() {
c.save(function() {
Chapter.count({bookId: book.id}, function(err, count) {
assert.equal(count, 2);
book.chapters({where: {title: 'Chapter 1'}}, function(err, chapters) {
assert.equal(chapters.length, 1);
@ -296,8 +296,8 @@ describe.onServer('Remote Methods', function(){
});
});
});
describe('Model.properties', function(){
describe('Model.properties', function() {
it('Normalized properties passed in originally by loopback.createModel()', function() {
var props = {
s: String,
@ -306,57 +306,56 @@ describe.onServer('Remote Methods', function(){
d: Date,
g: loopback.GeoPoint
};
var MyModel = loopback.createModel('foo', props);
Object.keys(MyModel.definition.properties).forEach(function (key) {
Object.keys(MyModel.definition.properties).forEach(function(key) {
var p = MyModel.definition.properties[key];
var o = MyModel.definition.properties[key];
assert(p);
assert(o);
assert(typeof p.type === 'function');
if(typeof o === 'function') {
if (typeof o === 'function') {
// the normalized property
// should match the given property
assert(
p.type.name === o.name
||
p.type.name === o.name ||
p.type.name === o
)
);
}
});
});
});
describe('Model.extend()', function(){
describe('Model.extend()', function() {
it('Create a new model by extending an existing model', function() {
var User = loopback.PersistedModel.extend('test-user', {
email: String
});
User.foo = function () {
User.foo = function() {
return 'bar';
}
User.prototype.bar = function () {
};
User.prototype.bar = function() {
return 'foo';
}
};
var MyUser = User.extend('my-user', {
a: String,
b: String
});
assert.equal(MyUser.prototype.bar, User.prototype.bar);
assert.equal(MyUser.foo, User.foo);
var user = new MyUser({
email: 'foo@bar.com',
a: 'foo',
b: 'bar'
});
assert.equal(user.email, 'foo@bar.com');
assert.equal(user.a, 'foo');
assert.equal(user.b, 'bar');
@ -379,7 +378,6 @@ describe.onServer('Remote Methods', function(){
user1Triggered = true;
});
var user2Triggered = false;
User2.once('x', function(event) {
user2Triggered = true;
@ -396,7 +394,7 @@ describe.onServer('Remote Methods', function(){
});
describe('Model.checkAccessTypeForMethod(remoteMethod)', function () {
describe('Model.checkAccessTypeForMethod(remoteMethod)', function() {
shouldReturn('create', ACL.WRITE);
shouldReturn('updateOrCreate', ACL.WRITE);
shouldReturn('upsert', ACL.WRITE);
@ -411,7 +409,7 @@ describe.onServer('Remote Methods', function(){
shouldReturn('unkown-model-method', ACL.EXECUTE);
function shouldReturn(methodName, expectedAccessType) {
describe(methodName, function () {
describe(methodName, function() {
it('should return ' + expectedAccessType, function() {
var remoteMethod = {name: methodName};
assert.equal(
@ -424,7 +422,7 @@ describe.onServer('Remote Methods', function(){
});
describe('Model.getChangeModel()', function() {
it('Get the Change Model', function () {
it('Get the Change Model', function() {
var UserChange = User.getChangeModel();
var change = new UserChange();
assert(change instanceof Change);
@ -432,7 +430,7 @@ describe.onServer('Remote Methods', function(){
});
describe('Model.getSourceId(callback)', function() {
it('Get the Source Id', function (done) {
it('Get the Source Id', function(done) {
User.getSourceId(function(err, id) {
assert.equal('memory-user', id);
done();
@ -441,7 +439,7 @@ describe.onServer('Remote Methods', function(){
});
describe('Model.checkpoint(callback)', function() {
it('Create a checkpoint', function (done) {
it('Create a checkpoint', function(done) {
var Checkpoint = User.getChangeModel().getCheckpointModel();
var tasks = [
getCurrentCheckpoint,
@ -451,7 +449,7 @@ describe.onServer('Remote Methods', function(){
var current;
async.series(tasks, function(err) {
if(err) return done(err);
if (err) return done(err);
assert.equal(result, current + 1);
done();

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ describe('RemoteConnector', function() {
});
});
it('should support the save method', function (done) {
it('should support the save method', function(done) {
var calledServerCreate = false;
var RemoteModel = loopback.PersistedModel.extend('TestModel');
RemoteModel.attachTo(this.remote);
@ -57,7 +57,7 @@ describe('RemoteConnector', function() {
calledServerCreate = true;
data.id = 1;
cb(null, data);
}
};
ServerModel.setupRemoting();

View File

@ -13,7 +13,7 @@ describe('remoting coercion', function() {
assert(inst instanceof TestModel);
assert(inst.foo === 'bar');
cb();
}
};
TestModel.remoteMethod('test', {
accepts: {arg: 'inst', type: 'TestModel', http: {source: 'body'}},
http: {path: '/test', verb: 'post'}
@ -26,9 +26,9 @@ describe('remoting coercion', function() {
foo: 'bar'
})
.end(function(err) {
if(err) return done(err);
if (err) return done(err);
assert(called);
done();
});
});
})
});

View File

@ -5,38 +5,38 @@ var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-integration-app');
var app = require(path.join(SIMPLE_APP, 'app.js'));
var assert = require('assert');
describe('remoting - integration', function () {
describe('remoting - integration', function() {
lt.beforeEach.withApp(app);
lt.beforeEach.givenModel('store');
afterEach(function (done) {
afterEach(function(done) {
this.app.models.store.destroyAll(done);
});
describe('app.remotes.options', function () {
it("should load remoting options", function () {
describe('app.remotes.options', function() {
it('should load remoting options', function() {
var remotes = app.remotes();
assert.deepEqual(remotes.options, {"json": {"limit": "1kb", "strict": false},
"urlencoded": {"limit": "8kb", "extended": true}});
assert.deepEqual(remotes.options, {'json': {'limit': '1kb', 'strict': false},
'urlencoded': {'limit': '8kb', 'extended': true}});
});
it("rest handler", function () {
it('rest handler', function() {
var handler = app.handler('rest');
assert(handler);
});
it('should accept request that has entity below 1kb', function (done) {
it('should accept request that has entity below 1kb', function(done) {
// Build an object that is smaller than 1kb
var name = "";
var name = '';
for (var i = 0; i < 256; i++) {
name += "11";
name += '11';
}
this.http = this.post('/api/stores');
this.http.send({
"name": name
'name': name
});
this.http.end(function (err) {
this.http.end(function(err) {
if (err) return done(err);
this.req = this.http.req;
this.res = this.http.res;
@ -45,17 +45,17 @@ describe('remoting - integration', function () {
}.bind(this));
});
it('should reject request that has entity beyond 1kb', function (done) {
it('should reject request that has entity beyond 1kb', function(done) {
// Build an object that is larger than 1kb
var name = "";
var name = '';
for (var i = 0; i < 2048; i++) {
name += "11111111111";
name += '11111111111';
}
this.http = this.post('/api/stores');
this.http.send({
"name": name
'name': name
});
this.http.end(function (err) {
this.http.end(function(err) {
if (err) return done(err);
this.req = this.http.req;
this.res = this.http.res;
@ -81,7 +81,7 @@ describe('remoting - integration', function () {
m.name,
'(',
m.accepts.map(function(a) {
return a.arg + ':' + a.type
return a.arg + ':' + a.type;
}).join(','),
')',
formatReturns(m),
@ -148,7 +148,6 @@ describe('remoting - integration', function () {
expect(methods).to.include.members(expectedMethods);
});
it('should have correct signatures for belongsTo methods',
function() {
@ -168,7 +167,6 @@ describe('remoting - integration', function () {
expect(methods).to.include.members(expectedMethods);
});
it('should have correct signatures for hasMany methods',
function() {

View File

@ -15,7 +15,7 @@ describe('Replication / Change APIs', function() {
trackChanges: true
});
SourceModel.attachTo(dataSource);
var TargetModel = this.TargetModel = PersistedModel.extend('TargetModel', {}, {
trackChanges: true
});
@ -23,11 +23,11 @@ describe('Replication / Change APIs', function() {
this.createInitalData = function(cb) {
SourceModel.create({name: 'foo'}, function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
test.model = inst;
// give loopback a chance to register the change
// TODO(ritch) get rid of this...
// TODO(ritch) get rid of this...
setTimeout(function() {
SourceModel.replicate(TargetModel, cb);
}, 100);
@ -36,10 +36,10 @@ describe('Replication / Change APIs', function() {
});
describe('Model.changes(since, filter, callback)', function() {
it('Get changes since the given checkpoint', function (done) {
it('Get changes since the given checkpoint', function(done) {
var test = this;
this.SourceModel.create({name: 'foo'}, function(err) {
if(err) return done(err);
if (err) return done(err);
setTimeout(function() {
test.SourceModel.changes(test.startingCheckpoint, {}, function(err, changes) {
assert.equal(changes.length, 1);
@ -51,7 +51,7 @@ describe('Replication / Change APIs', function() {
});
describe('Model.replicate(since, targetModel, options, callback)', function() {
it('Replicate data using the target model', function (done) {
it('Replicate data using the target model', function(done) {
var test = this;
var options = {};
var sourceData;
@ -62,26 +62,26 @@ describe('Replication / Change APIs', function() {
});
function replicate() {
test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel,
test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel,
options, function(err, conflicts) {
assert(conflicts.length === 0);
async.parallel([
function(cb) {
test.SourceModel.find(function(err, result) {
if(err) return cb(err);
if (err) return cb(err);
sourceData = result;
cb();
});
},
function(cb) {
test.TargetModel.find(function(err, result) {
if(err) return cb(err);
if (err) return cb(err);
targetData = result;
cb();
});
}
], function(err) {
if(err) return done(err);
if (err) return done(err);
assert.deepEqual(sourceData, targetData);
done();
@ -103,22 +103,22 @@ describe('Replication / Change APIs', function() {
async.parallel([
function(cb) {
SourceModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
inst.name = 'source update';
inst.save(cb);
});
},
function(cb) {
TargetModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
inst.name = 'target update';
inst.save(cb);
});
}
], function(err) {
if(err) return done(err);
if (err) return done(err);
SourceModel.replicate(TargetModel, function(err, conflicts) {
if(err) return done(err);
if (err) return done(err);
test.conflicts = conflicts;
test.conflict = conflicts[0];
done();
@ -175,22 +175,22 @@ describe('Replication / Change APIs', function() {
async.parallel([
function(cb) {
SourceModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
test.model = inst;
inst.remove(cb);
});
},
function(cb) {
TargetModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
inst.name = 'target update';
inst.save(cb);
});
}
], function(err) {
if(err) return done(err);
if (err) return done(err);
SourceModel.replicate(TargetModel, function(err, conflicts) {
if(err) return done(err);
if (err) return done(err);
test.conflicts = conflicts;
test.conflict = conflicts[0];
done();
@ -244,7 +244,7 @@ describe('Replication / Change APIs', function() {
async.parallel([
function(cb) {
SourceModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
test.model = inst;
inst.name = 'source update';
inst.save(cb);
@ -252,14 +252,14 @@ describe('Replication / Change APIs', function() {
},
function(cb) {
TargetModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
inst.remove(cb);
});
}
], function(err) {
if(err) return done(err);
if (err) return done(err);
SourceModel.replicate(TargetModel, function(err, conflicts) {
if(err) return done(err);
if (err) return done(err);
test.conflicts = conflicts;
test.conflict = conflicts[0];
done();
@ -313,21 +313,21 @@ describe('Replication / Change APIs', function() {
async.parallel([
function(cb) {
SourceModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
test.model = inst;
inst.remove(cb);
});
},
function(cb) {
TargetModel.findOne(function(err, inst) {
if(err) return cb(err);
if (err) return cb(err);
inst.remove(cb);
});
}
], function(err) {
if(err) return done(err);
if (err) return done(err);
SourceModel.replicate(TargetModel, function(err, conflicts) {
if(err) return done(err);
if (err) return done(err);
test.conflicts = conflicts;
test.conflict = conflicts[0];
done();

View File

@ -86,7 +86,7 @@ describe('loopback.rest', function() {
app.use(loopback.rest());
request(app).get('/mymodels')
.set('Accept', 'text/html,application/xml;q=0.9,*/*;q=0.8')
.set('Accept', 'text/html,application/xml;q= 0.9,*/*;q= 0.8')
.expect('Content-Type', 'application/json; charset=utf-8')
.expect(200, done);
});
@ -103,7 +103,7 @@ describe('loopback.rest', function() {
.set('Authorization', token.id)
.expect(200)
.end(done);
});
}, done);
});
it('does not include loopback.token when auth not enabled', function(done) {
@ -127,7 +127,7 @@ describe('loopback.rest', function() {
expect(res.body.id).to.equal(null);
done();
});
});
}, done);
});
describe('context propagation', function() {
@ -255,7 +255,7 @@ describe('loopback.rest', function() {
dataSource: 'db'
});
}
function givenLoggedInUser(cb) {
function givenLoggedInUser(cb, done) {
var credentials = { email: 'user@example.com', password: 'pwd' };
var User = app.models.user;
User.create(credentials,

View File

@ -10,7 +10,7 @@ function checkResult(err, result) {
assert(!err);
}
describe('role model', function () {
describe('role model', function() {
var ds;
beforeEach(function() {
@ -22,22 +22,22 @@ describe('role model', function () {
RoleMapping.attachTo(ds);
});
it("should define role/role relations", function () {
Role.create({name: 'user'}, function (err, userRole) {
Role.create({name: 'admin'}, function (err, adminRole) {
userRole.principals.create({principalType: RoleMapping.ROLE, principalId: adminRole.id}, function (err, mapping) {
Role.find(function (err, roles) {
it('should define role/role relations', function() {
Role.create({name: 'user'}, function(err, userRole) {
Role.create({name: 'admin'}, function(err, adminRole) {
userRole.principals.create({principalType: RoleMapping.ROLE, principalId: adminRole.id}, function(err, mapping) {
Role.find(function(err, roles) {
assert.equal(roles.length, 2);
});
RoleMapping.find(function (err, mappings) {
RoleMapping.find(function(err, mappings) {
assert.equal(mappings.length, 1);
assert.equal(mappings[0].principalType, RoleMapping.ROLE);
assert.equal(mappings[0].principalId, adminRole.id);
});
userRole.principals(function (err, principals) {
userRole.principals(function(err, principals) {
assert.equal(principals.length, 1);
});
userRole.roles(function (err, roles) {
userRole.roles(function(err, roles) {
assert.equal(roles.length, 1);
});
});
@ -46,25 +46,25 @@ describe('role model', function () {
});
it("should define role/user relations", function () {
it('should define role/user relations', function() {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
// console.log('User: ', user.id);
Role.create({name: 'userRole'}, function (err, role) {
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
Role.find(function (err, roles) {
Role.create({name: 'userRole'}, function(err, role) {
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
Role.find(function(err, roles) {
assert(!err);
assert.equal(roles.length, 1);
assert.equal(roles[0].name, 'userRole');
});
role.principals(function (err, principals) {
role.principals(function(err, principals) {
assert(!err);
// console.log(principals);
assert.equal(principals.length, 1);
assert.equal(principals[0].principalType, RoleMapping.USER);
assert.equal(principals[0].principalId, user.id);
});
role.users(function (err, users) {
role.users(function(err, users) {
assert(!err);
assert.equal(users.length, 1);
assert.equal(users[0].principalType, RoleMapping.USER);
@ -76,29 +76,28 @@ describe('role model', function () {
});
it('should automatically generate role id', function() {
it("should automatically generate role id", function () {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
// console.log('User: ', user.id);
Role.create({name: 'userRole'}, function (err, role) {
Role.create({name: 'userRole'}, function(err, role) {
assert(role.id);
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
assert(p.id);
assert.equal(p.roleId, role.id);
Role.find(function (err, roles) {
Role.find(function(err, roles) {
assert(!err);
assert.equal(roles.length, 1);
assert.equal(roles[0].name, 'userRole');
});
role.principals(function (err, principals) {
role.principals(function(err, principals) {
assert(!err);
// console.log(principals);
assert.equal(principals.length, 1);
assert.equal(principals[0].principalType, RoleMapping.USER);
assert.equal(principals[0].principalId, user.id);
});
role.users(function (err, users) {
role.users(function(err, users) {
assert(!err);
assert.equal(users.length, 1);
assert.equal(users[0].principalType, RoleMapping.USER);
@ -110,45 +109,45 @@ describe('role model', function () {
});
it("should support getRoles() and isInRole()", function () {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
it('should support getRoles() and isInRole()', function() {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
// console.log('User: ', user.id);
Role.create({name: 'userRole'}, function (err, role) {
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
Role.create({name: 'userRole'}, function(err, role) {
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
// Role.find(console.log);
// role.principals(console.log);
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: user.id}, function (err, exists) {
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: user.id}, function(err, exists) {
assert(!err && exists === true);
});
Role.isInRole('userRole', {principalType: RoleMapping.APP, principalId: user.id}, function (err, exists) {
Role.isInRole('userRole', {principalType: RoleMapping.APP, principalId: user.id}, function(err, exists) {
assert(!err && exists === false);
});
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: 100}, function (err, exists) {
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: 100}, function(err, exists) {
assert(!err && exists === false);
});
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function (err, roles) {
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function(err, roles) {
assert.equal(roles.length, 3); // everyone, authenticated, userRole
assert(roles.indexOf(role.id) >=0);
assert(roles.indexOf(Role.EVERYONE) >=0);
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
assert(roles.indexOf(role.id) >= 0);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
});
Role.getRoles({principalType: RoleMapping.APP, principalId: user.id}, function (err, roles) {
Role.getRoles({principalType: RoleMapping.APP, principalId: user.id}, function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >=0);
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
});
Role.getRoles({principalType: RoleMapping.USER, principalId: 100}, function (err, roles) {
Role.getRoles({principalType: RoleMapping.USER, principalId: 100}, function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >=0);
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
});
Role.getRoles({principalType: RoleMapping.USER, principalId: null}, function (err, roles) {
Role.getRoles({principalType: RoleMapping.USER, principalId: null}, function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >=0);
assert(roles.indexOf(Role.UNAUTHENTICATED) >=0);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.UNAUTHENTICATED) >= 0);
});
});
});
@ -156,7 +155,7 @@ describe('role model', function () {
});
it("should support owner role resolver", function () {
it('should support owner role resolver', function() {
var Album = ds.createModel('Album', {
name: String,
@ -171,36 +170,36 @@ describe('role model', function () {
}
});
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function (err, yes) {
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
assert(!err && yes);
});
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: null}, function (err, yes) {
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: null}, function(err, yes) {
assert(!err && !yes);
});
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function (err, yes) {
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
assert(!err && !yes);
});
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: null}, function (err, yes) {
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: null}, function(err, yes) {
assert(!err && yes);
});
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: user.id}, function (err, yes) {
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
assert(!err && yes);
});
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: null}, function (err, yes) {
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: null}, function(err, yes) {
assert(!err && yes);
});
// console.log('User: ', user.id);
Album.create({name: 'Album 1', userId: user.id}, function (err, album1) {
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id}, function (err, yes) {
Album.create({name: 'Album 1', userId: user.id}, function(err, album1) {
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id}, function(err, yes) {
assert(!err && yes);
});
Album.create({name: 'Album 2'}, function (err, album2) {
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id}, function (err, yes) {
Album.create({name: 'Album 2'}, function(err, album2) {
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id}, function(err, yes) {
assert(!err && !yes);
});
});
@ -210,7 +209,3 @@ describe('role model', function () {
});
});

View File

@ -1,7 +1,7 @@
/**
* loopback test setup and support.
*/
assert = require('assert');
expect = require('chai').expect;
loopback = require('../');
@ -16,7 +16,7 @@ var RemoteObjects = require('strong-remoting');
// for tests using the built-in User model
loopback.User.settings.saltWorkFactor = 4;
beforeEach(function () {
beforeEach(function() {
this.app = app = loopback();
// setup default data sources
@ -35,7 +35,7 @@ beforeEach(function () {
loopback.autoAttach();
});
assertValidDataSource = function (dataSource) {
assertValidDataSource = function(dataSource) {
// has methods
assert.isFunc(dataSource, 'createModel');
assert.isFunc(dataSource, 'discoverModelDefinitions');
@ -44,9 +44,9 @@ assertValidDataSource = function (dataSource) {
assert.isFunc(dataSource, 'disableRemote');
assert.isFunc(dataSource, 'defineOperation');
assert.isFunc(dataSource, 'operations');
}
};
assert.isFunc = function (obj, name) {
assert.isFunc = function(obj, name) {
assert(obj, 'cannot assert function ' + name + ' on object that doesnt exist');
assert(typeof obj[name] === 'function', name + ' is not a function');
}
};

View File

@ -6,7 +6,7 @@ var userMemory = loopback.createDataSource({
connector: 'memory'
});
describe('User', function(){
describe('User', function() {
var validCredentials = {email: 'foo@bar.com', password: 'bar'};
var validCredentialsEmailVerified = {email: 'foo1@bar.com', password: 'bar1', emailVerified: true};
var validCredentialsEmailVerifiedOverREST = {email: 'foo2@bar.com', password: 'bar2', emailVerified: true};
@ -21,32 +21,32 @@ describe('User', function(){
// Update the AccessToken relation to use the subclass of User
AccessToken.belongsTo(User);
// allow many User.afterRemote's to be called
User.setMaxListeners(0);
});
beforeEach(function (done) {
beforeEach(function(done) {
app.enableAuth();
app.use(loopback.token());
app.use(loopback.rest());
app.model(User);
User.create(validCredentials, function(err, user) {
User.create(validCredentialsEmailVerified, done);
});
});
afterEach(function (done) {
User.destroyAll(function (err) {
afterEach(function(done) {
User.destroyAll(function(err) {
User.accessToken.destroyAll(done);
});
});
describe('User.create', function(){
describe('User.create', function() {
it('Create a new user', function(done) {
User.create({email: 'f@b.com', password: 'bar'}, function (err, user) {
User.create({email: 'f@b.com', password: 'bar'}, function(err, user) {
assert(!err);
assert(user.id);
assert(user.email);
@ -54,13 +54,13 @@ describe('User', function(){
});
});
it('credentials/challenges are object types', function (done) {
it('credentials/challenges are object types', function(done) {
User.create({email: 'f1@b.com', password: 'bar1',
credentials: {cert: 'xxxxx', key: '111'},
challenges: {x: 'X', a: 1}
}, function (err, user) {
}, function(err, user) {
assert(!err);
User.findById(user.id, function (err, user) {
User.findById(user.id, function(err, user) {
assert(user.id);
assert(user.email);
assert.deepEqual(user.credentials, {cert: 'xxxxx', key: '111'});
@ -70,12 +70,12 @@ describe('User', function(){
});
});
it('Email is required', function (done) {
User.create({password: '123'}, function (err) {
it('Email is required', function(done) {
User.create({password: '123'}, function(err) {
assert(err);
assert.equal(err.name, "ValidationError");
assert.equal(err.name, 'ValidationError');
assert.equal(err.statusCode, 422);
assert.equal(err.details.context, "user");
assert.equal(err.details.context, 'user');
assert.deepEqual(err.details.codes.email, [
'presence',
'format.blank'
@ -84,27 +84,27 @@ describe('User', function(){
done();
});
});
// will change in future versions where password will be optional by default
it('Password is required', function(done) {
var u = new User({email: "123@456.com"});
User.create({email: 'c@d.com'}, function (err) {
var u = new User({email: '123@456.com'});
User.create({email: 'c@d.com'}, function(err) {
assert(err);
done();
});
});
it('Requires a valid email', function(done) {
User.create({email: 'foo@', password: '123'}, function (err) {
User.create({email: 'foo@', password: '123'}, function(err) {
assert(err);
done();
});
});
it('Requires a unique email', function(done) {
User.create({email: 'a@b.com', password: 'foobar'}, function () {
User.create({email: 'a@b.com', password: 'batbaz'}, function (err) {
User.create({email: 'a@b.com', password: 'foobar'}, function() {
User.create({email: 'a@b.com', password: 'batbaz'}, function(err) {
assert(err, 'should error because the email is not unique!');
done();
});
@ -112,24 +112,24 @@ 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: 'a@b.com', username: 'abc', password: 'foobar'}, function() {
User.create({email: 'b@b.com', username: 'abc', password: 'batbaz'}, function(err) {
assert(err, 'should error because the username is not unique!');
done();
});
});
});
});
it('Requires a password to login with basic auth', function(done) {
User.create({email: 'b@c.com'}, function (err) {
User.login({email: 'b@c.com'}, function (err, accessToken) {
User.create({email: 'b@c.com'}, function(err) {
User.login({email: 'b@c.com'}, function(err, accessToken) {
assert(!accessToken, 'should not create a accessToken without a valid password');
assert(err, 'should not login without a password');
done();
});
});
});
it('Hashes the given password', function() {
var u = new User({username: 'foo', password: 'bar'});
assert(u.password !== 'bar');
@ -141,26 +141,26 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(200)
.send(validCredentialsEmailVerifiedOverREST)
.end(function(err, res){
.end(function(err, res) {
assert(!res.body.emailVerified);
done();
});
});
});
describe('User.login', function() {
it('Login a user by providing credentials', function(done) {
User.login(validCredentials, function (err, accessToken) {
User.login(validCredentials, function(err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.id.length, 64);
done();
});
});
it('Login a user by providing credentials with TTL', function(done) {
User.login(validCredentialsWithTTL, function (err, accessToken) {
User.login(validCredentialsWithTTL, function(err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, validCredentialsWithTTL.ttl);
@ -175,16 +175,16 @@ describe('User', function(){
// Override createAccessToken
User.prototype.createAccessToken = function(ttl, cb) {
// Reduce the ttl by half for testing purpose
this.accessTokens.create({ttl: ttl /2 }, cb);
this.accessTokens.create({ttl: ttl / 2 }, cb);
};
User.login(validCredentialsWithTTL, function (err, accessToken) {
User.login(validCredentialsWithTTL, function(err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, 1800);
assert.equal(accessToken.id.length, 64);
User.findById(accessToken.userId, function(err, user) {
user.createAccessToken(120, function (err, accessToken) {
user.createAccessToken(120, function(err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, 60);
@ -203,15 +203,15 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(200)
.send(validCredentials)
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
var accessToken = res.body;
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.id.length, 64);
assert(accessToken.user === undefined);
done();
});
});
@ -222,7 +222,7 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(401)
.send(invalidCredentials)
.end(function(err, res){
.end(function(err, res) {
done();
});
});
@ -233,7 +233,7 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(400)
.send(incompleteCredentials)
.end(function(err, res){
.end(function(err, res) {
done();
});
});
@ -245,7 +245,7 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(400)
.send(validCredentials)
.end(function(err, res){
.end(function(err, res) {
done();
});
});
@ -284,7 +284,7 @@ describe('User', function(){
it('Login should only allow correct credentials', function(done) {
User.create({email: 'foo22@bar.com', password: 'bar'}, function(user, err) {
User.login({email: 'foo44@bar.com', password: 'bar'}, function(err, accessToken) {
User.login({email: 'foo44@bar.com', password: 'bar'}, function(err, accessToken) {
assert(err);
assert(!accessToken);
done();
@ -309,14 +309,14 @@ describe('User', function(){
});
it('Login a user by without email verification', function(done) {
User.login(validCredentials, function (err, accessToken) {
User.login(validCredentials, function(err, accessToken) {
assert(err);
done();
});
});
it('Login a user by with email verification', function(done) {
User.login(validCredentialsEmailVerified, function (err, accessToken) {
User.login(validCredentialsEmailVerified, function(err, accessToken) {
assertGoodToken(accessToken);
done();
});
@ -328,8 +328,8 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(200)
.send(validCredentialsEmailVerified)
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
var accessToken = res.body;
assertGoodToken(accessToken);
@ -353,7 +353,8 @@ describe('User', function(){
});
describe('User.login requiring realm', function() {
var User, AccessToken;
var User;
var AccessToken;
before(function() {
User = loopback.User.extend('RealmUser', {},
@ -511,20 +512,20 @@ describe('User', function(){
});
});
});
describe('User.logout', function() {
it('Logout a user by providing the current accessToken id (using node)', function(done) {
login(logout);
function login(fn) {
User.login({email: 'foo@bar.com', password: 'bar'}, fn);
}
function logout(err, accessToken) {
User.logout(accessToken.id, verify(accessToken.id, done));
}
});
it('Logout a user by providing the current accessToken id (over rest)', function(done) {
login(logout);
function login(fn) {
@ -533,17 +534,17 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(200)
.send({email: 'foo@bar.com', password: 'bar'})
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
var accessToken = res.body;
assert(accessToken.userId);
assert(accessToken.id);
fn(null, accessToken.id);
});
}
function logout(err, token) {
request(app)
.post('/users/logout')
@ -552,74 +553,74 @@ describe('User', function(){
.end(verify(token, done));
}
});
function verify(token, done) {
assert(token);
return function (err) {
if(err) return done(err);
AccessToken.findById(token, function (err, accessToken) {
return function(err) {
if (err) return done(err);
AccessToken.findById(token, function(err, accessToken) {
assert(!accessToken, 'accessToken should not exist after logging out');
done(err);
});
}
};
}
});
describe('user.hasPassword(plain, fn)', function(){
describe('user.hasPassword(plain, fn)', function() {
it('Determine if the password matches the stored password', function(done) {
var u = new User({username: 'foo', password: 'bar'});
u.hasPassword('bar', function (err, isMatch) {
u.hasPassword('bar', function(err, isMatch) {
assert(isMatch, 'password doesnt match');
done();
});
});
});
it('should match a password when saved', function(done) {
var u = new User({username: 'a', password: 'b', email: 'z@z.net'});
u.save(function (err, user) {
User.findById(user.id, function (err, uu) {
uu.hasPassword('b', function (err, isMatch) {
u.save(function(err, user) {
User.findById(user.id, function(err, uu) {
uu.hasPassword('b', function(err, isMatch) {
assert(isMatch);
done();
});
});
});
});
it('should match a password after it is changed', function(done) {
User.create({email: 'foo@baz.net', username: 'bat', password: 'baz'}, function (err, user) {
User.findById(user.id, function (err, foundUser) {
assert(foundUser);
foundUser.hasPassword('baz', function (err, isMatch) {
assert(isMatch);
foundUser.password = 'baz2';
foundUser.save(function (err, updatedUser) {
updatedUser.hasPassword('baz2', function (err, isMatch) {
assert(isMatch);
User.findById(user.id, function (err, uu) {
uu.hasPassword('baz2', function (err, isMatch) {
assert(isMatch);
done();
});
});
});
});
});
});
});
User.create({email: 'foo@baz.net', username: 'bat', password: 'baz'}, function(err, user) {
User.findById(user.id, function(err, foundUser) {
assert(foundUser);
foundUser.hasPassword('baz', function(err, isMatch) {
assert(isMatch);
foundUser.password = 'baz2';
foundUser.save(function(err, updatedUser) {
updatedUser.hasPassword('baz2', function(err, isMatch) {
assert(isMatch);
User.findById(user.id, function(err, uu) {
uu.hasPassword('baz2', function(err, isMatch) {
assert(isMatch);
done();
});
});
});
});
});
});
});
});
});
describe('Verification', function(){
describe('user.verify(options, fn)', function(){
describe('Verification', function() {
describe('user.verify(options, fn)', function() {
it('Verify a user\'s email address', function(done) {
User.afterRemote('create', function(ctx, user, next) {
assert(user, 'afterRemote should include result');
var options = {
type: 'email',
to: user.email,
@ -628,8 +629,8 @@ describe('User', function(){
protocol: ctx.req.protocol,
host: ctx.req.get('host')
};
user.verify(options, function (err, result) {
user.verify(options, function(err, result) {
assert(result.email);
assert(result.email.response);
assert(result.token);
@ -639,21 +640,21 @@ describe('User', function(){
done();
});
});
request(app)
.post('/users')
.expect('Content-Type', /json/)
.expect(200)
.send({email: 'bar@bat.com', password: 'bar'})
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
});
});
it('Verify a user\'s email address with custom header', function(done) {
User.afterRemote('create', function(ctx, user, next) {
assert(user, 'afterRemote should include result');
var options = {
type: 'email',
to: user.email,
@ -663,31 +664,31 @@ describe('User', function(){
host: ctx.req.get('host'),
headers: {'message-id':'custom-header-value'}
};
user.verify(options, function (err, result) {
user.verify(options, function(err, result) {
assert(result.email);
assert.equal(result.email.messageId, 'custom-header-value');
done();
});
});
request(app)
.post('/users')
.expect('Content-Type', /json/)
.expect(200)
.send({email: 'bar@bat.com', password: 'bar'})
.end(function(err, res){
if(err) return done(err);
.end(function(err, res) {
if (err) return done(err);
});
});
});
describe('User.confirm(options, fn)', function () {
describe('User.confirm(options, fn)', function() {
var options;
function testConfirm(testFunc, done) {
User.afterRemote('create', function (ctx, user, next) {
User.afterRemote('create', function(ctx, user, next) {
assert(user, 'afterRemote should include result');
options = {
@ -699,7 +700,7 @@ describe('User', function(){
host: ctx.req.get('host')
};
user.verify(options, function (err, result) {
user.verify(options, function(err, result) {
if (err) {
return done(err);
}
@ -712,21 +713,21 @@ describe('User', function(){
.expect('Content-Type', /json/)
.expect(302)
.send({email: 'bar@bat.com', password: 'bar'})
.end(function (err, res) {
.end(function(err, res) {
if (err) {
return done(err);
}
});
}
it('Confirm a user verification', function (done) {
testConfirm(function (result, done) {
it('Confirm a user verification', function(done) {
testConfirm(function(result, done) {
request(app)
.get('/users/confirm?uid=' + (result.uid )
.get('/users/confirm?uid=' + (result.uid)
+ '&token=' + encodeURIComponent(result.token)
+ '&redirect=' + encodeURIComponent(options.redirect))
.expect(302)
.end(function (err, res) {
.end(function(err, res) {
if (err) {
return done(err);
}
@ -735,14 +736,14 @@ describe('User', function(){
}, done);
});
it('Report error for invalid user id during verification', function (done) {
testConfirm(function (result, done) {
it('Report error for invalid user id during verification', function(done) {
testConfirm(function(result, done) {
request(app)
.get('/users/confirm?uid=' + (result.uid + '_invalid')
+ '&token=' + encodeURIComponent(result.token)
+ '&redirect=' + encodeURIComponent(options.redirect))
.expect(404)
.end(function (err, res) {
.end(function(err, res) {
if (err) {
return done(err);
}
@ -752,14 +753,14 @@ describe('User', function(){
}, done);
});
it('Report error for invalid token during verification', function (done) {
testConfirm(function (result, done) {
it('Report error for invalid token during verification', function(done) {
testConfirm(function(result, done) {
request(app)
.get('/users/confirm?uid=' + result.uid
+ '&token=' + encodeURIComponent(result.token) + '_invalid'
+ '&redirect=' + encodeURIComponent(options.redirect))
.expect(400)
.end(function (err, res) {
.end(function(err, res) {
if (err) return done(err);
assert(res.body.error);
done();
@ -769,25 +770,25 @@ describe('User', function(){
});
});
describe('Password Reset', function () {
describe('User.resetPassword(options, cb)', function () {
it('Creates a temp accessToken to allow a user to change password', function (done) {
describe('Password Reset', function() {
describe('User.resetPassword(options, cb)', function() {
it('Creates a temp accessToken to allow a user to change password', function(done) {
var calledBack = false;
var email = 'foo@bar.com';
User.resetPassword({
email: email
}, function () {
}, function() {
calledBack = true;
});
User.once('resetPasswordRequest', function (info) {
User.once('resetPasswordRequest', function(info) {
assert(info.email);
assert(info.accessToken);
assert(info.accessToken.id);
assert.equal(info.accessToken.ttl / 60, 15);
assert(calledBack);
info.accessToken.user(function (err, user) {
info.accessToken.user(function(err, user) {
assert.equal(user.email, email);
done();
});

View File

@ -8,187 +8,202 @@ var RemoteObjects = require('strong-remoting');
module.exports = function defineModelTestsWithDataSource(options) {
describe('Model Tests', function() {
describe('Model Tests', function() {
var User, dataSource;
var User;
var dataSource;
if(options.beforeEach) {
beforeEach(options.beforeEach);
}
beforeEach(function() {
var test = this;
// setup a model / datasource
dataSource = this.dataSource || loopback.createDataSource(options.dataSource);
var extend = PersistedModel.extend;
// create model hook
PersistedModel.extend = function() {
var extendedModel = extend.apply(PersistedModel, arguments);
if(options.onDefine) {
options.onDefine.call(test, extendedModel);
}
return extendedModel;
if (options.beforeEach) {
beforeEach(options.beforeEach);
}
User = PersistedModel.extend('user', {
'first': String,
'last': String,
'age': Number,
'password': String,
'gender': String,
'domain': String,
'email': String
}, {
trackChanges: true
beforeEach(function() {
var test = this;
// setup a model / datasource
dataSource = this.dataSource || loopback.createDataSource(options.dataSource);
var extend = PersistedModel.extend;
// create model hook
PersistedModel.extend = function() {
var extendedModel = extend.apply(PersistedModel, arguments);
if (options.onDefine) {
options.onDefine.call(test, extendedModel);
}
return extendedModel;
};
User = PersistedModel.extend('user', {
'first': String,
'last': String,
'age': Number,
'password': String,
'gender': String,
'domain': String,
'email': String
}, {
trackChanges: true
});
// enable destroy all for testing
User.destroyAll.shared = true;
User.attachTo(dataSource);
});
// enable destroy all for testing
User.destroyAll.shared = true;
User.attachTo(dataSource);
});
describe('Model.validatesPresenceOf(properties...)', function() {
it("Require a model to include a property to be considered valid", function() {
User.validatesPresenceOf('first', 'last', 'age');
var joe = new User({first: 'joe'});
assert(joe.isValid() === false, 'model should not validate');
assert(joe.errors.last, 'should have a missing last error');
assert(joe.errors.age, 'should have a missing age error');
describe('Model.validatesPresenceOf(properties...)', function() {
it('Require a model to include a property to be considered valid', function() {
User.validatesPresenceOf('first', 'last', 'age');
var joe = new User({first: 'joe'});
assert(joe.isValid() === false, 'model should not validate');
assert(joe.errors.last, 'should have a missing last error');
assert(joe.errors.age, 'should have a missing age error');
});
});
});
describe('Model.validatesLengthOf(property, options)', function() {
it("Require a property length to be within a specified range", function() {
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
var joe = new User({password: '1234'});
assert(joe.isValid() === false, 'model should not be valid');
assert(joe.errors.password, 'should have password error');
describe('Model.validatesLengthOf(property, options)', function() {
it('Require a property length to be within a specified range', function() {
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
var joe = new User({password: '1234'});
assert(joe.isValid() === false, 'model should not be valid');
assert(joe.errors.password, 'should have password error');
});
});
});
describe('Model.validatesInclusionOf(property, options)', function() {
it("Require a value for `property` to be in the specified array", function() {
User.validatesInclusionOf('gender', {in: ['male', 'female']});
var foo = new User({gender: 'bar'});
assert(foo.isValid() === false, 'model should not be valid');
assert(foo.errors.gender, 'should have gender error');
describe('Model.validatesInclusionOf(property, options)', function() {
it('Require a value for `property` to be in the specified array', function() {
User.validatesInclusionOf('gender', {in: ['male', 'female']});
var foo = new User({gender: 'bar'});
assert(foo.isValid() === false, 'model should not be valid');
assert(foo.errors.gender, 'should have gender error');
});
});
});
describe('Model.validatesExclusionOf(property, options)', function() {
it("Require a value for `property` to not exist in the specified array", function() {
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
var foo = new User({domain: 'www'});
var bar = new User({domain: 'billing'});
var bat = new User({domain: 'admin'});
assert(foo.isValid() === false);
assert(bar.isValid() === false);
assert(bat.isValid() === false);
assert(foo.errors.domain, 'model should have a domain error');
assert(bat.errors.domain, 'model should have a domain error');
assert(bat.errors.domain, 'model should have a domain error');
describe('Model.validatesExclusionOf(property, options)', function() {
it('Require a value for `property` to not exist in the specified array', function() {
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
var foo = new User({domain: 'www'});
var bar = new User({domain: 'billing'});
var bat = new User({domain: 'admin'});
assert(foo.isValid() === false);
assert(bar.isValid() === false);
assert(bat.isValid() === false);
assert(foo.errors.domain, 'model should have a domain error');
assert(bat.errors.domain, 'model should have a domain error');
assert(bat.errors.domain, 'model should have a domain error');
});
});
});
describe('Model.validatesNumericalityOf(property, options)', function() {
it("Require a value for `property` to be a specific type of `Number`", function() {
User.validatesNumericalityOf('age', {int: true});
var joe = new User({age: 10.2});
assert(joe.isValid() === false);
var bob = new User({age: 0});
assert(bob.isValid() === true);
assert(joe.errors.age, 'model should have an age error');
describe('Model.validatesNumericalityOf(property, options)', function() {
it('Require a value for `property` to be a specific type of `Number`', function() {
User.validatesNumericalityOf('age', {int: true});
var joe = new User({age: 10.2});
assert(joe.isValid() === false);
var bob = new User({age: 0});
assert(bob.isValid() === true);
assert(joe.errors.age, 'model should have an age error');
});
});
});
describe('myModel.isValid()', function() {
it("Validate the model instance", function() {
User.validatesNumericalityOf('age', {int: true});
var user = new User({first: 'joe', age: 'flarg'})
var valid = user.isValid();
assert(valid === false);
assert(user.errors.age, 'model should have age error');
});
it('Asynchronously validate the model', function(done) {
User.validatesNumericalityOf('age', {int: true});
var user = new User({first: 'joe', age: 'flarg'});
user.isValid(function (valid) {
describe('myModel.isValid()', function() {
it('Validate the model instance', function() {
User.validatesNumericalityOf('age', {int: true});
var user = new User({first: 'joe', age: 'flarg'});
var valid = user.isValid();
assert(valid === false);
assert(user.errors.age, 'model should have age error');
done();
});
});
});
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);
done();
});
});
});
describe('model.save([options], [callback])', function() {
it("Save an instance of a Model to the attached data source", function(done) {
var joe = new User({first: 'Joe', last: 'Bob'});
joe.save(function(err, user) {
assert(user.id);
assert(!err);
assert(!user.errors);
done();
});
});
});
describe('model.updateAttributes(data, [callback])', function() {
it("Save specified attributes to the attached data source", function(done) {
User.create({first: 'joe', age: 100}, function (err, user) {
assert(!err);
assert.equal(user.first, 'joe');
user.updateAttributes({
first: 'updatedFirst',
last: 'updatedLast'
}, function (err, updatedUser) {
assert(!err);
assert.equal(updatedUser.first, 'updatedFirst');
assert.equal(updatedUser.last, 'updatedLast');
assert.equal(updatedUser.age, 100);
it('Asynchronously validate the model', function(done) {
User.validatesNumericalityOf('age', {int: true});
var user = new User({first: 'joe', age: 'flarg'});
user.isValid(function(valid) {
assert(valid === false);
assert(user.errors.age, 'model should have age error');
done();
});
});
});
});
describe('Model.upsert(data, callback)', function() {
it("Update when record with id=data.id found, insert otherwise", function(done) {
User.upsert({first: 'joe', id: 7}, function (err, user) {
assert(!err);
assert.equal(user.first, 'joe');
User.upsert({first: 'bob', id: 7}, function (err, updatedUser) {
assert(!err);
assert.equal(updatedUser.first, 'bob');
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);
done();
});
});
});
});
describe('model.destroy([callback])', function() {
it("Remove a model from the attached data source", function(done) {
User.create({first: 'joe', last: 'bob'}, function (err, user) {
User.findById(user.id, function (err, foundUser) {
assert.equal(user.id, foundUser.id);
foundUser.destroy(function () {
User.findById(user.id, function (err, notFound) {
describe('model.save([options], [callback])', function() {
it('Save an instance of a Model to the attached data source', function(done) {
var joe = new User({first: 'Joe', last: 'Bob'});
joe.save(function(err, user) {
assert(user.id);
assert(!err);
assert(!user.errors);
done();
});
});
});
describe('model.updateAttributes(data, [callback])', function() {
it('Save specified attributes to the attached data source', function(done) {
User.create({first: 'joe', age: 100}, function(err, user) {
assert(!err);
assert.equal(user.first, 'joe');
user.updateAttributes({
first: 'updatedFirst',
last: 'updatedLast'
}, function(err, updatedUser) {
assert(!err);
assert.equal(updatedUser.first, 'updatedFirst');
assert.equal(updatedUser.last, 'updatedLast');
assert.equal(updatedUser.age, 100);
done();
});
});
});
});
describe('Model.upsert(data, callback)', function() {
it('Update when record with id=data.id found, insert otherwise', function(done) {
User.upsert({first: 'joe', id: 7}, function(err, user) {
assert(!err);
assert.equal(user.first, 'joe');
User.upsert({first: 'bob', id: 7}, function(err, updatedUser) {
assert(!err);
assert.equal(updatedUser.first, 'bob');
done();
});
});
});
});
describe('model.destroy([callback])', function() {
it('Remove a model from the attached data source', function(done) {
User.create({first: 'joe', last: 'bob'}, function(err, user) {
User.findById(user.id, function(err, foundUser) {
assert.equal(user.id, foundUser.id);
foundUser.destroy(function() {
User.findById(user.id, function(err, notFound) {
assert.equal(notFound, null);
done();
});
});
});
});
});
});
describe('Model.deleteById(id, [callback])', function() {
it('Delete a model instance from the attached data source', function(done) {
User.create({first: 'joe', last: 'bob'}, function(err, user) {
User.deleteById(user.id, function(err) {
User.findById(user.id, function(err, notFound) {
assert.equal(notFound, null);
done();
});
@ -196,52 +211,37 @@ describe('Model Tests', function() {
});
});
});
});
describe('Model.deleteById(id, [callback])', function () {
it("Delete a model instance from the attached data source", function (done) {
User.create({first: 'joe', last: 'bob'}, function (err, user) {
User.deleteById(user.id, function (err) {
User.findById(user.id, function (err, notFound) {
assert.equal(notFound, null);
done();
});
});
});
});
});
describe('Model.findById(id, callback)', function() {
it("Find an instance by id", function(done) {
User.create({first: 'michael', last: 'jordan', id: 23}, function () {
User.findById(23, function (err, user) {
assert.equal(user.id, 23);
assert.equal(user.first, 'michael');
assert.equal(user.last, 'jordan');
done();
});
});
});
});
describe('Model.count([query], callback)', function() {
it("Query count of Model instances in data source", function(done) {
(new TaskEmitter())
.task(User, 'create', {first: 'jill', age: 100})
.task(User, 'create', {first: 'bob', age: 200})
.task(User, 'create', {first: 'jan'})
.task(User, 'create', {first: 'sam'})
.task(User, 'create', {first: 'suzy'})
.on('done', function () {
User.count({age: {gt: 99}}, function (err, count) {
assert.equal(count, 2);
describe('Model.findById(id, callback)', function() {
it('Find an instance by id', function(done) {
User.create({first: 'michael', last: 'jordan', id: 23}, function() {
User.findById(23, function(err, user) {
assert.equal(user.id, 23);
assert.equal(user.first, 'michael');
assert.equal(user.last, 'jordan');
done();
});
});
});
});
describe('Model.count([query], callback)', function() {
it('Query count of Model instances in data source', function(done) {
(new TaskEmitter())
.task(User, 'create', {first: 'jill', age: 100})
.task(User, 'create', {first: 'bob', age: 200})
.task(User, 'create', {first: 'jan'})
.task(User, 'create', {first: 'sam'})
.task(User, 'create', {first: 'suzy'})
.on('done', function() {
User.count({age: {gt: 99}}, function(err, count) {
assert.equal(count, 2);
done();
});
});
});
});
});
});
}
};