Clean up tests
This commit is contained in:
parent
7ac9679c17
commit
ba1703fbea
|
@ -14,8 +14,9 @@
|
|||
"quotmark": "single",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"unused": false,
|
||||
"trailing": true,
|
||||
"sub": true,
|
||||
"maxlen": 80
|
||||
"maxlen": 80,
|
||||
"predef": [ "describe", "beforeEach", "afterEach", "before", "after", "it" ]
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ module.exports = function(grunt) {
|
|||
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
|
||||
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||
'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
|
||||
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
|
||||
'* Copyright (c) <%= grunt.template.today("yyyy") %> ' +
|
||||
'<%= pkg.author.name %>;' +
|
||||
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
|
||||
// Task configuration.
|
||||
jshint: {
|
||||
|
@ -17,7 +18,7 @@ module.exports = function(grunt) {
|
|||
gruntfile: {
|
||||
src: 'Gruntfile.js'
|
||||
},
|
||||
lib_test: {
|
||||
libTest: {
|
||||
src: ['lib/**/*.js', 'test/**/*.js']
|
||||
}
|
||||
},
|
||||
|
|
|
@ -41,14 +41,15 @@ function RelationMixin() {
|
|||
* // Save the new chapter
|
||||
* chapter.save();
|
||||
*
|
||||
* // you can also call the Chapter.create method with the `chapters` property which will build a chapter
|
||||
* // instance and save the it in the data source.
|
||||
* // you can also call the Chapter.create method with the `chapters` property
|
||||
* // which will build a chapter instance and save the it in the data source.
|
||||
* book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
|
||||
* // this callback is optional
|
||||
* });
|
||||
*
|
||||
* // Query chapters for the book
|
||||
* book.chapters(function(err, chapters) { // all chapters with bookId = book.id
|
||||
* book.chapters(function(err, chapters) {
|
||||
* // all chapters with bookId = book.id
|
||||
* console.log(chapters);
|
||||
* });
|
||||
*
|
||||
|
@ -58,9 +59,11 @@ function RelationMixin() {
|
|||
* });
|
||||
* });
|
||||
*```
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to
|
||||
* which you are creating the relationship.
|
||||
* @options {Object} parameters Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} as Name of the property in the referring model that
|
||||
* corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {Object} model Model object
|
||||
*/
|
||||
|
@ -71,12 +74,14 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Declare "belongsTo" relation that sets up a one-to-one connection with another model, such that each
|
||||
* instance of the declaring model "belongs to" one instance of the other model.
|
||||
* Declare "belongsTo" relation that sets up a one-to-one connection with
|
||||
* another model, such that each instance of the declaring model "belongs
|
||||
* to" one instance of the other model.
|
||||
*
|
||||
* For example, if an application includes users and posts, and each post can be written by exactly one user.
|
||||
* The following code specifies that `Post` has a reference called `author` to the `User` model via the `userId` property of `Post`
|
||||
* as the foreign key.
|
||||
* For example, if an application includes users and posts, and each post can be
|
||||
* written by exactly one user. The following code specifies that `Post` has a
|
||||
* reference called `author` to the `User` model via the `userId` property of
|
||||
* `Post` as the foreign key.
|
||||
* ```
|
||||
* Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
|
||||
* ```
|
||||
|
@ -94,7 +99,8 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
* ```
|
||||
* Examples:
|
||||
*
|
||||
* Suppose the model Post has a *belongsTo* relationship with User (the author of the post). You could declare it this way:
|
||||
* Suppose the model Post has a *belongsTo* relationship with User (the author
|
||||
* of the post). You could declare it this way:
|
||||
* ```js
|
||||
* Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
|
||||
* ```
|
||||
|
@ -106,18 +112,22 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
* });
|
||||
* ```
|
||||
*
|
||||
* The related object is cached, so if later you try to get again the author, no additional request will be made.
|
||||
* But there is an optional boolean parameter in first position that set whether or not you want to reload the cache:
|
||||
* The related object is cached, so if later you try to get again the author, no
|
||||
* additional request will be made. But there is an optional boolean parameter
|
||||
* in first position that set whether or not you want to reload the cache:
|
||||
* ```js
|
||||
* post.author(true, function(err, user) {
|
||||
* // The user is reloaded, even if it was already cached.
|
||||
* });
|
||||
* ```
|
||||
* This optional parameter default value is false, so the related object will be loaded from cache if available.
|
||||
* This optional parameter default value is false, so the related object will
|
||||
* be loaded from cache if available.
|
||||
*
|
||||
* @param {Class|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @param {Class|String} modelTo Model object (or String name of model)
|
||||
* to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} as Name of the property in the referring model that
|
||||
* corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Name of foreign key property.
|
||||
*
|
||||
*/
|
||||
|
@ -128,9 +138,10 @@ RelationMixin.belongsTo = function(modelTo, params) {
|
|||
};
|
||||
|
||||
/**
|
||||
* A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model.
|
||||
* For example, if your application includes users and groups, with each group having many users and each user appearing
|
||||
* in many groups, you could declare the models this way:
|
||||
* A hasAndBelongsToMany relation creates a direct many-to-many connection with
|
||||
* another model, with no intervening model. For example, if your application
|
||||
* includes users and groups, with each group having many users and each user
|
||||
* appearing in many groups, you could declare the models this way:
|
||||
* ```
|
||||
* User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'});
|
||||
* ```
|
||||
|
@ -151,10 +162,11 @@ RelationMixin.belongsTo = function(modelTo, params) {
|
|||
* user.groups.remove(group, callback);
|
||||
* ```
|
||||
*
|
||||
* @param {String|Object} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* the relation
|
||||
* @param {String|Object} modelTo Model object (or String name of model) to
|
||||
* which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} as Name of the property in the referring model that
|
||||
* corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {Object} model Model object
|
||||
*/
|
||||
|
@ -202,7 +214,7 @@ function defineRelationProperty(modelClass, def) {
|
|||
scope.create = function() {
|
||||
return that['__create__' + def.name].apply(that, arguments);
|
||||
};
|
||||
scope.deleteById = destroyById = function() {
|
||||
scope.deleteById = scope.destroyById = function() {
|
||||
return that['__destroyById__' + def.name].apply(that, arguments);
|
||||
};
|
||||
scope.exists = function() {
|
||||
|
|
|
@ -24,7 +24,7 @@ function RemoteConnector(settings) {
|
|||
'cannot initiaze RemoteConnector without a settings object');
|
||||
this.client = settings.client;
|
||||
this.adapter = settings.adapter || 'rest';
|
||||
this.protocol = settings.protocol || 'http'
|
||||
this.protocol = settings.protocol || 'http';
|
||||
this.root = settings.root || '';
|
||||
this.host = settings.host || 'localhost';
|
||||
this.port = settings.port || 3000;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"devDependencies": {
|
||||
"assert": "^1.1.2",
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-mocha-test": "^0.11.0",
|
||||
"loopback": "^2.2.0",
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
var loopback = require('loopback');
|
||||
var remoteConnector = require('..');
|
||||
|
||||
exports.createMemoryDataSource = createMemoryDataSource;
|
||||
exports.createModel = createModel;
|
||||
exports.createRemoteDataSource = createRemoteDataSource;
|
||||
exports.createRestAppAndListen = createRestAppAndListen;
|
||||
exports.getUserProperties = getUserProperties;
|
||||
|
||||
function createRestAppAndListen(port) {
|
||||
var app = loopback();
|
||||
|
||||
app.set('host', '127.0.0.1');
|
||||
if (port) app.set('port', port);
|
||||
|
||||
app.use(loopback.rest());
|
||||
app.locals.handler = app.listen();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
function createMemoryDataSource() {
|
||||
return loopback.createDataSource({connector: 'memory'});
|
||||
}
|
||||
|
||||
function createRemoteDataSource(remoteApp) {
|
||||
return loopback.createDataSource({
|
||||
url: 'http://' + remoteApp.get('host') + ':' + remoteApp.get('port'),
|
||||
connector: remoteConnector
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create models based on a set of options. May associate or link to an
|
||||
* app.
|
||||
*/
|
||||
function createModel(options) {
|
||||
var Model = loopback.PersistedModel.extend(options.parent, options.properties,
|
||||
options.options);
|
||||
if (options.app) options.app.model(Model);
|
||||
if (options.datasource) Model.attachTo(options.datasource);
|
||||
return Model;
|
||||
}
|
||||
|
||||
function getUserProperties() {
|
||||
return {
|
||||
'first': String,
|
||||
'last': String,
|
||||
'age': Number,
|
||||
'password': String,
|
||||
'gender': String,
|
||||
'domain': String,
|
||||
'email': String
|
||||
};
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
var assert = require('assert');
|
||||
var helper = require('./helper');
|
||||
var TaskEmitter = require('strong-task-emitter');
|
||||
|
||||
describe('Model tests', function() {
|
||||
var User;
|
||||
|
||||
beforeEach(function() {
|
||||
User = helper.createModel({
|
||||
parent: 'user',
|
||||
app: helper.createRestAppAndListen(),
|
||||
datasource: helper.createMemoryDataSource(),
|
||||
properties: helper.getUserProperties()
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model.validatesPresenceOf(properties...)', function() {
|
||||
it('should 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('should 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('should 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('should 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('should 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('should 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('should validate the model asynchronously', 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.create([data], [callback])', function() {
|
||||
it('should create an instance 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('should 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('should 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('should update when a record with id=data.id is 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('should 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('should 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('should 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('should return the count of Model instances in data source',
|
||||
function(done) {
|
||||
var taskEmitter = new TaskEmitter();
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,122 +1,108 @@
|
|||
var loopback = require('loopback');
|
||||
var defineModelTestsWithDataSource = require('./util/model-tests');
|
||||
var assert = require('assert');
|
||||
var Remote = require('..');
|
||||
|
||||
function createAppWithRest() {
|
||||
var app = loopback();
|
||||
app.set('host', '127.0.0.1');
|
||||
app.use(loopback.rest());
|
||||
return app;
|
||||
}
|
||||
|
||||
function listenAndSetupRemoteDS(test, app, remoteName, cb) {
|
||||
app.listen(0, function() {
|
||||
test[remoteName] = loopback.createDataSource({
|
||||
host: '127.0.0.1',
|
||||
port: app.get('port'),
|
||||
connector: Remote,
|
||||
});
|
||||
cb();
|
||||
});
|
||||
}
|
||||
var helper = require('./helper');
|
||||
|
||||
describe('RemoteConnector', function() {
|
||||
var remoteApp;
|
||||
var remote;
|
||||
var ctx = this;
|
||||
|
||||
defineModelTestsWithDataSource({
|
||||
beforeEach: function(done) {
|
||||
var test = this;
|
||||
remoteApp = createAppWithRest();
|
||||
listenAndSetupRemoteDS(test, remoteApp, 'dataSource', done);
|
||||
},
|
||||
onDefine: function(Model) {
|
||||
var RemoteModel = Model.extend(Model.modelName);
|
||||
RemoteModel.attachTo(loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
}));
|
||||
remoteApp.model(RemoteModel);
|
||||
}
|
||||
before(function() {
|
||||
ctx.serverApp = helper.createRestAppAndListen(3001);
|
||||
ctx.ServerModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.serverApp,
|
||||
datasource: helper.createMemoryDataSource()
|
||||
});
|
||||
ctx.remoteApp = helper.createRestAppAndListen(3002);
|
||||
ctx.RemoteModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.remoteApp,
|
||||
datasource: helper.createRemoteDataSource(ctx.serverApp)
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
var test = this;
|
||||
var ServerModel = this.ServerModel =
|
||||
loopback.PersistedModel.extend('TestModel');
|
||||
|
||||
remoteApp = test.remoteApp = createAppWithRest();
|
||||
remoteApp.model(ServerModel);
|
||||
|
||||
listenAndSetupRemoteDS(test, remoteApp, 'remote', done);
|
||||
after(function() {
|
||||
ctx.serverApp.locals.handler.close();
|
||||
ctx.remoteApp.locals.handler.close();
|
||||
ctx.ServerModel = null;
|
||||
ctx.RemoteModel = null;
|
||||
});
|
||||
|
||||
it('should support the save method', function(done) {
|
||||
var calledServerCreate = false;
|
||||
var RemoteModel = loopback.PersistedModel.extend('TestModel');
|
||||
RemoteModel.attachTo(this.remote);
|
||||
|
||||
var ServerModel = this.ServerModel;
|
||||
|
||||
ServerModel.create = function(data, cb) {
|
||||
ctx.ServerModel.create = function(data, cb, callback) {
|
||||
calledServerCreate = true;
|
||||
data.id = 1;
|
||||
cb(null, data);
|
||||
}
|
||||
if (callback) callback(null, data);
|
||||
else cb(null, data);
|
||||
};
|
||||
|
||||
ServerModel.setupRemoting();
|
||||
|
||||
var m = new RemoteModel({foo: 'bar'});
|
||||
m.save(function(err, inst) {
|
||||
assert(inst instanceof RemoteModel);
|
||||
var m = new ctx.RemoteModel({foo: 'bar'});
|
||||
m.save(function(err, instance) {
|
||||
if (err) return done(err);
|
||||
assert(instance);
|
||||
assert(instance instanceof ctx.RemoteModel);
|
||||
assert(calledServerCreate);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support aliases', function(done) {
|
||||
var RemoteModel = loopback.PersistedModel.extend('TestModel');
|
||||
RemoteModel.attachTo(this.remote);
|
||||
|
||||
var ServerModel = this.ServerModel;
|
||||
|
||||
ServerModel.upsert = function(id, cb) {
|
||||
done();
|
||||
var calledServerUpsert = false;
|
||||
ctx.ServerModel.upsert = function(id, cb) {
|
||||
calledServerUpsert = true;
|
||||
cb();
|
||||
};
|
||||
|
||||
RemoteModel.updateOrCreate({}, function(err, inst) {
|
||||
ctx.RemoteModel.updateOrCreate({}, function(err, instance) {
|
||||
if (err) return done(err);
|
||||
assert(instance);
|
||||
assert(instance instanceof ctx.RemoteModel);
|
||||
assert(calledServerUpsert);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom Path', function() {
|
||||
var test = this;
|
||||
var ctx = this;
|
||||
|
||||
before(function(done) {
|
||||
var ServerModel = loopback.PersistedModel.extend('TestModel', {}, {
|
||||
ctx.serverApp = helper.createRestAppAndListen(3001);
|
||||
ctx.ServerModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.serverApp,
|
||||
datasource: helper.createMemoryDataSource(),
|
||||
options: {
|
||||
http: {path: '/custom'}
|
||||
}
|
||||
});
|
||||
|
||||
server = test.server = createAppWithRest();
|
||||
server.dataSource('db', {
|
||||
connector: loopback.Memory,
|
||||
name: 'db'
|
||||
ctx.remoteApp = helper.createRestAppAndListen(3002);
|
||||
ctx.RemoteModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.remoteApp,
|
||||
datasource: helper.createRemoteDataSource(ctx.serverApp),
|
||||
options: {
|
||||
dataSource: 'remote',
|
||||
http: {path: '/custom'}
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
server.model(ServerModel, {dataSource: 'db'});
|
||||
|
||||
listenAndSetupRemoteDS(test, server, 'remote', done);
|
||||
after(function(done)
|
||||
{
|
||||
ctx.serverApp.locals.handler.close();
|
||||
ctx.remoteApp.locals.handler.close();
|
||||
ctx.ServerModel = null;
|
||||
ctx.RemoteModel = null;
|
||||
done();
|
||||
});
|
||||
|
||||
it('should support http.path configuration', function(done) {
|
||||
var RemoteModel = loopback.PersistedModel.extend('TestModel', {}, {
|
||||
dataSource: 'remote',
|
||||
http: {path: '/custom'}
|
||||
});
|
||||
RemoteModel.attachTo(test.remote);
|
||||
|
||||
RemoteModel.create({}, function(err, instance) {
|
||||
if (err) return assert(err);
|
||||
ctx.RemoteModel.create({}, function(err, instance) {
|
||||
if (err) return done(err);
|
||||
assert(instance);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
var assert = require('assert');
|
||||
var helper = require('./helper');
|
||||
var TaskEmitter = require('strong-task-emitter');
|
||||
|
||||
describe('Remote model tests', function() {
|
||||
var ctx = this;
|
||||
|
||||
beforeEach(function() {
|
||||
ctx.serverApp = helper.createRestAppAndListen(3001);
|
||||
ctx.ServerModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.serverApp,
|
||||
datasource: helper.createMemoryDataSource(),
|
||||
properties: helper.userProperties
|
||||
});
|
||||
|
||||
ctx.remoteApp = helper.createRestAppAndListen(3002);
|
||||
ctx.RemoteModel = helper.createModel({
|
||||
parent: 'TestModel',
|
||||
app: ctx.remoteApp,
|
||||
datasource: helper.createRemoteDataSource(ctx.serverApp),
|
||||
properties: helper.userProperties
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
ctx.serverApp.locals.handler.close();
|
||||
ctx.remoteApp.locals.handler.close();
|
||||
ctx.ServerModel = null;
|
||||
ctx.RemoteModel = null;
|
||||
});
|
||||
|
||||
describe('Model.create([data], [callback])', function() {
|
||||
it('should create an instance and save to the attached data source',
|
||||
function(done) {
|
||||
ctx.RemoteModel.create({first: 'Joe', last: 'Bob'}, function(err, user) {
|
||||
assert(user instanceof ctx.RemoteModel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('model.save([options], [callback])', function() {
|
||||
it('should save an instance of a Model to the attached data source',
|
||||
function(done) {
|
||||
var joe = new ctx.RemoteModel({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('should save specified attributes to the attached data source',
|
||||
function(done) {
|
||||
ctx.ServerModel.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('should update when a record with id=data.id is found, insert otherwise',
|
||||
function(done) {
|
||||
ctx.RemoteModel.upsert({first: 'joe', id: 7}, function(err, user) {
|
||||
assert(!err);
|
||||
assert.equal(user.first, 'joe');
|
||||
|
||||
ctx.RemoteModel.upsert({first: 'bob', id: 7}, function(err,
|
||||
updatedUser) {
|
||||
assert(!err);
|
||||
assert.equal(updatedUser.first, 'bob');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model.deleteById(id, [callback])', function() {
|
||||
it('should delete a model instance from the attached data source',
|
||||
function(done) {
|
||||
ctx.ServerModel.create({first: 'joe', last: 'bob'}, function(err, user) {
|
||||
ctx.RemoteModel.deleteById(user.id, function(err) {
|
||||
ctx.RemoteModel.findById(user.id, function(err, notFound) {
|
||||
assert.equal(notFound, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model.findById(id, callback)', function() {
|
||||
it('should find an instance by id from the attached data source',
|
||||
function(done) {
|
||||
ctx.ServerModel.create({first: 'michael', last: 'jordan', id: 23},
|
||||
function() {
|
||||
ctx.RemoteModel.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('should return the count of Model instances from both data source',
|
||||
function(done) {
|
||||
var taskEmitter = new TaskEmitter();
|
||||
taskEmitter
|
||||
.task(ctx.ServerModel, 'create', {first: 'jill', age: 100})
|
||||
.task(ctx.RemoteModel, 'create', {first: 'bob', age: 200})
|
||||
.task(ctx.RemoteModel, 'create', {first: 'jan'})
|
||||
.task(ctx.ServerModel, 'create', {first: 'sam'})
|
||||
.task(ctx.ServerModel, 'create', {first: 'suzy'})
|
||||
.on('done', function() {
|
||||
ctx.RemoteModel.count({age: {gt: 99}}, function(err, count) {
|
||||
assert.equal(count, 2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,259 +0,0 @@
|
|||
var assert = require('assert');
|
||||
var loopback = require('loopback');
|
||||
var PersistedModel = loopback.PersistedModel;
|
||||
var TaskEmitter = require('strong-task-emitter');
|
||||
|
||||
module.exports = function defineModelTestsWithDataSource(options) {
|
||||
|
||||
describe('Model Tests', function() {
|
||||
|
||||
var User, 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;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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.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.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) {
|
||||
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);
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue