diff --git a/package.json b/package.json index 2074e809..01ef5319 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ ], "devDependencies": { "mocha": "~1.20.1", - "should": "^1.3.0" + "should": "^4.6.3" }, "dependencies": { "async": "~0.9.0", diff --git a/test/datatype.test.js b/test/datatype.test.js index b4761ffa..3c542e2e 100644 --- a/test/datatype.test.js +++ b/test/datatype.test.js @@ -8,7 +8,7 @@ describe('datatypes', function () { before(function (done) { db = getSchema(); Nested = db.define('Nested', {}); - + Model = db.define('Model', { str: String, date: Date, @@ -29,11 +29,11 @@ describe('datatypes', function () { Model.create({ str: 'hello', date: d, num: '3', bool: 1, list: ['test'], arr: [1, 'str'] }, function (err, m) { - should.not.exist(err); + should.not.exists(err); should.exist(m && m.id); - m.str.should.be.a('string'); - m.num.should.be.a('number'); - m.bool.should.be.a('boolean'); + m.str.should.be.type('string'); + m.num.should.be.type('number'); + m.bool.should.be.type('boolean'); m.list[0].should.be.equal('test'); m.arr[0].should.be.equal(1); m.arr[1].should.be.equal('str'); @@ -45,9 +45,9 @@ describe('datatypes', function () { Model.findById(id, function (err, m) { should.not.exist(err); should.exist(m); - m.str.should.be.a('string'); - m.num.should.be.a('number'); - m.bool.should.be.a('boolean'); + m.str.should.be.type('string'); + m.num.should.be.type('number'); + m.bool.should.be.type('boolean'); m.list[0].should.be.equal('test'); m.arr[0].should.be.equal(1); m.arr[1].should.be.equal('str'); @@ -61,9 +61,9 @@ describe('datatypes', function () { Model.findOne(function (err, m) { should.not.exist(err); should.exist(m); - m.str.should.be.a('string'); - m.num.should.be.a('number'); - m.bool.should.be.a('boolean'); + m.str.should.be.type('string'); + m.num.should.be.type('number'); + m.bool.should.be.type('boolean'); m.date.should.be.an.instanceOf(Date); m.date.toString().should.equal(d.toString(), 'Time must match'); done(); @@ -81,9 +81,9 @@ describe('datatypes', function () { should.exist(m && m.id); // sanity check initial types - m.str.should.be.a('string'); - m.num.should.be.a('number'); - m.bool.should.be.a('boolean'); + m.str.should.be.type('string'); + m.num.should.be.type('number'); + m.bool.should.be.type('boolean'); id = m.id; testDataInDB(function () { testUpdate(function() { @@ -101,7 +101,7 @@ describe('datatypes', function () { id: id, num: '10' }, function (err, m) { should.not.exist(err); - m.num.should.be.a('number'); + m.num.should.be.type('number'); done(); }); }); @@ -112,15 +112,15 @@ describe('datatypes', function () { // verify that the value stored in the db is still an object db.connector.find(Model.modelName, id, function (err, data) { should.exist(data); - data.num.should.be.a('number'); + data.num.should.be.type('number'); done(); }); } }); - + it('should not coerce nested objects into ModelConstructor types', function() { var coerced = Model._coerce({ nested: { foo: 'bar' } }); coerced.nested.constructor.name.should.equal('Object'); }); - + }); diff --git a/test/defaults.test.js b/test/defaults.test.js index 0aab4ef1..8c3e89a2 100644 --- a/test/defaults.test.js +++ b/test/defaults.test.js @@ -35,7 +35,7 @@ describe('defaults', function () { done(); }); }); - + it('should ignore defaults with limited fields', function (done) { Server.create({ host: 'localhost', port: 8080 }, function(err, s) { should.not.exist(err); @@ -43,10 +43,10 @@ describe('defaults', function () { Server.find({ fields: ['host'] }, function (err, servers) { servers[0].host.should.equal('localhost'); servers[0].should.have.property('host'); - servers[0].should.not.have.property('port'); + servers[0].should.have.property('port', undefined); done(); }); }); }); - + }); diff --git a/test/include.test.js b/test/include.test.js index a2f522bb..e760508c 100644 --- a/test/include.test.js +++ b/test/include.test.js @@ -79,7 +79,7 @@ describe('include', function () { done(); }); }); - + it('should fetch Passport - Owner - Posts - alternate syntax', function (done) { Passport.find({include: {owner: {relation: 'posts'}}}, function (err, passports) { should.not.exist(err); @@ -120,7 +120,7 @@ describe('include', function () { done(); }); }); - + it('should fetch Passports with include scope on Posts', function (done) { Passport.find({ include: {owner: {relation: 'posts', scope:{ @@ -131,31 +131,31 @@ describe('include', function () { should.not.exist(err); should.exist(passports); passports.length.should.equal(3); - + var passport = passports[0]; passport.number.should.equal('1'); passport.owner().name.should.equal('User A'); var owner = passport.owner().toObject(); - + var posts = passport.owner().posts(); posts.should.be.an.array; posts.should.have.length(3); - + posts[0].title.should.equal('Post C'); - posts[0].should.not.have.property('id'); // omitted + posts[0].should.have.property('id', undefined); // omitted posts[0].author().should.be.instanceOf(User); posts[0].author().name.should.equal('User A'); - + posts[1].title.should.equal('Post B'); posts[1].author().name.should.equal('User A'); - + posts[2].title.should.equal('Post A'); posts[2].author().name.should.equal('User A'); - + done(); }); }); - + it('should fetch Users with include scope on Posts - belongsTo', function (done) { Post.find({ include: { relation: 'author', scope:{ fields: ['name'] }} @@ -163,16 +163,16 @@ describe('include', function () { should.not.exist(err); should.exist(posts); posts.length.should.equal(5); - + var author = posts[0].author(); author.name.should.equal('User A'); author.should.have.property('id'); - author.should.not.have.property('age'); - + author.should.have.property('age', undefined); + done(); }); }); - + it('should fetch Users with include scope on Posts - hasMany', function (done) { User.find({ include: {relation: 'posts', scope:{ @@ -182,27 +182,27 @@ describe('include', function () { should.not.exist(err); should.exist(users); users.length.should.equal(5); - + users[0].name.should.equal('User A'); users[1].name.should.equal('User B'); - + var posts = users[0].posts(); posts.should.be.an.array; posts.should.have.length(3); - + posts[0].title.should.equal('Post C'); posts[1].title.should.equal('Post B'); posts[2].title.should.equal('Post A'); - + var posts = users[1].posts(); posts.should.be.an.array; posts.should.have.length(1); posts[0].title.should.equal('Post D'); - + done(); }); }); - + it('should fetch Users with include scope on Passports - hasMany', function (done) { User.find({ include: {relation: 'passports', scope:{ @@ -212,14 +212,14 @@ describe('include', function () { should.not.exist(err); should.exist(users); users.length.should.equal(5); - + users[0].name.should.equal('User A'); users[0].passports().should.be.empty; - + users[1].name.should.equal('User B'); var passports = users[1].passports(); passports[0].number.should.equal('2'); - + done(); }); }); @@ -317,23 +317,23 @@ describe('include', function () { should.exists(parts); parts.length.should.equal(1); parts[0].partNumber.should.equal('engine'); - + // Create a part assembly.parts.create({partNumber: 'door'}, function (err, part4) { - + Assembly.find({include: 'parts'}, function (err, assemblies) { assemblies.length.should.equal(1); assemblies[0].parts().length.should.equal(2); done(); }); - + }); }); }); }); }); }); - + // Not implemented correctly, see: loopback-datasource-juggler/issues/166 // // it('should support include scope on hasAndBelongsToMany', function (done) { diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index 1d570d13..c3a47e2c 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -25,17 +25,17 @@ describe('ModelBuilder define model', function () { return this.name + ', ' + this.age; }; - modelBuilder.models.should.be.a('object').and.have.property('User', User); - modelBuilder.definitions.should.be.a('object').and.have.property('User'); + modelBuilder.models.should.be.type('object').and.have.property('User').exactly(User); + modelBuilder.definitions.should.be.type('object').and.have.property('User'); var user = new User({name: 'Joe', age: 20, xyz: false}); User.modelName.should.equal('User'); - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.have.property('xyz', false); - user.should.not.have.property('bio'); + user.should.have.property('bio', undefined); done(null, User); }); @@ -47,12 +47,12 @@ describe('ModelBuilder define model', function () { var user = new User({name: 'Joe', age: 20}); User.modelName.should.equal('User'); - user.should.be.a('object'); + user.should.be.type('object'); user.should.have.property('name', 'Joe'); user.should.not.have.property('age'); user.toObject().should.not.have.property('age'); user.toObject(true).should.not.have.property('age'); - user.should.not.have.property('bio'); + user.should.have.property('bio', undefined); done(null, User); }); @@ -102,7 +102,7 @@ describe('ModelBuilder define model', function () { var user = new User({name: 'Joe', age: 20}); User.modelName.should.equal('User'); - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.not.have.property('bio'); @@ -142,7 +142,7 @@ describe('ModelBuilder define model', function () { var user = new User({name: 'Joe', age: 20}); User.modelName.should.equal('User'); - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.not.have.property('bio'); @@ -180,8 +180,8 @@ describe('ModelBuilder define model', function () { return this.name + ', ' + this.age; }; - modelBuilder.models.should.be.a('object').and.have.property('User', User); - modelBuilder.definitions.should.be.a('object').and.have.property('User'); + modelBuilder.models.should.be.type('object').and.have.property('User', User); + modelBuilder.definitions.should.be.type('object').and.have.property('User'); var user = new User({ name: 'Joe', age: 20, @@ -193,10 +193,10 @@ describe('ModelBuilder define model', function () { }); User.modelName.should.equal('User'); - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); - user.should.not.have.property('bio'); + user.should.have.property('bio', undefined); user.should.have.property('address'); user.address.should.have.property('city', 'San Jose'); user.address.should.have.property('state', 'CA'); @@ -236,7 +236,7 @@ describe('ModelBuilder define model', function () { User.modelName.should.equal('User'); User.definition.properties.address.should.have.property('type', Address); - user.should.be.a('object'); + user.should.be.type('object'); assert(user.name === 'Joe'); user.address.should.have.property('city', 'San Jose'); user.address.should.have.property('state', 'CA'); @@ -432,7 +432,7 @@ describe('DataSource define model', function () { User.create({name: 'Joe', age: 20}, function (err, user) { User.modelName.should.equal('User'); - user.should.be.a('object'); + user.should.be.type('object'); assert(user.name === 'Joe'); assert(user.age === undefined); assert(user.toObject().age === undefined); @@ -464,13 +464,13 @@ describe('DataSource define model', function () { User.create({name: 'Joe', age: 20}, function (err, user) { - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.not.have.property('bio'); User.findById(user.id, function (err, user) { - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.not.have.property('bio'); @@ -487,7 +487,7 @@ describe('DataSource define model', function () { User.create({name: 'Joe', age: 20}, function (err, user) { User.modelName.should.equal('User'); - user.should.be.a('object').and.have.property('name', 'Joe'); + user.should.be.type('object').and.have.property('name', 'Joe'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.should.not.have.property('bio'); @@ -504,7 +504,7 @@ describe('DataSource define model', function () { var user = new User({name: 'Joe', age: 20}); User.modelName.should.equal('User'); - user.should.be.a('object'); + user.should.be.type('object'); assert(user.name === 'Joe'); assert(user.age === undefined); assert(user.toObject().age === undefined); @@ -550,7 +550,7 @@ describe('DataSource define model', function () { var user = new User({name: 'Joe', age: 20}, {strict: false}); user.should.have.property('__strict', false); - user.should.be.a('object'); + user.should.be.type('object'); user.should.have.property('name', 'Joe'); user.should.have.property('age', 20); user.toObject().should.have.property('age', 20); @@ -622,11 +622,11 @@ describe('DataSource define model', function () { done(); }); - + it('should allow an explicit remoting path', function () { var ds = new DataSource('memory'); - - var User = ds.define('User', {name: String, bio: String}, { + + var User = ds.define('User', {name: String, bio: String}, { http: { path: 'accounts' } }); User.http.path.should.equal('/accounts'); @@ -652,7 +652,7 @@ describe('Load models with base', function () { assert(Customer.prototype.instanceMethod === User.prototype.instanceMethod); assert.equal(Customer.base, User); assert.equal(Customer.base, Customer.super_); - + try { var Customer1 = ds.define('Customer1', {vip: Boolean}, {base: 'User1'}); } catch (e) { @@ -949,37 +949,37 @@ describe('Load models with relations', function () { assert(Post.relations['user']); done(); }); - + it('should set up referencesMany relations', function (done) { var ds = new DataSource('memory'); - + var Post = ds.define('Post', {userId: Number, content: String}); var User = ds.define('User', {name: String}, {relations: {posts: {type: 'referencesMany', model: 'Post'}}}); - + assert(User.relations['posts']); done(); }); - + it('should set up embedsMany relations', function (done) { var ds = new DataSource('memory'); - + var Post = ds.define('Post', {userId: Number, content: String}); var User = ds.define('User', {name: String}, {relations: {posts: {type: 'embedsMany', model: 'Post' }}}); - + assert(User.relations['posts']); done(); }); - + it('should set up polymorphic relations', function (done) { var ds = new DataSource('memory'); - + var Author = ds.define('Author', {name: String}, {relations: { pictures: {type: 'hasMany', model: 'Picture', polymorphic: 'imageable'} }}); var Picture = ds.define('Picture', {name: String}, {relations: { imageable: {type: 'belongsTo', polymorphic: true} }}); - + assert(Author.relations['pictures']); assert.deepEqual(Author.relations['pictures'].toJSON(), { name: 'pictures', @@ -989,13 +989,13 @@ describe('Load models with relations', function () { modelTo: 'Picture', keyTo: 'imageableId', multiple: true, - polymorphic: { + polymorphic: { as: 'imageable', foreignKey: 'imageableId', discriminator: 'imageableType' } }); - + assert(Picture.relations['imageable']); assert.deepEqual(Picture.relations['imageable'].toJSON(), { name: 'imageable', @@ -1005,7 +1005,7 @@ describe('Load models with relations', function () { modelTo: '', keyTo: 'id', multiple: false, - polymorphic: { + polymorphic: { as: 'imageable', foreignKey: 'imageableId', discriminator: 'imageableType' @@ -1013,7 +1013,7 @@ describe('Load models with relations', function () { }); done(); }); - + it('should set up foreign key with the correct type', function (done) { var ds = new DataSource('memory'); @@ -1533,11 +1533,11 @@ describe('Load models from json', function () { var customer = new Customer({name: 'Joe', age: 20, customerId: 'c01'}); - customer.should.be.a('object').and.have.property('name', 'Joe'); + customer.should.be.type('object').and.have.property('name', 'Joe'); customer.should.have.property('name', 'Joe'); customer.should.have.property('age', 20); customer.should.have.property('customerId', 'c01'); - customer.should.not.have.property('bio'); + customer.should.have.property('bio', undefined); // The properties are defined at prototype level assert.equal(Object.keys(customer).filter(function (k) { diff --git a/test/relations.test.js b/test/relations.test.js index 23ceb8ad..4f66871f 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -47,8 +47,8 @@ describe('relations', function () { b.chapters.should.be.an.instanceOf(Function); b.users.should.be.an.instanceOf(Function); b.authors.should.be.an.instanceOf(Function); - Object.keys((new Chapter).toObject()).should.include('bookId'); - Object.keys((new Author).toObject()).should.include('projectId'); + Object.keys((new Chapter).toObject()).should.containEql('bookId'); + Object.keys((new Author).toObject()).should.containEql('projectId'); db.automigrate(done); }); @@ -56,7 +56,7 @@ describe('relations', function () { it('can be declared in short form', function (done) { Author.hasMany('readers'); (new Author).readers.should.be.an.instanceOf(Function); - Object.keys((new Reader).toObject()).should.include('authorId'); + Object.keys((new Reader).toObject()).should.containEql('authorId'); db.autoupdate(done); }); @@ -286,7 +286,7 @@ describe('relations', function () { return new Date(); }}}); Address = db.define('Address', {name: String}); - + Physician.hasMany(Patient, {through: Appointment}); Patient.hasMany(Physician, {through: Appointment}); Patient.belongsTo(Address); @@ -356,10 +356,10 @@ describe('relations', function () { }); function verify(physician) { physician.patients(function (err, ch) { - + var patients = physician.patients(); patients.should.eql(ch); - + should.not.exist(err); should.exist(ch); ch.should.have.lengthOf(3); @@ -706,7 +706,7 @@ describe('relations', function () { Book.hasMany(Chapter, { properties: { type: 'bookType' } }); db.automigrate(done); }); - + it('should create record on scope', function (done) { Book.create({ type: 'fiction' }, function (err, book) { book.chapters.create(function (err, c) { @@ -738,7 +738,7 @@ describe('relations', function () { }); db.automigrate(done); }); - + it('should create record on scope', function (done) { Category.create(function (err, c) { c.jobs.create({ type: 'book' }, function(err, p) { @@ -752,7 +752,7 @@ describe('relations', function () { }); }); }); - + it('should find records on scope', function (done) { Category.findOne(function (err, c) { c.jobs(function(err, jobs) { @@ -761,7 +761,7 @@ describe('relations', function () { }); }); }); - + it('should find record on scope - filtered', function (done) { Category.findOne(function (err, c) { c.jobs({ where: { type: 'book' } }, function(err, jobs) { @@ -771,7 +771,7 @@ describe('relations', function () { }); }); }); - + // So why not just do the above? In LoopBack, the context // that gets passed into a beforeRemote handler contains // a reference to the parent scope/instance: ctx.instance @@ -780,7 +780,7 @@ describe('relations', function () { // handler. Optionally,properties dynamic properties can be declared. // // The code below simulates this. - + it('should create record on scope - properties', function (done) { Category.findOne(function (err, c) { c.jobType = 'tool'; // temporary @@ -791,7 +791,7 @@ describe('relations', function () { }); }); }); - + it('should find records on scope', function (done) { Category.findOne(function (err, c) { c.jobs(function(err, jobs) { @@ -800,7 +800,7 @@ describe('relations', function () { }); }); }); - + it('should find record on scope - scoped', function (done) { Category.findOne(function (err, c) { c.jobType = 'book'; // temporary, for scoping @@ -811,7 +811,7 @@ describe('relations', function () { }); }); }); - + it('should find record on scope - scoped', function (done) { Category.findOne(function (err, c) { c.jobType = 'tool'; // temporary, for scoping @@ -832,7 +832,7 @@ describe('relations', function () { }); }); }); - + it('should delete records on scope - scoped', function (done) { Category.findOne(function (err, c) { c.jobType = 'tool'; // temporary, for scoping @@ -841,7 +841,7 @@ describe('relations', function () { }); }); }); - + it('should find record on scope - verify', function (done) { Category.findOne(function (err, c) { c.jobs(function(err, jobs) { @@ -850,9 +850,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('polymorphic hasOne', function () { before(function (done) { db = getSchema(); @@ -875,7 +875,7 @@ describe('relations', function () { Picture.belongsTo('imageable', { polymorphic: true }); db.automigrate(done); }); - + it('should create polymorphic relation - author', function (done) { Author.create({name: 'Author 1' }, function (err, author) { author.avatar.create({ name: 'Avatar' }, function (err, p) { @@ -887,7 +887,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic relation - reader', function (done) { Reader.create({name: 'Reader 1' }, function (err, reader) { reader.mugshot.create({ name: 'Mugshot' }, function (err, p) { @@ -899,15 +899,15 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic relation - author', function (done) { Author.findOne(function (err, author) { author.avatar(function (err, p) { should.not.exist(err); - + var avatar = author.avatar(); avatar.should.equal(p); - + p.name.should.equal('Avatar'); p.imageableId.should.eql(author.id); p.imageableType.should.equal('Author'); @@ -915,7 +915,7 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic relation - reader', function (done) { Reader.findOne(function (err, reader) { reader.mugshot(function (err, p) { @@ -927,7 +927,7 @@ describe('relations', function () { }); }); }); - + it('should find inverse polymorphic relation - author', function (done) { Picture.findOne({ where: { name: 'Avatar' } }, function (err, p) { p.imageable(function (err, imageable) { @@ -938,7 +938,7 @@ describe('relations', function () { }); }); }); - + it('should find inverse polymorphic relation - reader', function (done) { Picture.findOne({ where: { name: 'Mugshot' } }, function (err, p) { p.imageable(function (err, imageable) { @@ -949,9 +949,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('polymorphic hasOne with non standard ids', function () { before(function (done) { db = getSchema(); @@ -964,7 +964,7 @@ describe('relations', function () { username: {type: String, id: true}, name: String }); - + db.automigrate(function () { Picture.destroyAll(function () { Author.destroyAll(function () { @@ -973,7 +973,7 @@ describe('relations', function () { }); }); }); - + it('can be declared with non standard foreign key', function (done) { Author.hasOne(Picture, { as: 'avatar', @@ -999,7 +999,7 @@ describe('relations', function () { }); db.automigrate(done); }); - + it('should create polymorphic relation - author', function (done) { Author.create({name: 'Author 1' }, function (err, author) { author.avatar.create({ name: 'Avatar' }, function (err, p) { @@ -1011,7 +1011,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic relation - reader', function (done) { Reader.create({name: 'Reader 1' }, function (err, reader) { reader.mugshot.create({ name: 'Mugshot' }, function (err, p) { @@ -1023,15 +1023,15 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic relation - author', function (done) { Author.findOne(function (err, author) { author.avatar(function (err, p) { should.not.exist(err); - + var avatar = author.avatar(); avatar.should.equal(p); - + p.name.should.equal('Avatar'); p.oid.should.eql(author.username); p.type.should.equal('Author'); @@ -1039,7 +1039,7 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic relation - reader', function (done) { Reader.findOne(function (err, reader) { reader.mugshot(function (err, p) { @@ -1051,7 +1051,7 @@ describe('relations', function () { }); }); }); - + it('should find inverse polymorphic relation - author', function (done) { Picture.findOne({ where: { name: 'Avatar' } }, function (err, p) { p.owner(function (err, owner) { @@ -1062,7 +1062,7 @@ describe('relations', function () { }); }); }); - + it('should find inverse polymorphic relation - reader', function (done) { Picture.findOne({ where: { name: 'Mugshot' } }, function (err, p) { p.owner(function (err, owner) { @@ -1073,9 +1073,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('polymorphic hasMany', function () { before(function (done) { db = getSchema(); @@ -1099,7 +1099,7 @@ describe('relations', function () { discriminator: 'imageableType' } }); Picture.belongsTo('imageable', { polymorphic: true }); - + Author.relations['pictures'].toJSON().should.eql({ name: 'pictures', type: 'hasMany', @@ -1108,13 +1108,13 @@ describe('relations', function () { modelTo: 'Picture', keyTo: 'imageableId', multiple: true, - polymorphic: { + polymorphic: { as: 'imageable', foreignKey: 'imageableId', discriminator: 'imageableType' } }); - + Picture.relations['imageable'].toJSON().should.eql({ name: 'imageable', type: 'belongsTo', @@ -1123,16 +1123,16 @@ describe('relations', function () { modelTo: '', keyTo: 'id', multiple: false, - polymorphic: { + polymorphic: { as: 'imageable', foreignKey: 'imageableId', discriminator: 'imageableType' } }); - + db.automigrate(done); }); - + it('should create polymorphic relation - author', function (done) { Author.create({ name: 'Author 1' }, function (err, author) { author.pictures.create({ name: 'Author Pic' }, function (err, p) { @@ -1144,7 +1144,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic relation - reader', function (done) { Reader.create({ name: 'Reader 1' }, function (err, reader) { reader.pictures.create({ name: 'Reader Pic' }, function (err, p) { @@ -1156,22 +1156,22 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic items - author', function (done) { Author.findOne(function (err, author) { author.pictures(function (err, pics) { should.not.exist(err); - + var pictures = author.pictures(); pictures.should.eql(pics); - + pics.should.have.length(1); pics[0].name.should.equal('Author Pic'); done(); }); }); }); - + it('should find polymorphic items - reader', function (done) { Reader.findOne(function (err, reader) { reader.pictures(function (err, pics) { @@ -1182,7 +1182,7 @@ describe('relations', function () { }); }); }); - + it('should find the inverse of polymorphic relation - author', function (done) { Picture.findOne({ where: { name: 'Author Pic' } }, function (err, p) { should.not.exist(err); @@ -1195,7 +1195,7 @@ describe('relations', function () { }); }); }); - + it('should find the inverse of polymorphic relation - reader', function (done) { Picture.findOne({ where: { name: 'Reader Pic' } }, function (err, p) { should.not.exist(err); @@ -1208,7 +1208,7 @@ describe('relations', function () { }); }); }); - + it('should include the inverse of polymorphic relation', function (done) { Picture.find({ include: 'imageable' }, function (err, pics) { should.not.exist(err); @@ -1220,7 +1220,7 @@ describe('relations', function () { done(); }); }); - + it('should assign a polymorphic relation', function(done) { Author.create({ name: 'Author 2' }, function(err, author) { var p = new Picture({ name: 'Sample' }); @@ -1230,7 +1230,7 @@ describe('relations', function () { p.save(done); }); }); - + it('should find polymorphic items - author', function (done) { Author.findOne({ where: { name: 'Author 2' } }, function (err, author) { author.pictures(function (err, pics) { @@ -1241,7 +1241,7 @@ describe('relations', function () { }); }); }); - + it('should find the inverse of polymorphic relation - author', function (done) { Picture.findOne({ where: { name: 'Sample' } }, function (err, p) { should.not.exist(err); @@ -1254,9 +1254,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('polymorphic hasAndBelongsToMany through', function () { before(function (done) { db = getSchema(); @@ -1324,7 +1324,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic relation - reader', function (done) { Reader.create({ name: 'Reader 1' }, function (err, r) { should.not.exist(err); @@ -1336,7 +1336,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic through model', function (done) { PictureLink.findOne(function(err, link) { should.not.exist(err); @@ -1350,7 +1350,7 @@ describe('relations', function () { }); }); }); - + it('should get polymorphic relation through model - author', function (done) { Author.findById(author.id, function(err, author) { should.not.exist(err); @@ -1364,7 +1364,7 @@ describe('relations', function () { }); }); }); - + it('should get polymorphic relation through model - reader', function (done) { Reader.findById(reader.id, function(err, reader) { should.not.exist(err); @@ -1377,7 +1377,7 @@ describe('relations', function () { }); }); }); - + it('should include polymorphic items', function (done) { Author.find({ include: 'pictures' }, function(err, authors) { authors.should.have.length(1); @@ -1407,7 +1407,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic through model', function (done) { PictureLink.findOne({ where: { pictureId: anotherPicture.id, imageableType: 'Author' } }, function(err, link) { should.not.exist(err); @@ -1429,7 +1429,7 @@ describe('relations', function () { }); }); }); - + it('should add to a polymorphic relation - author', function (done) { Reader.create({name: 'Reader 2' }, function (err, reader) { should.not.exist(err); @@ -1440,7 +1440,7 @@ describe('relations', function () { }); }); }); - + it('should get the inverse polymorphic relation - author', function (done) { Picture.findById(anotherPicture.id, function(err, p) { p.authors(function(err, authors) { @@ -1451,7 +1451,7 @@ describe('relations', function () { }); }); }); - + it('should get the inverse polymorphic relation - reader', function (done) { Picture.findById(anotherPicture.id, function(err, p) { p.readers(function(err, readers) { @@ -1461,7 +1461,7 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic items - author', function (done) { Author.findById(author.id, function(err, author) { author.pictures(function(err, pics) { @@ -1473,7 +1473,7 @@ describe('relations', function () { }); }); }); - + it('should check if polymorphic relation exists - author', function (done) { Author.findById(author.id, function(err, author) { author.pictures.exists(anotherPicture.id, function(err, exists) { @@ -1482,7 +1482,7 @@ describe('relations', function () { }); }); }); - + it('should remove from a polymorphic relation - author', function (done) { Author.findById(author.id, function(err, author) { author.pictures.remove(anotherPicture.id, function(err) { @@ -1491,7 +1491,7 @@ describe('relations', function () { }); }); }); - + it('should find polymorphic items - author', function (done) { Author.findById(author.id, function(err, author) { author.pictures(function(err, pics) { @@ -1502,7 +1502,7 @@ describe('relations', function () { }); }); }); - + it('should check if polymorphic relation exists - author', function (done) { Author.findById(author.id, function(err, author) { author.pictures.exists(7, function(err, exists) { @@ -1511,7 +1511,7 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic item through relation scope', function (done) { Picture.findById(anotherPicture.id, function(err, p) { p.authors.create({ name: 'Author 3' }, function(err, a) { @@ -1522,9 +1522,9 @@ describe('relations', function () { }); }); }); - + it('should create polymorphic through model - new author', function (done) { - PictureLink.findOne({ where: { + PictureLink.findOne({ where: { pictureId: anotherPicture.id, imageableId: author.id, imageableType: 'Author' } }, function(err, link) { should.not.exist(err); @@ -1534,7 +1534,7 @@ describe('relations', function () { done(); }); }); - + it('should find polymorphic items - new author', function (done) { Author.findById(author.id, function(err, author) { author.pictures(function(err, pics) { @@ -1545,12 +1545,12 @@ describe('relations', function () { }); }); }); - + }); describe('belongsTo', function () { var List, Item, Fear, Mind; - + var listId, itemId; it('can be declared in different ways', function () { @@ -1561,12 +1561,12 @@ describe('relations', function () { // syntax 1 (old) Item.belongsTo(List); - Object.keys((new Item).toObject()).should.include('listId'); + Object.keys((new Item).toObject()).should.containEql('listId'); (new Item).list.should.be.an.instanceOf(Function); // syntax 2 (new) Fear.belongsTo('mind'); - Object.keys((new Fear).toObject()).should.include('mindId'); + Object.keys((new Fear).toObject()).should.containEql('mindId'); (new Fear).mind.should.be.an.instanceOf(Function); // (new Fear).mind.build().should.be.an.instanceOf(Mind); }); @@ -1607,7 +1607,7 @@ describe('relations', function () { }); }); }); - + it('should update related item on scope', function(done) { Item.findById(itemId, function (e, todo) { todo.list.update({name: 'List A'}, function(err, list) { @@ -1618,7 +1618,7 @@ describe('relations', function () { }); }); }); - + it('should get related item on scope', function(done) { Item.findById(itemId, function (e, todo) { todo.list(function(err, list) { @@ -1629,7 +1629,7 @@ describe('relations', function () { }); }); }); - + it('should destroy related item on scope', function(done) { Item.findById(itemId, function (e, todo) { todo.list.destroy(function(err) { @@ -1638,7 +1638,7 @@ describe('relations', function () { }); }); }); - + it('should get related item on scope - verify', function(done) { Item.findById(itemId, function (e, todo) { todo.list(function(err, list) { @@ -1648,7 +1648,7 @@ describe('relations', function () { }); }); }); - + it('should not have deleted related item', function(done) { List.findById(listId, function (e, list) { should.not.exist(e); @@ -1675,10 +1675,10 @@ describe('relations', function () { }); }); - + describe('belongsTo with scope', function () { var Person, Passport; - + it('can be declared with scope and properties', function (done) { Person = db.define('Person', {name: String, age: Number, passportNotes: String}); Passport = db.define('Passport', {name: String, notes: String}); @@ -1703,19 +1703,19 @@ describe('relations', function () { }); }); }); - + it('should find record on scope', function (done) { Passport.findOne(function (err, p) { p.personId.should.eql(personCreated.id); p.person(function(err, person) { person.name.should.equal('Fred'); - person.should.not.have.property('age'); - person.should.not.have.property('passportNotes'); + person.should.have.property('age', undefined); + person.should.have.property('passportNotes', undefined); done(); }); }); }); - + }); describe('belongsTo with embed', function () { @@ -1769,7 +1769,7 @@ describe('relations', function () { it('can be declared using hasOne method', function () { Supplier.hasOne(Account, { properties: { name: 'supplierName' } }); - Object.keys((new Account()).toObject()).should.include('supplierId'); + Object.keys((new Account()).toObject()).should.containEql('supplierId'); (new Supplier()).account.should.be.an.instanceOf(Function); }); @@ -1797,7 +1797,7 @@ describe('relations', function () { it('should set targetClass on scope property', function() { should.equal(Supplier.prototype.account._targetClass, 'Account'); }); - + it('should update the related item on scope', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1827,7 +1827,7 @@ describe('relations', function () { }); }); }); - + it('should get the related item on scope', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1840,7 +1840,7 @@ describe('relations', function () { }); }); }); - + it('should destroy the related item on scope', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1851,7 +1851,7 @@ describe('relations', function () { }); }); }); - + it('should get the related item on scope - verify', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1863,7 +1863,7 @@ describe('relations', function () { }); }); }); - + it('should have deleted related item', function(done) { Supplier.findById(supplierId, function (e, supplier) { should.not.exist(e); @@ -1919,11 +1919,11 @@ describe('relations', function () { }); }); - + describe('hasOne with non standard id', function () { var Supplier, Account; var supplierId, accountId; - + before(function () { db = getSchema(); Supplier = db.define('Supplier', { @@ -1942,16 +1942,16 @@ describe('relations', function () { supplierName: String }); }); - + it('can be declared with non standard foreignKey', function () { Supplier.hasOne(Account, { properties: {name: 'supplierName'}, foreignKey: 'sid' }); - Object.keys((new Account()).toObject()).should.include('sid'); + Object.keys((new Account()).toObject()).should.containEql('sid'); (new Supplier()).account.should.be.an.instanceOf(Function); }); - + it('can be used to query data', function (done) { db.automigrate(function () { Supplier.create({name: 'Supplier 1'}, function (e, supplier) { @@ -1972,7 +1972,7 @@ describe('relations', function () { }); }); }); - + it('should destroy the related item on scope', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1983,7 +1983,7 @@ describe('relations', function () { }); }); }); - + it('should get the related item on scope - verify', function(done) { Supplier.findById(supplierId, function(e, supplier) { should.not.exist(e); @@ -1995,7 +1995,7 @@ describe('relations', function () { }); }); }); - + it('should have deleted related item', function(done) { Supplier.findById(supplierId, function (e, supplier) { should.not.exist(e); @@ -2003,9 +2003,9 @@ describe('relations', function () { done(); }); }); - + }); - + describe('hasAndBelongsToMany', function () { var Article, TagName, ArticleTag; it('can be declared', function (done) { @@ -2041,9 +2041,9 @@ describe('relations', function () { article.tagNames(function (e, tags) { should.not.exist(e); should.exist(tags); - + article.tagNames().should.eql(tags); - + done(); }); }); @@ -2084,19 +2084,19 @@ describe('relations', function () { should.equal(Article.prototype.tagNames._targetClass, 'TagName'); }); }); - + describe('embedsOne', function () { - + var person; var Passport; var Other; - + before(function () { tmp = getTransientDataSource(); db = getSchema(); Person = db.define('Person', {name: String}); Passport = tmp.define('Passport', - {name:{type:'string', required: true}}, + {name:{type:'string', required: true}}, {idInjection: false} ); Address = tmp.define('Address', { street: String }, { idInjection: false }); @@ -2110,7 +2110,7 @@ describe('relations', function () { Person.embedsOne(Address); // all by default db.automigrate(done); }); - + it('should have setup a property and accessor', function() { var p = new Person(); p.passport.should.be.an.object; // because of default @@ -2132,7 +2132,7 @@ describe('relations', function () { done(); }); }); - + it('should return an instance with default values', function() { var p = new Person(); p.passport.toObject().should.eql({name: 'Anonymous'}); @@ -2142,14 +2142,14 @@ describe('relations', function () { passport.should.equal(p.passport); }); }); - + it('should embed a model instance', function() { var p = new Person(); p.passportItem(new Passport({name: 'Fred'})); p.passport.toObject().should.eql({name: 'Fred'}); p.passport.should.be.an.instanceOf(Passport); }); - + it('should not embed an invalid model type', function() { var p = new Person(); p.passportItem(new Other()); @@ -2170,7 +2170,7 @@ describe('relations', function () { }); }); }); - + it('should get an embedded item on scope', function(done) { Person.findById(personId, function(err, p) { should.not.exist(err); @@ -2182,7 +2182,7 @@ describe('relations', function () { done(); }); }); - + it('should validate an embedded item on scope - on creation', function(done) { var p = new Person({name: 'Fred'}); p.passportItem.create({}, function(err, passport) { @@ -2192,7 +2192,7 @@ describe('relations', function () { done(); }); }); - + it('should validate an embedded item on scope - on update', function(done) { Person.findById(personId, function(err, p) { var passport = p.passportItem(); @@ -2206,7 +2206,7 @@ describe('relations', function () { }); }); }); - + it('should update an embedded item on scope', function(done) { Person.findById(personId, function(err, p) { p.passportItem.update({name: 'Freddy'}, function(err, passport) { @@ -2219,7 +2219,7 @@ describe('relations', function () { }); }); }); - + it('should get an embedded item on scope - verify', function(done) { Person.findById(personId, function(err, p) { should.not.exist(err); @@ -2228,7 +2228,7 @@ describe('relations', function () { done(); }); }); - + it('should destroy an embedded item on scope', function(done) { Person.findById(personId, function(err, p) { p.passportItem.destroy(function(err) { @@ -2238,7 +2238,7 @@ describe('relations', function () { }); }); }); - + it('should get an embedded item on scope - verify', function(done) { Person.findById(personId, function(err, p) { should.not.exist(err); @@ -2246,15 +2246,15 @@ describe('relations', function () { done(); }); }); - + }); - + describe('embedsOne - persisted model', function () { - + // This test spefically uses the Memory connector // in order to test the use of the auto-generated // id, in the sequence of the related model. - + before(function () { db = getMemoryDataSource(); Person = db.define('Person', {name: String}); @@ -2269,7 +2269,7 @@ describe('relations', function () { }); db.automigrate(done); }); - + it('should create an item - to offset id', function(done) { Passport.create({name:'Wilma'}, function(err, p) { should.not.exist(err); @@ -2278,7 +2278,7 @@ describe('relations', function () { done(); }); }); - + it('should create an embedded item on scope', function(done) { Person.create({name: 'Fred'}, function(err, p) { should.not.exist(err); @@ -2290,11 +2290,11 @@ describe('relations', function () { }); }); }); - + }); - + describe('embedsOne - generated id', function () { - + before(function () { tmp = getTransientDataSource(); db = getSchema(); @@ -2309,7 +2309,7 @@ describe('relations', function () { Person.embedsOne(Passport); db.automigrate(done); }); - + it('should create an embedded item on scope', function(done) { Person.create({name: 'Fred'}, function(err, p) { should.not.exist(err); @@ -2321,13 +2321,13 @@ describe('relations', function () { }); }); }); - + }); - + describe('embedsMany', function () { - + var address1, address2; - + before(function (done) { tmp = getTransientDataSource({defaultIdType: Number}); db = getSchema(); @@ -2344,7 +2344,7 @@ describe('relations', function () { Person.embedsMany(Address); db.automigrate(done); }); - + it('should have setup embedded accessor/scope', function() { var p = new Person({ name: 'Fred' }); p.addresses.should.be.an.array; @@ -2369,7 +2369,7 @@ describe('relations', function () { }); }); }); - + it('should create embedded items on scope', function(done) { Person.findOne(function(err, p) { p.addressList.create({ street: 'Street 2' }, function(err, address) { @@ -2381,18 +2381,18 @@ describe('relations', function () { }); }); }); - + it('should return embedded items from scope', function(done) { Person.findOne(function(err, p) { p.addressList(function(err, addresses) { should.not.exist(err); - + var list = p.addressList(); list.should.equal(addresses); list.should.equal(p.addresses); - + p.addressList.value().should.equal(list); - + addresses.should.have.length(2); addresses[0].id.should.eql(address1.id); addresses[0].street.should.equal('Street 1'); @@ -2402,7 +2402,7 @@ describe('relations', function () { }); }); }); - + it('should filter embedded items on scope', function(done) { Person.findOne(function(err, p) { p.addressList({ where: { street: 'Street 2' } }, function(err, addresses) { @@ -2414,7 +2414,7 @@ describe('relations', function () { }); }); }); - + it('should validate embedded items', function(done) { Person.findOne(function(err, p) { p.addressList.create({}, function(err, address) { @@ -2426,7 +2426,7 @@ describe('relations', function () { }); }); }); - + it('should find embedded items by id', function(done) { Person.findOne(function(err, p) { p.addressList.findById(address2.id, function(err, address) { @@ -2437,7 +2437,7 @@ describe('relations', function () { }); }); }); - + it('should check if item exists', function(done) { Person.findOne(function(err, p) { p.addressList.exists(address2.id, function(err, exists) { @@ -2447,7 +2447,7 @@ describe('relations', function () { }); }); }); - + it('should update embedded items by id', function(done) { Person.findOne(function(err, p) { p.addressList.updateById(address2.id, { street: 'New Street' }, function(err, address) { @@ -2458,7 +2458,7 @@ describe('relations', function () { }); }); }); - + it('should validate the update of embedded items', function(done) { Person.findOne(function(err, p) { p.addressList.updateById(address2.id, { street: null }, function(err, address) { @@ -2468,7 +2468,7 @@ describe('relations', function () { }); }); }); - + it('should find embedded items by id - verify', function(done) { Person.findOne(function(err, p) { p.addressList.findById(address2.id, function(err, address) { @@ -2479,7 +2479,7 @@ describe('relations', function () { }); }); }); - + it('should have accessors: at, get, set', function(done) { Person.findOne(function(err, p) { p.addressList.at(0).id.should.equal(address1.id); @@ -2493,7 +2493,7 @@ describe('relations', function () { done(); }); }); - + it('should remove embedded items by id', function(done) { Person.findOne(function(err, p) { p.addresses.should.have.length(2); @@ -2504,18 +2504,18 @@ describe('relations', function () { }); }); }); - + it('should have embedded items - verify', function(done) { Person.findOne(function(err, p) { p.addresses.should.have.length(1); done(); }); }); - + }); - + describe('embedsMany - numeric ids + forceId', function () { - + before(function (done) { tmp = getTransientDataSource(); db = getSchema(); @@ -2534,7 +2534,7 @@ describe('relations', function () { Person.embedsMany(Address, {options: {forceId: true}}); db.automigrate(done); }); - + it('should create embedded items on scope', function(done) { Person.create({ name: 'Fred' }, function(err, p) { p.addressList.create({ street: 'Street 1' }, function(err, address) { @@ -2550,9 +2550,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('embedsMany - explicit ids', function () { before(function (done) { tmp = getTransientDataSource(); @@ -2570,7 +2570,7 @@ describe('relations', function () { Person.embedsMany(Address); db.automigrate(done); }); - + it('should create embedded items on scope', function(done) { Person.create({ name: 'Fred' }, function(err, p) { p.addressList.create({ id: 'home', street: 'Street 1' }, function(err, address) { @@ -2584,7 +2584,7 @@ describe('relations', function () { }); }); }); - + it('should find embedded items by id', function(done) { Person.findOne(function(err, p) { p.addressList.findById('work', function(err, address) { @@ -2595,7 +2595,7 @@ describe('relations', function () { }); }); }); - + it('should check for duplicate ids', function(done) { Person.findOne(function(err, p) { p.addressList.create({ id: 'home', street: 'Invalid' }, function(err, addresses) { @@ -2606,7 +2606,7 @@ describe('relations', function () { }); }); }); - + it('should update embedded items by id', function(done) { Person.findOne(function(err, p) { p.addressList.updateById('home', { street: 'New Street' }, function(err, address) { @@ -2617,7 +2617,7 @@ describe('relations', function () { }); }); }); - + it('should remove embedded items by id', function(done) { Person.findOne(function(err, p) { p.addresses.should.have.length(2); @@ -2628,14 +2628,14 @@ describe('relations', function () { }); }); }); - + it('should have embedded items - verify', function(done) { Person.findOne(function(err, p) { p.addresses.should.have.length(1); done(); }); }); - + it('should validate all embedded items', function(done) { var addresses = []; addresses.push({ id: 'home', street: 'Home Street' }); @@ -2648,7 +2648,7 @@ describe('relations', function () { done(); }); }); - + it('should build embedded items', function(done) { Person.create({ name: 'Wilma' }, function(err, p) { p.addressList.build({ id: 'home', street: 'Home' }); @@ -2659,7 +2659,7 @@ describe('relations', function () { }); }); }); - + it('should have embedded items - verify', function(done) { Person.findOne({ where: { name: 'Wilma' } }, function(err, p) { p.name.should.equal('Wilma'); @@ -2671,7 +2671,7 @@ describe('relations', function () { done(); }); }); - + it('should have accessors: at, get, set', function(done) { Person.findOne({ where: { name: 'Wilma' } }, function(err, p) { p.name.should.equal('Wilma'); @@ -2685,7 +2685,7 @@ describe('relations', function () { done(); }); }); - + it('should create embedded from attributes - property name', function(done) { var addresses = [ {id: 'home', street: 'Home Street'}, @@ -2698,7 +2698,7 @@ describe('relations', function () { done(); }); }); - + it('should not create embedded from attributes - relation name', function(done) { var addresses = [ {id: 'home', street: 'Home Street'}, @@ -2710,7 +2710,7 @@ describe('relations', function () { done(); }); }); - + it('should create embedded items with auto-generated id', function(done) { Person.create({ name: 'Wilma' }, function(err, p) { p.addressList.create({ street: 'Home Street 1' }, function(err, address) { @@ -2721,18 +2721,18 @@ describe('relations', function () { }); }); }); - + }); - + describe('embedsMany - persisted model', function () { - + var address0, address1, address2; var person; - + // This test spefically uses the Memory connector // in order to test the use of the auto-generated // id, in the sequence of the related model. - + before(function (done) { db = getMemoryDataSource(); Person = db.define('Person', {name: String}); @@ -2748,12 +2748,12 @@ describe('relations', function () { // to save related model itself, set // persistent: true Person.embedsMany(Address, { - scope: {order: 'street'}, + scope: {order: 'street'}, options: {persistent: true} }); db.automigrate(done); }); - + it('should create individual items (0)', function(done) { Address.create({ street: 'Street 0' }, function(err, inst) { inst.id.should.equal(1); // offset sequence @@ -2761,7 +2761,7 @@ describe('relations', function () { done(); }); }); - + it('should create individual items (1)', function(done) { Address.create({ street: 'Street 1' }, function(err, inst) { inst.id.should.equal(2); @@ -2769,7 +2769,7 @@ describe('relations', function () { done(); }); }); - + it('should create individual items (2)', function(done) { Address.create({ street: 'Street 2' }, function(err, inst) { inst.id.should.equal(3); @@ -2777,14 +2777,14 @@ describe('relations', function () { done(); }); }); - + it('should create individual items (3)', function(done) { Address.create({ street: 'Street 3' }, function(err, inst) { inst.id.should.equal(4); // offset sequence done(); }); }); - + it('should add embedded items on scope', function(done) { Person.create({ name: 'Fred' }, function(err, p) { person = p; @@ -2801,7 +2801,7 @@ describe('relations', function () { }); }); }); - + it('should create embedded items on scope', function(done) { Person.findById(person.id, function(err, p) { p.addressList.create({ street: 'Street 4' }, function(err, address) { @@ -2812,7 +2812,7 @@ describe('relations', function () { }); }); }); - + it('should have embedded items on scope', function(done) { Person.findById(person.id, function(err, p) { p.addressList(function(err, addresses) { @@ -2825,7 +2825,7 @@ describe('relations', function () { }); }); }); - + it('should validate embedded items on scope - id', function(done) { Person.create({ name: 'Wilma' }, function(err, p) { p.addressList.create({ id: null, street: 'Street 1' }, function(err, address) { @@ -2835,7 +2835,7 @@ describe('relations', function () { }); }); }); - + it('should validate embedded items on scope - street', function(done) { Person.create({ name: 'Wilma' }, function(err, p) { p.addressList.create({ id: 1234 }, function(err, address) { @@ -2849,27 +2849,27 @@ describe('relations', function () { }); }); }); - + }); - + describe('embedsMany - relations, scope and properties', function () { - + var category, job1, job2, job3; - + before(function () { db = getSchema(); Category = db.define('Category', {name: String}); Job = db.define('Job', {name: String}); Link = db.define('Link', {name: String, notes: String}); }); - + it('can be declared', function (done) { - Category.embedsMany(Link, { + Category.embedsMany(Link, { as: 'items', // rename scope: { include: 'job' }, // always include options: { belongsTo: 'job' } // optional, for add()/remove() }); - Link.belongsTo(Job, { + Link.belongsTo(Job, { foreignKey: 'id', // re-use the actual job id properties: { id: 'id', name: 'name' }, // denormalize, transfer id options: { invertProperties: true } @@ -2878,7 +2878,7 @@ describe('relations', function () { Job.create({ name: 'Job 0' }, done); // offset ids for tests }); }); - + it('should setup related items', function(done) { Job.create({ name: 'Job 1' }, function(err, p) { job1 = p; @@ -2891,7 +2891,7 @@ describe('relations', function () { }); }); }); - + it('should associate items on scope', function(done) { Category.create({ name: 'Category A' }, function(err, cat) { var link = cat.items.build(); @@ -2911,22 +2911,22 @@ describe('relations', function () { }); }); }); - + it('should include related items on scope', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(2); - + // denormalized properties: cat.items.at(0).should.be.instanceof(Link); cat.items.at(0).id.should.eql(job1.id); cat.items.at(0).name.should.equal(job1.name); cat.items.at(1).id.should.eql(job2.id); cat.items.at(1).name.should.equal(job2.name); - + // lazy-loaded relations should.not.exist(cat.items.at(0).job()); should.not.exist(cat.items.at(1).job()); - + cat.items(function(err, items) { cat.items.at(0).job().should.be.instanceof(Job); cat.items.at(1).job().should.be.instanceof(Job); @@ -2935,7 +2935,7 @@ describe('relations', function () { }); }); }); - + it('should remove embedded items by id', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(2); @@ -2946,16 +2946,16 @@ describe('relations', function () { }); }); }); - + it('should find items on scope', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(1); cat.items.at(0).id.should.eql(job2.id); cat.items.at(0).name.should.equal(job2.name); - + // lazy-loaded relations should.not.exist(cat.items.at(0).job()); - + cat.items(function(err, items) { cat.items.at(0).job().should.be.instanceof(Job); cat.items.at(0).job().name.should.equal('Job 2'); @@ -2963,7 +2963,7 @@ describe('relations', function () { }); }); }); - + it('should add related items to scope', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(1); @@ -2971,27 +2971,27 @@ describe('relations', function () { link.should.be.instanceof(Link); link.id.should.eql(job3.id); link.name.should.equal('Job 3'); - + cat.links.should.have.length(2); done(); }); }); }); - + it('should find items on scope', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(2); - + cat.items.at(0).should.be.instanceof(Link); cat.items.at(0).id.should.eql(job2.id); cat.items.at(0).name.should.equal(job2.name); cat.items.at(1).id.should.eql(job3.id); cat.items.at(1).name.should.equal(job3.name); - + done(); }); }); - + it('should remove embedded items by reference id', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(2); @@ -3002,7 +3002,7 @@ describe('relations', function () { }); }); }); - + it('should have removed embedded items by reference id', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(1); @@ -3026,7 +3026,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope', function(done) { Category.findById(category.id, function(err, cat) { cat.name.should.equal('Category B'); @@ -3044,7 +3044,7 @@ describe('relations', function () { }); }); }); - + it('should update items on scope - and save parent', function(done) { Category.findById(category.id, function(err, cat) { var link = cat.items.at(0); @@ -3054,7 +3054,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - verify update', function(done) { Category.findById(category.id, function(err, cat) { cat.name.should.equal('Category B'); @@ -3064,7 +3064,7 @@ describe('relations', function () { done(); }); }); - + it('should remove items from scope - and save parent', function(done) { Category.findById(category.id, function(err, cat) { cat.items.at(0).destroy(function(err, link) { @@ -3073,7 +3073,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - verify destroy', function(done) { Category.findById(category.id, function(err, cat) { cat.name.should.equal('Category B'); @@ -3081,21 +3081,21 @@ describe('relations', function () { done(); }); }); - + }); - + describe('embedsMany - polymorphic relations', function () { - + var person1, person2; - + before(function (done) { db = getSchema(); tmp = getTransientDataSource(); - + Book = db.define('Book', {name: String}); Author = db.define('Author', {name: String}); Reader = db.define('Reader', {name: String}); - + Link = tmp.define('Link', { id: {type: Number, id: true}, name: String, notes: String @@ -3114,11 +3114,11 @@ describe('relations', function () { it('can be declared', function (done) { var idType = db.connector.getDefaultIdType(); - + Book.embedsMany(Link, { as: 'people', polymorphic: 'linked', scope: { include: 'linked' } - }); + }); Link.belongsTo('linked', { polymorphic: { idType: idType }, // native type properties: { name: 'name' }, // denormalized @@ -3126,7 +3126,7 @@ describe('relations', function () { }); db.automigrate(done); }); - + it('should setup related items', function(done) { Author.create({ name: 'Author 1' }, function(err, p) { person1 = p; @@ -3136,7 +3136,7 @@ describe('relations', function () { }); }); }); - + it('should create items on scope', function(done) { Book.create({ name: 'Book' }, function(err, book) { var link = book.people.build({ notes: 'Something ...' }); @@ -3145,47 +3145,47 @@ describe('relations', function () { link.linked(person2); book.save(function(err, book) { should.not.exist(err); - + var link = book.people.at(0); link.should.be.instanceof(Link); link.id.should.equal(1); link.linkedId.should.eql(person1.id); link.linkedType.should.equal('Author'); link.name.should.equal('Author 1'); - + var link = book.people.at(1); link.should.be.instanceof(Link); link.id.should.equal(2); link.linkedId.should.eql(person2.id); link.linkedType.should.equal('Reader'); link.name.should.equal('Reader 1'); - + done(); }); }); }); - + it('should include related items on scope', function(done) { Book.findOne(function(err, book) { book.links.should.have.length(2); - + var link = book.people.at(0); link.should.be.instanceof(Link); link.id.should.equal(1); link.linkedId.should.eql(person1.id); link.linkedType.should.equal('Author'); link.notes.should.equal('Something ...'); - + var link = book.people.at(1); link.should.be.instanceof(Link); link.id.should.equal(2); link.linkedId.should.eql(person2.id); link.linkedType.should.equal('Reader'); - + // lazy-loaded relations should.not.exist(book.people.at(0).linked()); should.not.exist(book.people.at(1).linked()); - + book.people(function(err, people) { people[0].linked().should.be.instanceof(Author); people[0].linked().name.should.equal('Author 1'); @@ -3195,47 +3195,47 @@ describe('relations', function () { }); }); }); - + it('should include nested related items on scope', function(done) { - + // There's some date duplication going on, so it might // make sense to override toObject on a case-by-case basis // to sort this out (delete links, keep people). // In loopback, an afterRemote filter could do this as well. - + Book.find({ include: 'people' }, function(err, books) { var obj = books[0].toObject(); - + obj.should.have.property('links'); obj.should.have.property('people'); - + obj.links.should.have.length(2); obj.links[0].name.should.equal('Author 1'); obj.links[1].name.should.equal('Reader 1'); - + obj.people.should.have.length(2); - + obj.people[0].name.should.equal('Author 1'); obj.people[0].notes.should.equal('Something ...'); - + obj.people[0].linked.name.should.equal('Author 1'); obj.people[1].linked.name.should.equal('Reader 1'); - + done(); }); }); - + }); - + describe('referencesMany', function () { - + var job1, job2, job3; - + before(function (done) { db = getSchema(); Category = db.define('Category', {name: String}); Job = db.define('Job', {name: String}); - + db.automigrate(function () { Category.destroyAll(function() { Job.destroyAll(done); @@ -3252,21 +3252,21 @@ describe('relations', function () { cb(err, inst[fk] || []); }); }; - + reverse.shared = true; // remoting reverse.http = { verb: 'put', path: '/jobs/reverse' }; - + Category.referencesMany(Job, { scopeMethods: { reverse: reverse } }); - + Category.prototype['__reverse__jobs'].should.be.a.function; should.exist(Category.prototype['__reverse__jobs'].shared); Category.prototype['__reverse__jobs'].http.should.eql(reverse.http); - + db.automigrate(done); }); - + it('should setup test records', function (done) { Job.create({ name: 'Job 1' }, function(err, p) { job1 = p; @@ -3276,7 +3276,7 @@ describe('relations', function () { }); }); }); - + it('should create record on scope', function (done) { Category.create({ name: 'Category A' }, function(err, cat) { cat.jobIds.should.be.an.array; @@ -3291,7 +3291,7 @@ describe('relations', function () { }); }); }); - + it('should not allow duplicate record on scope', function (done) { Category.findOne(function(err, cat) { cat.jobIds = [job2.id, job2.id]; @@ -3303,7 +3303,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope', function (done) { Category.findOne(function(err, cat) { cat.jobIds.should.eql([job2.id]); @@ -3316,7 +3316,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - findById', function (done) { Category.findOne(function(err, cat) { cat.jobIds.should.eql([job2.id]); @@ -3329,7 +3329,7 @@ describe('relations', function () { }); }); }); - + it('should check if a record exists on scope', function (done) { Category.findOne(function(err, cat) { cat.jobs.exists(job2.id, function(err, exists) { @@ -3339,7 +3339,7 @@ describe('relations', function () { }); }); }); - + it('should update a record on scope', function (done) { Category.findOne(function(err, cat) { var attrs = { name: 'Job 2 - edit' }; @@ -3350,7 +3350,7 @@ describe('relations', function () { }); }); }); - + it('should get a record by index - at', function (done) { Category.findOne(function(err, cat) { cat.jobs.at(0, function(err, p) { @@ -3362,7 +3362,7 @@ describe('relations', function () { }); }); }); - + it('should add a record to scope - object', function (done) { Category.findOne(function(err, cat) { cat.jobs.add(job1, function(err, prod) { @@ -3374,7 +3374,7 @@ describe('relations', function () { }); }); }); - + it('should add a record to scope - object', function (done) { Category.findOne(function(err, cat) { cat.jobs.add(job3.id, function(err, prod) { @@ -3387,7 +3387,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - findById', function (done) { Category.findOne(function(err, cat) { cat.jobs.findById(job3.id, function(err, p) { @@ -3398,7 +3398,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - filter', function (done) { Category.findOne(function(err, cat) { var filter = { where: { name: 'Job 1' } }; @@ -3412,7 +3412,7 @@ describe('relations', function () { }); }); }); - + it('should remove items from scope', function (done) { Category.findOne(function(err, cat) { cat.jobs.remove(job1.id, function(err, ids) { @@ -3424,7 +3424,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - verify', function (done) { Category.findOne(function(err, cat) { var expected = [job2.id, job3.id]; @@ -3438,7 +3438,7 @@ describe('relations', function () { }); }); }); - + it('should allow custom scope methods - reverse', function(done) { Category.findOne(function(err, cat) { cat.jobs.reverse(function(err, ids) { @@ -3449,7 +3449,7 @@ describe('relations', function () { }); }) }); - + it('should include related items from scope', function(done) { Category.find({ include: 'jobs' }, function(err, categories) { categories.should.have.length(1); @@ -3461,7 +3461,7 @@ describe('relations', function () { done(); }); }); - + it('should destroy items from scope - destroyById', function (done) { Category.findOne(function(err, cat) { cat.jobs.destroy(job2.id, function(err) { @@ -3476,7 +3476,7 @@ describe('relations', function () { }); }); }); - + it('should find items on scope - verify', function (done) { Category.findOne(function(err, cat) { var expected = [job3.id]; @@ -3489,9 +3489,9 @@ describe('relations', function () { }); }); }); - + }); - + describe('custom relation/scope methods', function () { var categoryId; @@ -3499,7 +3499,7 @@ describe('relations', function () { db = getSchema(); Category = db.define('Category', {name: String}); Job = db.define('Job', {name: String}); - + db.automigrate(function () { Category.destroyAll(function() { Job.destroyAll(done); @@ -3509,7 +3509,7 @@ describe('relations', function () { it('can be declared', function (done) { var relation = Category.hasMany(Job); - + var summarize = function(cb) { var modelInstance = this.modelInstance; this.fetch(function(err, items) { @@ -3522,19 +3522,19 @@ describe('relations', function () { cb(null, summary); }); }; - + summarize.shared = true; // remoting summarize.http = { verb: 'get', path: '/jobs/summary' }; - + relation.defineMethod('summarize', summarize); - + Category.prototype['__summarize__jobs'].should.be.a.function; should.exist(Category.prototype['__summarize__jobs'].shared); Category.prototype['__summarize__jobs'].http.should.eql(summarize.http); - + db.automigrate(done); }); - + it('should setup test records', function (done) { Category.create({ name: 'Category A' }, function(err, cat) { categoryId = cat.id; @@ -3545,13 +3545,13 @@ describe('relations', function () { }) }); }); - + it('should allow custom scope methods - summarize', function(done) { var expected = [ { name: 'Job 1', categoryId: categoryId, categoryName: 'Category A' }, { name: 'Job 2', categoryId: categoryId, categoryName: 'Category A' } ]; - + Category.findOne(function(err, cat) { cat.jobs.summarize(function(err, summary) { should.not.exist(err); @@ -3564,7 +3564,7 @@ describe('relations', function () { }); }) }); - + }); }); diff --git a/test/schema.test.js b/test/schema.test.js index 1f1caf7a..02c15a5c 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -13,13 +13,17 @@ describe('dataSource', function () { }); it('should clone existing model', function () { + // Workaround for a possible bug in `should` + // where it takes ages to evaluate `should.equal` for complex objects + this.timeout(20000); + SlaveModel = slave.copyModel(Model); - SlaveModel.dataSource.should.eql(slave); - slave.should.not.eql(db); + SlaveModel.dataSource.should.equal(slave); + slave.should.not.equal(db); var sm = new SlaveModel; sm.should.be.instanceOf(Model); - sm.getDataSource().should.not.eql(db); - sm.getDataSource().should.eql(slave); + sm.getDataSource().should.not.equal(db); + sm.getDataSource().should.equal(slave); }); it('should automigrate', function (done) {