diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..43c97e71 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml index 37bac7de..9cc22b70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ sudo: false language: node_js node_js: - - "4" - "6" - "8" + - "10" after_success: npm run coverage diff --git a/lib/connectors/transient.js b/lib/connectors/transient.js index 29afc39d..5578e2a9 100644 --- a/lib/connectors/transient.js +++ b/lib/connectors/transient.js @@ -67,8 +67,8 @@ Transient.prototype.generateId = function(model, data, idName) { return Math.floor(Math.random() * 10000); // max. 4 digits } else { return crypto.randomBytes(Math.ceil(24 / 2)) - .toString('hex') // convert to hexadecimal format - .slice(0, 24); // return required number of characters + .toString('hex') // convert to hexadecimal format + .slice(0, 24); // return required number of characters } }; diff --git a/lib/dao.js b/lib/dao.js index c5f3e810..de57d1f8 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -487,7 +487,7 @@ function stillConnecting(dataSource, obj, args) { // promise variant var promiseArgs = Array.prototype.slice.call(args); promiseArgs.callee = args.callee; - var cb = utils.createPromiseCallback(); + var cb = utils.createPromiseCallback(); promiseArgs.push(cb); if (dataSource.ready(obj, promiseArgs)) { return cb.promise; @@ -801,7 +801,7 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { function callConnector() { try { // Support an optional where object - var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values ctx.where = removeUndefined(ctx.where, handleUndefined); ctx.where = Model._coerce(ctx.where, options); @@ -864,7 +864,7 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { self.find({where: ctx.query.where}, opts, function(err, instances) { if (err) return cb(err); var modelsLength = instances.length; - if (modelsLength === 0) { + if (modelsLength === 0) { self.create(data, options, cb); } else if (modelsLength === 1) { var modelInst = instances[0]; @@ -1089,7 +1089,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) // query will be built from data, and method will return Promise data = query; query = {where: data}; - } else if (options === undefined && cb === undefined) { + } else if (options === undefined && cb === undefined) { if (typeof data === 'function') { // findOrCreate(data, cb); // query will be built from data @@ -1517,7 +1517,7 @@ DataAccessObject._normalize = function(filter, options) { } if (isNaN(offset) || offset < 0 || Math.ceil(offset) !== offset) { err = new Error(g.f('The {{offset/skip}} parameter %j is not valid', - filter.skip || filter.offset)); + filter.skip || filter.offset)); err.statusCode = 400; throw err; } @@ -1574,7 +1574,7 @@ DataAccessObject._normalize = function(filter, options) { Object.keys(this.definition.properties), this.settings.strict); } - var handleUndefined = this._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = this._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values filter = removeUndefined(filter, handleUndefined); this._coerce(filter.where, options); @@ -2118,7 +2118,7 @@ DataAccessObject.find = function find(query, options, cb) { if (options.notify === false) { invokeConnectorMethod(connector, 'all', self, [query], options, allCb); } else { - var context = { + var context = { Model: this, query: query, hookState: hookState, @@ -2271,7 +2271,7 @@ DataAccessObject.destroyAll = function destroyAll(where, options, cb) { } else { try { // Support an optional where object - var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values where = removeUndefined(where, handleUndefined); where = Model._coerce(where, options); @@ -2426,7 +2426,7 @@ DataAccessObject.count = function(where, options, cb) { where = query.where; try { - var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values where = removeUndefined(where, handleUndefined); where = this._coerce(where, options); @@ -2478,7 +2478,7 @@ DataAccessObject.prototype.save = function(options, cb) { if (isPKMissing(Model, cb)) { return cb.promise; - } else if (this.isNewRecord()) { + } else if (this.isNewRecord()) { return Model.create(this, options, cb); } @@ -2719,7 +2719,7 @@ DataAccessObject.updateAll = function(where, data, options, cb) { function doUpdate(where, data) { try { // Support an optional where object - var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = Model._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values where = removeUndefined(where, handleUndefined); where = Model._coerce(where, options); @@ -2982,7 +2982,7 @@ DataAccessObject.replaceById = function(id, data, options, cb) { options = options || {}; assert((typeof data === 'object') && (data !== null), - 'The data argument must be an object'); + 'The data argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof cb === 'function', 'The cb argument must be a function'); @@ -3101,7 +3101,7 @@ DataAccessObject.replaceById = function(id, data, options, cb) { Model._warned.cannotOverwritePKInLoadedHook = true; g.warn('WARNING: {{id}} property cannot be changed from %s to %s for model:%s in ' + '{{\'loaded\'}} operation hook', - id, ctx.data[pkName], Model.modelName); + id, ctx.data[pkName], Model.modelName); } inst.__persisted = true; @@ -3208,7 +3208,7 @@ function(data, options, cb) { if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) { var err = new Error(g.f('{{id}} cannot be updated from ' + '%s to %s when {{forceId}} is set to true', - inst[idName], data[idName])); + inst[idName], data[idName])); err.statusCode = 400; process.nextTick(function() { cb(err); diff --git a/lib/datasource.js b/lib/datasource.js index 029d7c5e..6006eceb 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -227,7 +227,7 @@ function connectorModuleNames(name) { } // Only try the short name if the connector is not from StrongLoop if (['mongodb', 'oracle', 'mysql', 'postgresql', 'mssql', 'rest', 'soap', 'db2', 'cloudant'] - .indexOf(name) === -1) { + .indexOf(name) === -1) { names.push(name); } return names; @@ -272,7 +272,7 @@ DataSource._resolveConnector = function(name, loader) { if (!connector) { error = g.f('\nWARNING: {{LoopBack}} connector "%s" is not installed ' + 'as any of the following modules:\n\n %s\n\nTo fix, run:\n\n {{npm install %s --save}}\n', - name, names.join('\n'), names[names.length - 1]); + name, names.join('\n'), names[names.length - 1]); } return { connector: connector, @@ -498,7 +498,7 @@ DataSource.prototype.setup = function(dsName, settings) { } catch (err) { if (err.message) { err.message = 'Cannot initialize connector ' + - JSON.stringify(connectorName) + ': ' + + JSON.stringify(connectorName) + ': ' + err.message; } throw err; @@ -1101,7 +1101,7 @@ DataSource.prototype.autoupdate = function(models, cb) { if (invalidModels.length) { process.nextTick(function() { cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s', - invalidModels.join(' ')))); + invalidModels.join(' ')))); }); return cb.promise; } diff --git a/lib/hooks.js b/lib/hooks.js index db946844..52ec8ce2 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -106,7 +106,7 @@ function deprecateHook(ctor, prefixes, capitalizedName) { var hookName = candidateNames.filter(function(hook) { return !!ctor[hook]; })[0]; if (!hookName) return; // just to be sure, this should never happen - if (ctor.modelName) hookName = ctor.modelName + '.' + hookName; + if (ctor.modelName) hookName = ctor.modelName + '.' + hookName; deprecated(g.f('Model hook "%s" is deprecated, ' + 'use Operation hooks instead. ' + '{{http://docs.strongloop.com/display/LB/Operation+hooks}}', hookName)); diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 9234b772..9452dc53 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -575,7 +575,7 @@ function lookupModelTo(modelFrom, modelToRef, params, singularize) { if (!modelTo) { // lookup by modelTo name was not successful. Now looking-up by relationTo name - var relationToName = params.as || modelToRef; // modelToRef might be relationTo name + var relationToName = params.as || modelToRef; // modelToRef might be relationTo name modelToName = (singularize ? i8n.singularize(relationToName) : relationToName).toLowerCase(); modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName); } @@ -787,7 +787,7 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelToRef, params) { if (relation.type === RelationTypes.belongsTo && (relation.polymorphic && !relation.modelTo || relation.modelTo === definition.modelTo) && (relation.keyFrom === definition.keyThrough) - ) { + ) { throughRelationName = relation.name; break; } @@ -992,7 +992,7 @@ var throughKeys = function(definition) { }); } else { fk1 = findBelongsTo(modelThrough, definition.modelFrom, - definition.keyFrom)[0]; + definition.keyFrom)[0]; fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2)[0]; } return [fk1, fk2]; @@ -1022,8 +1022,8 @@ HasManyThrough.prototype.findById = function(fkId, options, cb) { if (!err) { err = new Error(g.f('No relation found in %s' + ' for (%s.%s,%s.%s)', - modelThrough.modelName, self.definition.modelFrom.modelName, - modelInstance[pk], modelTo.modelName, fkId)); + modelThrough.modelName, self.definition.modelFrom.modelName, + modelInstance[pk], modelTo.modelName, fkId)); err.statusCode = 404; } return cb(err); @@ -1825,7 +1825,7 @@ HasOne.prototype.create = function(targetModelData, options, cb) { } else { cb && cb(new Error(g.f( '{{HasOne}} relation cannot create more than one instance of %s', - modelTo.modelName))); + modelTo.modelName))); } }); return cb.promise; @@ -2472,10 +2472,10 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelToRef, param var opts = Object.assign( params.options && params.options.property ? params.options.property : {}, params.options && params.options.omitDefaultEmbeddedItem ? {type: [modelTo]} : - { - type: [modelTo], - default: function() { return []; }, - } + { + type: [modelTo], + default: function() { return []; }, + } ); modelFrom.dataSource.defineProperty(modelFrom.modelName, propertyName, opts); @@ -2785,12 +2785,12 @@ EmbedsMany.prototype.updateById = function(fkId, data, options, cb) { if (typeof cb === 'function') { modelInstance.updateAttribute(propertyName, embeddedList, options, - function(err) { - if (err) return cb(err, inst); - modelTo.notifyObserversOf('after save', context, function(err) { - cb(err, inst); + function(err) { + if (err) return cb(err, inst); + modelTo.notifyObserversOf('after save', context, function(err) { + cb(err, inst); + }); }); - }); } else { modelTo.notifyObserversOf('after save', context, function(err) { if (!err) return; diff --git a/lib/utils.js b/lib/utils.js index 3b99e637..4e8d665a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -63,7 +63,7 @@ function setScopeValuesFromWhere(data, where, targetModel) { if (prop) { var val = where[i]; if (typeof val !== 'object' || val instanceof prop.type || - prop.type.name === 'ObjectID' || // MongoDB key + prop.type.name === 'ObjectID' || // MongoDB key prop.type.name === 'uuidFromString') { // C* // Only pick the {propertyName: propertyValue} data[i] = where[i]; @@ -358,7 +358,7 @@ function parseSettings(urlStr) { settings.port = uri.port && Number(uri.port); // port is a string settings.user = settings.username = uri.auth && uri.auth.split(':')[0]; // : settings.password = uri.auth && uri.auth.split(':')[1]; - settings.database = uri.pathname && uri.pathname.split('/')[1]; // remove the leading / + settings.database = uri.pathname && uri.pathname.split('/')[1]; // remove the leading / settings.url = urlStr; if (uri.query) { var params = qs.parse(uri.query); diff --git a/lib/validations.js b/lib/validations.js index 929911ce..33ad6fe3 100644 --- a/lib/validations.js +++ b/lib/validations.js @@ -869,8 +869,8 @@ function ValidationError(obj) { var context = obj && obj.constructor && obj.constructor.modelName; this.message = g.f( 'The %s instance is not valid. Details: %s.', - context ? '`' + context + '`' : 'model', - formatErrors(obj.errors, obj.toJSON()) || '(unknown)' + context ? '`' + context + '`' : 'model', + formatErrors(obj.errors, obj.toJSON()) || '(unknown)' ); this.statusCode = 422; diff --git a/package.json b/package.json index 6745f41c..94ed46a7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "ORM" ], "engines": { - "node": ">=4.0.0" + "node": ">=6" }, "repository": { "type": "git", @@ -37,12 +37,12 @@ "@types/node": "^10.0.8", "async-iterators": "^0.2.2", "bson": "^1.0.4", - "coveralls": "^2.13.1", - "eslint": "^3.12.2", - "eslint-config-loopback": "^8.0.0", + "coveralls": "^3.0.1", + "eslint": "^4.19.1", + "eslint-config-loopback": "^10.0.0", "loopback-connector-throwing": "file:./test/fixtures/loopback-connector-throwing", - "mocha": "^3.2.0", - "nyc": "^11.1.0", + "mocha": "^5.2.0", + "nyc": "^12.0.2", "should": "^8.4.0", "typescript": "^2.8.3" }, @@ -57,7 +57,7 @@ "minimatch": "^3.0.3", "qs": "^6.5.0", "shortid": "^2.2.6", - "strong-globalize": "^3.1.0", + "strong-globalize": "^4.1.1", "traverse": "^0.6.6", "uuid": "^3.0.1" }, diff --git a/test/basic-querying.test.js b/test/basic-querying.test.js index 89408635..d733ead0 100644 --- a/test/basic-querying.test.js +++ b/test/basic-querying.test.js @@ -137,27 +137,27 @@ describe('basic-querying', function() { createdUsers[1].id, createdUsers[2].id, createdUsers[3].id], - {where: {vip: true}}, function(err, users) { - should.exist(users); - should.not.exist(err); - var names = users.map(function(u) { - return u.name; - }); - names.should.eql(createdUsers.slice(0, 4). - filter(function(u) { - return u.vip; - }).map(function(u) { - return u.name; - })); - done(); + {where: {vip: true}}, function(err, users) { + should.exist(users); + should.not.exist(err); + var names = users.map(function(u) { + return u.name; }); + names.should.eql(createdUsers.slice(0, 4). + filter(function(u) { + return u.vip; + }).map(function(u) { + return u.name; + })); + done(); + }); }); bdd.itIf(connectorCapabilities.nullDataValueExists !== false, - 'should query by ids to check null property', function(done) { - User.findByIds([ - createdUsers[0].id, - createdUsers[1].id], + 'should query by ids to check null property', function(done) { + User.findByIds([ + createdUsers[0].id, + createdUsers[1].id], {where: {vip: null}}, function(err, users) { should.not.exist(err); should.exist(users); @@ -165,7 +165,7 @@ describe('basic-querying', function() { users[0].name.should.eql(createdUsers[1].name); done(); }); - }); + }); }); describe('find', function() { @@ -334,28 +334,28 @@ describe('basic-querying', function() { }); bdd.itIf(connectorCapabilities.nullDataValueExists !== false, - 'should support where date "neq" null', function(done) { - User.find({where: {birthday: {'neq': null}, - }}, function(err, users) { - should.not.exist(err); - should.exist(users); - users.should.have.property('length', 2); - should(users[0].name).be.oneOf('John Lennon', 'Paul McCartney'); - should(users[1].name).be.oneOf('John Lennon', 'Paul McCartney'); - done(); + 'should support where date "neq" null', function(done) { + User.find({where: {birthday: {'neq': null}, + }}, function(err, users) { + should.not.exist(err); + should.exist(users); + users.should.have.property('length', 2); + should(users[0].name).be.oneOf('John Lennon', 'Paul McCartney'); + should(users[1].name).be.oneOf('John Lennon', 'Paul McCartney'); + done(); + }); }); - }); bdd.itIf(connectorCapabilities.nullDataValueExists !== false, - 'should support where date is null', function(done) { - User.find({where: {birthday: null, - }}, function(err, users) { - should.not.exist(err); - should.exist(users); - users.should.have.property('length', 4); - done(); + 'should support where date is null', function(done) { + User.find({where: {birthday: null, + }}, function(err, users) { + should.not.exist(err); + should.exist(users); + users.should.have.property('length', 4); + done(); + }); }); - }); it('should support date "gte" that is satisfied', function(done) { User.find({where: {birthday: {'gte': new Date('1980-12-08')}, @@ -887,13 +887,13 @@ describe('basic-querying', function() { 'should support nested property for order in query', function(done) { User.find({where: {'address.state': 'CA'}, order: 'address.city DESC'}, - function(err, users) { - if (err) return done(err); - users.length.should.be.equal(2); - users[0].address.city.should.be.eql('San Mateo'); - users[1].address.city.should.be.eql('San Jose'); - done(); - }); + function(err, users) { + if (err) return done(err); + users.length.should.be.equal(2); + users[0].address.city.should.be.eql('San Mateo'); + users[1].address.city.should.be.eql('San Jose'); + done(); + }); }); it('should support multi-level nested array property in query', function(done) { @@ -907,13 +907,13 @@ describe('basic-querying', function() { }); it('should fail when querying with an invalid value for a type', - function(done) { - User.find({where: {birthday: 'notadate'}}, function(err, users) { - should.exist(err); - err.message.should.equal('Invalid date: notadate'); - done(); + function(done) { + User.find({where: {birthday: 'notadate'}}, function(err, users) { + should.exist(err); + err.message.should.equal('Invalid date: notadate'); + done(); + }); }); - }); }); }); @@ -1160,16 +1160,16 @@ describe.skip('queries', function() { }); it('should return an error for deleteById/destroyById/removeById', - function(done) { - var aliases = ['deleteById', 'destroyById', 'removeById']; - async.each(aliases, function(alias, cb) { - Todo[alias](1, function(err) { - should.exist(err); - err.message.should.equal(expectedErrMsg); - cb(); - }); - }, done); - }); + function(done) { + var aliases = ['deleteById', 'destroyById', 'removeById']; + async.each(aliases, function(alias, cb) { + Todo[alias](1, function(err) { + should.exist(err); + err.message.should.equal(expectedErrMsg); + cb(); + }); + }, done); + }); it('should return an error for instance.save', function(done) { var todo = new Todo(); diff --git a/test/common_test.js b/test/common_test.js index 8942a5e5..aa5a5811 100644 --- a/test/common_test.js +++ b/test/common_test.js @@ -90,6 +90,7 @@ function clearAndCreate(model, data, callback) { } } +/* eslint-disable mocha/handle-done-callback */ function testOrm(dataSource) { var requestsAreCounted = dataSource.name !== 'mongodb'; @@ -407,7 +408,7 @@ function testOrm(dataSource) { dataSource.name !== 'memory' && dataSource.name !== 'neo4j' && dataSource.name !== 'cradle' - ) + ) it('relations key is working', function(test) { test.ok(User.relations, 'Relations key should be defined'); test.ok(User.relations.posts, 'posts relation should exist on User'); diff --git a/test/datasource.test.js b/test/datasource.test.js index a0cd1dc2..f37b33ed 100644 --- a/test/datasource.test.js +++ b/test/datasource.test.js @@ -124,7 +124,7 @@ describe('DataSource', function() { /** * new DataSource(dsName, connectorInstance) */ - it('should accept resolved connector', function() { + it('should accept dsName and resolved connector', function() { var mockConnector = { name: 'loopback-connector-mock', initialize: function(ds, cb) { diff --git a/test/datatype.test.js b/test/datatype.test.js index efbd88eb..841d83b9 100644 --- a/test/datatype.test.js +++ b/test/datatype.test.js @@ -156,19 +156,19 @@ describe('datatypes', function() { }); it('rejects array value converted to NaN for a required property', - function(done) { - db = getSchema(); - Model = db.define('RequiredNumber', { - num: {type: Number, required: true}, - }); - db.automigrate(['Model'], function() { - Model.create({num: [1, 2, 3]}, function(err, inst) { - should.exist(err); - err.should.have.property('name').equal('ValidationError'); - done(); + function(done) { + db = getSchema(); + Model = db.define('RequiredNumber', { + num: {type: Number, required: true}, + }); + db.automigrate(['Model'], function() { + Model.create({num: [1, 2, 3]}, function(err, inst) { + should.exist(err); + err.should.have.property('name').equal('ValidationError'); + done(); + }); }); }); - }); it('handles null data', (done) => { db = getSchema(); diff --git a/test/default-scope.test.js b/test/default-scope.test.js index f9788c40..afdaecb5 100644 --- a/test/default-scope.test.js +++ b/test/default-scope.test.js @@ -667,6 +667,7 @@ describe('default scope', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find a scoped instance - thing', function(done) { Product.find({where: {name: 'Product'}}, function(err, products) { products.should.have.length(2); diff --git a/test/discovery.test.js b/test/discovery.test.js index ec742969..6fad9286 100644 --- a/test/discovery.test.js +++ b/test/discovery.test.js @@ -162,20 +162,20 @@ describe('Memory connector with mocked discovery', function() { function(done) { ds.connector.discoverSchemas = null; ds.discoverSchemas('INVENTORY', {}) - .then(function(schemas) { - schemas.should.have.property('STRONGLOOP.INVENTORY'); + .then(function(schemas) { + schemas.should.have.property('STRONGLOOP.INVENTORY'); - var s = schemas['STRONGLOOP.INVENTORY']; - s.name.should.be.eql('Inventory'); + var s = schemas['STRONGLOOP.INVENTORY']; + s.name.should.be.eql('Inventory'); - Object.keys(s.properties).should.be.eql( - ['productId', 'locationId', 'available', 'total'] - ); - done(); - }) - .catch(function(err) { - done(err); - }); + Object.keys(s.properties).should.be.eql( + ['productId', 'locationId', 'available', 'total'] + ); + done(); + }) + .catch(function(err) { + done(err); + }); }); describe('discoverSchema', function() { @@ -344,9 +344,9 @@ describe('discoverModelDefinitions', function() { ); done(); }) - .catch(function(err) { - done(err); - }); + .catch(function(err) { + done(err); + }); }); }); @@ -430,9 +430,9 @@ describe('discoverModelProperties', function() { schemas.should.be.eql(modelProperties); done(); }) - .catch(function(err) { - done(err); - }); + .catch(function(err) { + done(err); + }); }); }); @@ -599,16 +599,16 @@ describe('discoverExportedForeignKeys', function() { }); it('should discover foreign key definitions using `discoverExportedForeignKeys` - promise variant', - function(done) { - ds.discoverExportedForeignKeys('INVENTORY', {}) - .then(function(modelForeignKeys) { - modelForeignKeys.should.be.eql(exportedForeignKeys); - done(); - }) - .catch(function(err) { - done(err); - }); - }); + function(done) { + ds.discoverExportedForeignKeys('INVENTORY', {}) + .then(function(modelForeignKeys) { + modelForeignKeys.should.be.eql(exportedForeignKeys); + done(); + }) + .catch(function(err) { + done(err); + }); + }); }); describe('Mock connector', function() { diff --git a/test/exclude-base-props.test.js b/test/exclude-base-props.test.js index 14064093..202130a4 100644 --- a/test/exclude-base-props.test.js +++ b/test/exclude-base-props.test.js @@ -19,7 +19,7 @@ describe('exclude properties ', function() { var User = ds.define('User', {name: String, password: String}); var properties = User.definition.properties; // User should have id, name & password properties - assert(('id' in properties) && ('password' in properties) && ('name' in properties), + assert(('id' in properties) && ('password' in properties) && ('name' in properties), 'User should have id, name & password properties'); // Create sub model Customer with vip as property. id property gets automatically created here as well. // Customer will inherit name, password and id from base User model. diff --git a/test/include.test.js b/test/include.test.js index 06bb64ae..ee9b2ada 100644 --- a/test/include.test.js +++ b/test/include.test.js @@ -85,7 +85,7 @@ describe('include', function() { }); bdd.itIf(connectorCapabilities.cloudantCompatible !== false, - 'should not save in db included models, in query returned models', + 'should not save in db included models, in query returned models', function(done) { const originalStrict = User.definition.settings.strict; User.definition.settings.strict = true; // Change to test regression for issue #1252 @@ -172,7 +172,7 @@ describe('include', function() { user.__cachedRelations.should.have.property('posts'); user.should.have.property('posts'); user.toJSON().should.have.property('posts').and.be.an.Array().with - .length(0); + .length(0); done(); }); }); @@ -285,101 +285,24 @@ describe('include', function() { }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should support limit', function(done) { - Passport.find({ - include: { - owner: { - relation: 'posts', scope: { - fields: ['title'], include: ['author'], - order: 'title DESC', - limit: 1, - }, - }, - }, - limit: 2, - }, function(err, passports) { - if (err) return done(err); - passports.length.should.equal(2); - var posts1 = passports[0].toJSON().owner.posts; - posts1.length.should.equal(1); - posts1[0].title.should.equal('Post C'); - var posts2 = passports[1].toJSON().owner.posts; - posts2.length.should.equal(1); - posts2[0].title.should.equal('Post D'); - - done(); - }); - }); - - bdd.itIf(connectorCapabilities.cloudantCompatible !== false, - 'should support limit - no sort', function(done) { - Passport.find({ - include: { - owner: { - relation: 'posts', scope: { - fields: ['title'], include: ['author'], - order: 'title DESC', - limit: 1, - }, - }, - }, - limit: 2, - }, function(err, passports) { - if (err) return done(err); - passports.length.should.equal(2); - var owner = passports[0].toJSON().owner; - if (owner) { - var posts1 = owner.posts; - posts1.length.should.belowOrEqual(1); - if (posts1.length === 1) { - posts1[0].title.should.be.oneOf(knownPosts); - } - } - owner = passports[1].toJSON().owner; - if (owner) { - var posts2 = owner.posts; - posts2.length.should.belowOrEqual(1); - if (posts2.length === 1) { - posts2[0].title.should.be.oneOf(knownPosts); - } - } - done(); - }); - }); - - bdd.describeIf(connectorCapabilities.adhocSort !== false, - 'inq limit', function() { - before(function() { - Passport.dataSource.settings.inqLimit = 2; - }); - - after(function() { - delete Passport.dataSource.settings.inqLimit; - }); - - it('should support include by pagination', function(done) { - // `pagination` in this case is inside the implementation and set by - // `inqLimit = 2` in the before block. This will need to be reworked once - // we decouple `findWithForeignKeysByPage`. - // - // --superkhau + 'should support limit', function(done) { Passport.find({ include: { owner: { - relation: 'posts', - scope: { + relation: 'posts', scope: { fields: ['title'], include: ['author'], - order: 'title ASC', + order: 'title DESC', + limit: 1, }, }, }, + limit: 2, }, function(err, passports) { if (err) return done(err); - - passports.length.should.equal(4); + passports.length.should.equal(2); var posts1 = passports[0].toJSON().owner.posts; - posts1.length.should.equal(3); - posts1[0].title.should.equal('Post A'); + posts1.length.should.equal(1); + posts1[0].title.should.equal('Post C'); var posts2 = passports[1].toJSON().owner.posts; posts2.length.should.equal(1); posts2[0].title.should.equal('Post D'); @@ -387,485 +310,247 @@ describe('include', function() { done(); }); }); - }); - bdd.describeIf(connectorCapabilities.adhocSort !== false, - 'findWithForeignKeysByPage', function() { - context('filter', function() { - it('works when using a `where` with a foreign key', function(done) { - User.findOne({ - include: { - relation: 'passports', - }, - }, function(err, user) { - if (err) return done(err); - - var passport = user.passports()[0]; - // eql instead of equal because mongo uses object id type - passport.id.should.eql(createdPassports[0].id); - passport.ownerId.should.eql(createdPassports[0].ownerId); - passport.number.should.eql(createdPassports[0].number); - - done(); - }); - }); - - it('works when using a `where` with `and`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - where: { - and: [ - {id: createdPosts[0].id}, - // Remove the duplicate userId to avoid Cassandra failure - // {userId: createdPosts[0].userId}, - {title: 'Post A'}, - ], - }, - }, - }, - }, function(err, user) { - if (err) return done(err); - - user.name.should.equal('User A'); - user.age.should.equal(21); - user.id.should.eql(createdUsers[0].id); - var posts = user.posts(); - posts.length.should.equal(1); - var post = posts[0]; - post.title.should.equal('Post A'); - // eql instead of equal because mongo uses object id type - post.userId.should.eql(createdPosts[0].userId); - post.id.should.eql(createdPosts[0].id); - - done(); - }); - }); - - it('works when using `where` with `limit`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { + bdd.itIf(connectorCapabilities.cloudantCompatible !== false, + 'should support limit - no sort', function(done) { + Passport.find({ + include: { + owner: { + relation: 'posts', scope: { + fields: ['title'], include: ['author'], + order: 'title DESC', limit: 1, }, }, - }, function(err, user) { - if (err) return done(err); - - user.posts().length.should.equal(1); - - done(); - }); - }); - - it('works when using `where` with `skip`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - skip: 1, - }, - }, - }, function(err, user) { - if (err) return done(err); - - var ids = user.posts().map(function(p) { return p.id; }); - ids.should.eql([createdPosts[1].id, createdPosts[2].id]); - - done(); - }); - }); - - it('works when using `where` with `offset`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - offset: 1, - }, - }, - }, function(err, user) { - if (err) return done(err); - - var ids = user.posts().map(function(p) { return p.id; }); - ids.should.eql([createdPosts[1].id, createdPosts[2].id]); - - done(); - }); - }); - - it('works when using `where` without `limit`, `skip` or `offset`', - function(done) { - User.findOne({include: {relation: 'posts'}}, function(err, user) { - if (err) return done(err); - - var posts = user.posts(); - var ids = posts.map(function(p) { return p.id; }); - ids.should.eql([ - createdPosts[0].id, - createdPosts[1].id, - createdPosts[2].id, - ]); - - done(); - }); + }, + limit: 2, + }, function(err, passports) { + if (err) return done(err); + passports.length.should.equal(2); + var owner = passports[0].toJSON().owner; + if (owner) { + var posts1 = owner.posts; + posts1.length.should.belowOrEqual(1); + if (posts1.length === 1) { + posts1[0].title.should.be.oneOf(knownPosts); + } + } + owner = passports[1].toJSON().owner; + if (owner) { + var posts2 = owner.posts; + posts2.length.should.belowOrEqual(1); + if (posts2.length === 1) { + posts2[0].title.should.be.oneOf(knownPosts); + } + } + done(); }); }); - context('pagination', function() { - it('works with the default page size (0) and `inqlimit` is exceeded', - function(done) { - // inqLimit modifies page size in the impl (there is no way to modify - // page size directly as it is hardcoded (once we decouple the func, - // we can use ctor injection to pass in whatever page size we want). - // - // --superkhau - Post.dataSource.settings.inqLimit = 2; - - User.find({include: {relation: 'posts'}}, function(err, users) { - if (err) return done(err); - - users.length.should.equal(5); - - delete Post.dataSource.settings.inqLimit; - - done(); - }); + bdd.describeIf(connectorCapabilities.adhocSort !== false, + 'inq limit', function() { + before(function() { + Passport.dataSource.settings.inqLimit = 2; }); - it('works when page size is set to 0', function(done) { - Post.dataSource.settings.inqLimit = 0; - - User.find({include: {relation: 'posts'}}, function(err, users) { - if (err) return done(err); - - users.length.should.equal(5); - - delete Post.dataSource.settings.inqLimit; - - done(); - }); + after(function() { + delete Passport.dataSource.settings.inqLimit; }); - }); - context('relations', function() { - // WARNING - // The code paths for in this suite of tests were verified manually due to - // the tight coupling of the `findWithForeignKeys` in `include.js`. - // - // TODO - // Decouple the utility functions into their own modules and export each - // function individually to allow for unit testing via DI. + it('should support include by pagination', function(done) { + // `pagination` in this case is inside the implementation and set by + // `inqLimit = 2` in the before block. This will need to be reworked once + // we decouple `findWithForeignKeysByPage`. // // --superkhau - - it('works when hasOne is called', function(done) { - User.findOne({include: {relation: 'profile'}}, function(err, user) { - if (err) return done(err); - - user.name.should.equal('User A'); - user.age.should.equal(21); - // eql instead of equal because mongo uses object id type - user.id.should.eql(createdUsers[0].id); - var profile = user.profile(); - profile.profileName.should.equal('Profile A'); - // eql instead of equal because mongo uses object id type - profile.userId.should.eql(createdProfiles[0].userId); - profile.id.should.eql(createdProfiles[0].id); - - done(); - }); - }); - - it('works when hasMany is called', function(done) { - User.findOne({include: {relation: 'posts'}}, function(err, user) { - if (err) return done(); - - user.name.should.equal('User A'); - user.age.should.equal(21); - // eql instead of equal because mongo uses object id type - user.id.should.eql(createdUsers[0].id); - user.posts().length.should.equal(3); - - done(); - }); - }); - - it('works when hasManyThrough is called', function(done) { - var Physician = db.define('Physician', {name: String}); - var Patient = db.define('Patient', {name: String}); - var Appointment = db.define('Appointment', { - date: { - type: Date, - default: function() { - return new Date(); - }, - }, - }); - var Address = db.define('Address', {name: String}); - - Physician.hasMany(Patient, {through: Appointment}); - Patient.hasMany(Physician, {through: Appointment}); - Patient.belongsTo(Address); - Appointment.belongsTo(Patient); - Appointment.belongsTo(Physician); - - db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], - function() { - Physician.create(function(err, physician) { - physician.patients.create({name: 'a'}, function(err, patient) { - Address.create({name: 'z'}, function(err, address) { - patient.address(address); - patient.save(function() { - physician.patients({include: 'address'}, - function(err, patients) { - if (err) return done(err); - - patients.should.have.length(1); - var p = patients[0]; - p.name.should.equal('a'); - p.addressId.should.eql(patient.addressId); - p.address().id.should.eql(address.id); - p.address().name.should.equal('z'); - - done(); - }); - }); - }); - }); - }); - }); - }); - - it('works when belongsTo is called', function(done) { - Profile.findOne({include: 'user'}, function(err, profile) { - if (err) return done(err); - - profile.profileName.should.equal('Profile A'); - profile.userId.should.eql(createdProfiles[0].userId); - profile.id.should.eql(createdProfiles[0].id); - var user = profile.user(); - user.name.should.equal('User A'); - user.age.should.equal(21); - user.id.should.eql(createdUsers[0].id); - - done(); - }); - }); - }); - }); - - bdd.describeIf(connectorCapabilities.adhocSort === false, - 'findWithForeignKeysByPage', function() { - context('filter', function() { - it('works when using a `where` with a foreign key', function(done) { - User.findOne({ + Passport.find({ include: { - relation: 'passports', - }, - }, function(err, user) { - if (err) return done(err); - - var passport = user.passports()[0]; - if (passport) { - var knownPassportIds = []; - var knownOwnerIds = []; - createdPassports.forEach(function(p) { - if (p.id) knownPassportIds.push(p.id); - if (p.ownerId) knownOwnerIds.push(p.ownerId.toString()); - }); - passport.id.should.be.oneOf(knownPassportIds); - // FIXME passport.ownerId may be string - passport.ownerId.toString().should.be.oneOf(knownOwnerIds); - passport.number.should.be.oneOf(knownPassports); - } - done(); - }); - }); - - it('works when using a `where` with `and`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - where: { - and: [ - {id: createdPosts[0].id}, - // Remove the duplicate userId to avoid Cassandra failure - // {userId: createdPosts[0].userId}, - {title: createdPosts[0].title}, - ], + owner: { + relation: 'posts', + scope: { + fields: ['title'], include: ['author'], + order: 'title ASC', }, }, }, - }, function(err, user) { + }, function(err, passports) { if (err) return done(err); - var posts, post; - if (connectorCapabilities.adhocSort !== false) { + passports.length.should.equal(4); + var posts1 = passports[0].toJSON().owner.posts; + posts1.length.should.equal(3); + posts1[0].title.should.equal('Post A'); + var posts2 = passports[1].toJSON().owner.posts; + posts2.length.should.equal(1); + posts2[0].title.should.equal('Post D'); + + done(); + }); + }); + }); + + bdd.describeIf(connectorCapabilities.adhocSort !== false, + 'findWithForeignKeysByPage', function() { + context('filter', function() { + it('works when using a `where` with a foreign key', function(done) { + User.findOne({ + include: { + relation: 'passports', + }, + }, function(err, user) { + if (err) return done(err); + + var passport = user.passports()[0]; + // eql instead of equal because mongo uses object id type + passport.id.should.eql(createdPassports[0].id); + passport.ownerId.should.eql(createdPassports[0].ownerId); + passport.number.should.eql(createdPassports[0].number); + + done(); + }); + }); + + it('works when using a `where` with `and`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + where: { + and: [ + {id: createdPosts[0].id}, + // Remove the duplicate userId to avoid Cassandra failure + // {userId: createdPosts[0].userId}, + {title: 'Post A'}, + ], + }, + }, + }, + }, function(err, user) { + if (err) return done(err); + user.name.should.equal('User A'); user.age.should.equal(21); user.id.should.eql(createdUsers[0].id); - posts = user.posts(); + var posts = user.posts(); posts.length.should.equal(1); - post = posts[0]; + var post = posts[0]; post.title.should.equal('Post A'); // eql instead of equal because mongo uses object id type post.userId.should.eql(createdPosts[0].userId); post.id.should.eql(createdPosts[0].id); - } else { - user.name.should.be.oneOf(knownUsers); - var knownUserIds = []; - createdUsers.forEach(function(u) { - knownUserIds.push(u.id.toString()); - }); - user.id.toString().should.be.oneOf(knownUserIds); - posts = user.posts(); - if (posts && posts.length > 0) { - post = posts[0]; - post.title.should.be.oneOf(knownPosts); - post.userId.toString().should.be.oneOf(knownUserIds); - var knownPostIds = []; - createdPosts.forEach(function(p) { - knownPostIds.push(p.id); - }); - post.id.should.be.oneOf(knownPostIds); - } - } - done(); - }); - }); - it('works when using `where` with `limit`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - limit: 1, + done(); + }); + }); + + it('works when using `where` with `limit`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + limit: 1, + }, }, - }, - }, function(err, user) { - if (err) return done(err); + }, function(err, user) { + if (err) return done(err); - user.posts().length.should.belowOrEqual(1); + user.posts().length.should.equal(1); - done(); + done(); + }); }); - }); - it('works when using `where` with `skip`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - skip: 1, // will be ignored + it('works when using `where` with `skip`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + skip: 1, + }, }, - }, - }, function(err, user) { - if (err) return done(err); + }, function(err, user) { + if (err) return done(err); - var ids = user.posts().map(function(p) { return p.id; }); - if (ids.length > 0) { - var knownPosts = []; - createdPosts.forEach(function(p) { - if (p.id) knownPosts.push(p.id); - }); - ids.forEach(function(id) { - if (id) id.should.be.oneOf(knownPosts); - }); - } + var ids = user.posts().map(function(p) { return p.id; }); + ids.should.eql([createdPosts[1].id, createdPosts[2].id]); - done(); + done(); + }); }); - }); - it('works when using `where` with `offset`', function(done) { - User.findOne({ - include: { - relation: 'posts', - scope: { - offset: 1, // will be ignored + it('works when using `where` with `offset`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + offset: 1, + }, }, - }, - }, function(err, user) { - if (err) return done(err); + }, function(err, user) { + if (err) return done(err); - var ids = user.posts().map(function(p) { return p.id; }); - if (ids.length > 0) { - var knownPosts = []; - createdPosts.forEach(function(p) { - if (p.id) knownPosts.push(p.id); - }); - ids.forEach(function(id) { - if (id) id.should.be.oneOf(knownPosts); - }); - } + var ids = user.posts().map(function(p) { return p.id; }); + ids.should.eql([createdPosts[1].id, createdPosts[2].id]); - done(); + done(); + }); + }); + + it('works when using `where` without `limit`, `skip` or `offset`', + function(done) { + User.findOne({include: {relation: 'posts'}}, function(err, user) { + if (err) return done(err); + + var posts = user.posts(); + var ids = posts.map(function(p) { return p.id; }); + ids.should.eql([ + createdPosts[0].id, + createdPosts[1].id, + createdPosts[2].id, + ]); + + done(); + }); + }); + }); + + context('pagination', function() { + it('works with the default page size (0) and `inqlimit` is exceeded', + function(done) { + // inqLimit modifies page size in the impl (there is no way to modify + // page size directly as it is hardcoded (once we decouple the func, + // we can use ctor injection to pass in whatever page size we want). + // + // --superkhau + Post.dataSource.settings.inqLimit = 2; + + User.find({include: {relation: 'posts'}}, function(err, users) { + if (err) return done(err); + + users.length.should.equal(5); + + delete Post.dataSource.settings.inqLimit; + + done(); + }); + }); + + it('works when page size is set to 0', function(done) { + Post.dataSource.settings.inqLimit = 0; + + User.find({include: {relation: 'posts'}}, function(err, users) { + if (err) return done(err); + + users.length.should.equal(5); + + delete Post.dataSource.settings.inqLimit; + + done(); + }); }); }); - it('works when using `where` without `limit`, `skip` or `offset`', - function(done) { - User.findOne({include: {relation: 'posts'}}, function(err, user) { - if (err) return done(err); - - var posts = user.posts(); - var ids = posts.map(function(p) { return p.id; }); - if (ids.length > 0) { - var knownPosts = []; - createdPosts.forEach(function(p) { - if (p.id) knownPosts.push(p.id); - }); - ids.forEach(function(id) { - if (id) id.should.be.oneOf(knownPosts); - }); - } - - done(); - }); - }); - }); - - context('pagination', function() { - it('works with the default page size (0) and `inqlimit` is exceeded', - function(done) { - // inqLimit modifies page size in the impl (there is no way to modify - // page size directly as it is hardcoded (once we decouple the func, - // we can use ctor injection to pass in whatever page size we want). - // - // --superkhau - Post.dataSource.settings.inqLimit = 2; - - User.find({include: {relation: 'posts'}}, function(err, users) { - if (err) return done(err); - - users.length.should.equal(5); - - delete Post.dataSource.settings.inqLimit; - - done(); - }); - }); - - it('works when page size is set to 0', function(done) { - Post.dataSource.settings.inqLimit = 0; - - User.find({include: {relation: 'posts'}}, function(err, users) { - if (err) return done(err); - - users.length.should.equal(5); - - delete Post.dataSource.settings.inqLimit; - - done(); - }); - }); - }); - - context('relations', function() { + context('relations', function() { // WARNING // The code paths for in this suite of tests were verified manually due to // the tight coupling of the `findWithForeignKeys` in `include.js`. @@ -876,81 +561,399 @@ describe('include', function() { // // --superkhau - it('works when hasOne is called', function(done) { - User.findOne({include: {relation: 'profile'}}, function(err, user) { - if (err) return done(err); + it('works when hasOne is called', function(done) { + User.findOne({include: {relation: 'profile'}}, function(err, user) { + if (err) return done(err); - var knownUserIds = []; - var knownProfileIds = []; - createdUsers.forEach(function(u) { + user.name.should.equal('User A'); + user.age.should.equal(21); + // eql instead of equal because mongo uses object id type + user.id.should.eql(createdUsers[0].id); + var profile = user.profile(); + profile.profileName.should.equal('Profile A'); + // eql instead of equal because mongo uses object id type + profile.userId.should.eql(createdProfiles[0].userId); + profile.id.should.eql(createdProfiles[0].id); + + done(); + }); + }); + + it('works when hasMany is called', function(done) { + User.findOne({include: {relation: 'posts'}}, function(err, user) { + if (err) return done(); + + user.name.should.equal('User A'); + user.age.should.equal(21); + // eql instead of equal because mongo uses object id type + user.id.should.eql(createdUsers[0].id); + user.posts().length.should.equal(3); + + done(); + }); + }); + + it('works when hasManyThrough is called', function(done) { + var Physician = db.define('Physician', {name: String}); + var Patient = db.define('Patient', {name: String}); + var Appointment = db.define('Appointment', { + date: { + type: Date, + default: function() { + return new Date(); + }, + }, + }); + var Address = db.define('Address', {name: String}); + + Physician.hasMany(Patient, {through: Appointment}); + Patient.hasMany(Physician, {through: Appointment}); + Patient.belongsTo(Address); + Appointment.belongsTo(Patient); + Appointment.belongsTo(Physician); + + db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], + function() { + Physician.create(function(err, physician) { + physician.patients.create({name: 'a'}, function(err, patient) { + Address.create({name: 'z'}, function(err, address) { + patient.address(address); + patient.save(function() { + physician.patients({include: 'address'}, + function(err, patients) { + if (err) return done(err); + + patients.should.have.length(1); + var p = patients[0]; + p.name.should.equal('a'); + p.addressId.should.eql(patient.addressId); + p.address().id.should.eql(address.id); + p.address().name.should.equal('z'); + + done(); + }); + }); + }); + }); + }); + }); + }); + + it('works when belongsTo is called', function(done) { + Profile.findOne({include: 'user'}, function(err, profile) { + if (err) return done(err); + + profile.profileName.should.equal('Profile A'); + profile.userId.should.eql(createdProfiles[0].userId); + profile.id.should.eql(createdProfiles[0].id); + var user = profile.user(); + user.name.should.equal('User A'); + user.age.should.equal(21); + user.id.should.eql(createdUsers[0].id); + + done(); + }); + }); + }); + }); + + bdd.describeIf(connectorCapabilities.adhocSort === false, + 'findWithForeignKeysByPage', function() { + // eslint-disable-next-line mocha/no-identical-title + context('filter', function() { + it('works when using a `where` with a foreign key', function(done) { + User.findOne({ + include: { + relation: 'passports', + }, + }, function(err, user) { + if (err) return done(err); + + var passport = user.passports()[0]; + if (passport) { + var knownPassportIds = []; + var knownOwnerIds = []; + createdPassports.forEach(function(p) { + if (p.id) knownPassportIds.push(p.id); + if (p.ownerId) knownOwnerIds.push(p.ownerId.toString()); + }); + passport.id.should.be.oneOf(knownPassportIds); + // FIXME passport.ownerId may be string + passport.ownerId.toString().should.be.oneOf(knownOwnerIds); + passport.number.should.be.oneOf(knownPassports); + } + done(); + }); + }); + + it('works when using a `where` with `and`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + where: { + and: [ + {id: createdPosts[0].id}, + // Remove the duplicate userId to avoid Cassandra failure + // {userId: createdPosts[0].userId}, + {title: createdPosts[0].title}, + ], + }, + }, + }, + }, function(err, user) { + if (err) return done(err); + + var posts, post; + if (connectorCapabilities.adhocSort !== false) { + user.name.should.equal('User A'); + user.age.should.equal(21); + user.id.should.eql(createdUsers[0].id); + posts = user.posts(); + posts.length.should.equal(1); + post = posts[0]; + post.title.should.equal('Post A'); + // eql instead of equal because mongo uses object id type + post.userId.should.eql(createdPosts[0].userId); + post.id.should.eql(createdPosts[0].id); + } else { + user.name.should.be.oneOf(knownUsers); + var knownUserIds = []; + createdUsers.forEach(function(u) { + knownUserIds.push(u.id.toString()); + }); + user.id.toString().should.be.oneOf(knownUserIds); + posts = user.posts(); + if (posts && posts.length > 0) { + post = posts[0]; + post.title.should.be.oneOf(knownPosts); + post.userId.toString().should.be.oneOf(knownUserIds); + var knownPostIds = []; + createdPosts.forEach(function(p) { + knownPostIds.push(p.id); + }); + post.id.should.be.oneOf(knownPostIds); + } + } + done(); + }); + }); + + it('works when using `where` with `limit`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + limit: 1, + }, + }, + }, function(err, user) { + if (err) return done(err); + + user.posts().length.should.belowOrEqual(1); + + done(); + }); + }); + + it('works when using `where` with `skip`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + skip: 1, // will be ignored + }, + }, + }, function(err, user) { + if (err) return done(err); + + var ids = user.posts().map(function(p) { return p.id; }); + if (ids.length > 0) { + var knownPosts = []; + createdPosts.forEach(function(p) { + if (p.id) knownPosts.push(p.id); + }); + ids.forEach(function(id) { + if (id) id.should.be.oneOf(knownPosts); + }); + } + + done(); + }); + }); + + it('works when using `where` with `offset`', function(done) { + User.findOne({ + include: { + relation: 'posts', + scope: { + offset: 1, // will be ignored + }, + }, + }, function(err, user) { + if (err) return done(err); + + var ids = user.posts().map(function(p) { return p.id; }); + if (ids.length > 0) { + var knownPosts = []; + createdPosts.forEach(function(p) { + if (p.id) knownPosts.push(p.id); + }); + ids.forEach(function(id) { + if (id) id.should.be.oneOf(knownPosts); + }); + } + + done(); + }); + }); + + it('works when using `where` without `limit`, `skip` or `offset`', + function(done) { + User.findOne({include: {relation: 'posts'}}, function(err, user) { + if (err) return done(err); + + var posts = user.posts(); + var ids = posts.map(function(p) { return p.id; }); + if (ids.length > 0) { + var knownPosts = []; + createdPosts.forEach(function(p) { + if (p.id) knownPosts.push(p.id); + }); + ids.forEach(function(id) { + if (id) id.should.be.oneOf(knownPosts); + }); + } + + done(); + }); + }); + }); + + // eslint-disable-next-line mocha/no-identical-title + context('pagination', function() { + it('works with the default page size (0) and `inqlimit` is exceeded', + function(done) { + // inqLimit modifies page size in the impl (there is no way to modify + // page size directly as it is hardcoded (once we decouple the func, + // we can use ctor injection to pass in whatever page size we want). + // + // --superkhau + Post.dataSource.settings.inqLimit = 2; + + User.find({include: {relation: 'posts'}}, function(err, users) { + if (err) return done(err); + + users.length.should.equal(5); + + delete Post.dataSource.settings.inqLimit; + + done(); + }); + }); + + it('works when page size is set to 0', function(done) { + Post.dataSource.settings.inqLimit = 0; + + User.find({include: {relation: 'posts'}}, function(err, users) { + if (err) return done(err); + + users.length.should.equal(5); + + delete Post.dataSource.settings.inqLimit; + + done(); + }); + }); + }); + + // eslint-disable-next-line mocha/no-identical-title + context('relations', function() { + // WARNING + // The code paths for in this suite of tests were verified manually due to + // the tight coupling of the `findWithForeignKeys` in `include.js`. + // + // TODO + // Decouple the utility functions into their own modules and export each + // function individually to allow for unit testing via DI. + // + // --superkhau + + it('works when hasOne is called', function(done) { + User.findOne({include: {relation: 'profile'}}, function(err, user) { + if (err) return done(err); + + var knownUserIds = []; + var knownProfileIds = []; + createdUsers.forEach(function(u) { // FIXME user.id below might be string, so knownUserIds should match - knownUserIds.push(u.id.toString()); - }); - createdProfiles.forEach(function(p) { + knownUserIds.push(u.id.toString()); + }); + createdProfiles.forEach(function(p) { // knownProfileIds.push(p.id ? p.id.toString() : ''); - knownProfileIds.push(p.id); + knownProfileIds.push(p.id); + }); + if (user) { + user.name.should.be.oneOf(knownUsers); + // eql instead of equal because mongo uses object id type + user.id.toString().should.be.oneOf(knownUserIds); + var profile = user.profile(); + if (profile) { + profile.profileName.should.be.oneOf(knownProfiles); + // eql instead of equal because mongo uses object id type + if (profile.userId) profile.userId.toString().should.be.oneOf(knownUserIds); + profile.id.should.be.oneOf(knownProfileIds); + } + } + + done(); }); - if (user) { + }); + + it('works when hasMany is called', function(done) { + User.findOne({include: {relation: 'posts'}}, function(err, user) { + if (err) return done(); + + var knownUserIds = []; + createdUsers.forEach(function(u) { + knownUserIds.push(u.id); + }); user.name.should.be.oneOf(knownUsers); // eql instead of equal because mongo uses object id type - user.id.toString().should.be.oneOf(knownUserIds); - var profile = user.profile(); - if (profile) { - profile.profileName.should.be.oneOf(knownProfiles); - // eql instead of equal because mongo uses object id type - if (profile.userId) profile.userId.toString().should.be.oneOf(knownUserIds); - profile.id.should.be.oneOf(knownProfileIds); - } - } + user.id.should.be.oneOf(knownUserIds); + user.posts().length.should.be.belowOrEqual(3); - done(); - }); - }); - - it('works when hasMany is called', function(done) { - User.findOne({include: {relation: 'posts'}}, function(err, user) { - if (err) return done(); - - var knownUserIds = []; - createdUsers.forEach(function(u) { - knownUserIds.push(u.id); + done(); }); - user.name.should.be.oneOf(knownUsers); - // eql instead of equal because mongo uses object id type - user.id.should.be.oneOf(knownUserIds); - user.posts().length.should.be.belowOrEqual(3); - - done(); }); - }); - it('works when hasManyThrough is called', function(done) { - var Physician = db.define('Physician', {name: String}); - var Patient = db.define('Patient', {name: String}); - var Appointment = db.define('Appointment', { - date: { - type: Date, - default: function() { - return new Date(); + it('works when hasManyThrough is called', function(done) { + var Physician = db.define('Physician', {name: String}); + var Patient = db.define('Patient', {name: String}); + var Appointment = db.define('Appointment', { + date: { + type: Date, + default: function() { + return new Date(); + }, }, - }, - }); - var Address = db.define('Address', {name: String}); + }); + var Address = db.define('Address', {name: String}); - Physician.hasMany(Patient, {through: Appointment}); - Patient.hasMany(Physician, {through: Appointment}); - Patient.belongsTo(Address); - Appointment.belongsTo(Patient); - Appointment.belongsTo(Physician); + Physician.hasMany(Patient, {through: Appointment}); + Patient.hasMany(Physician, {through: Appointment}); + Patient.belongsTo(Address); + Appointment.belongsTo(Patient); + Appointment.belongsTo(Physician); - db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], - function() { - Physician.create(function(err, physician) { - physician.patients.create({name: 'a'}, function(err, patient) { - Address.create({name: 'z'}, function(err, address) { - patient.address(address); - patient.save(function() { - physician.patients({include: 'address'}, + db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], + function() { + Physician.create(function(err, physician) { + physician.patients.create({name: 'a'}, function(err, patient) { + Address.create({name: 'z'}, function(err, address) { + patient.address(address); + patient.save(function() { + physician.patients({include: 'address'}, function(err, patients) { if (err) return done(err); patients.should.have.length(1); @@ -962,45 +965,45 @@ describe('include', function() { done(); }); + }); }); }); }); }); - }); - }); + }); - it('works when belongsTo is called', function(done) { - Profile.findOne({include: 'user'}, function(err, profile) { - if (err) return done(err); - if (!profile) return done(); // not every user has progile + it('works when belongsTo is called', function(done) { + Profile.findOne({include: 'user'}, function(err, profile) { + if (err) return done(err); + if (!profile) return done(); // not every user has progile - var knownUserIds = []; - var knownProfileIds = []; - createdUsers.forEach(function(u) { - knownUserIds.push(u.id.toString()); - }); - createdProfiles.forEach(function(p) { - if (p.id) knownProfileIds.push(p.id.toString()); - }); - if (profile) { - profile.profileName.should.be.oneOf(knownProfiles); - if (profile.userId) profile.userId.toString().should.be.oneOf(knownUserIds); - if (profile.id) profile.id.toString().should.be.oneOf(knownProfileIds); - var user = profile.user(); - if (user) { - user.name.should.be.oneOf(knownUsers); - user.id.toString().should.be.oneOf(knownUserIds); + var knownUserIds = []; + var knownProfileIds = []; + createdUsers.forEach(function(u) { + knownUserIds.push(u.id.toString()); + }); + createdProfiles.forEach(function(p) { + if (p.id) knownProfileIds.push(p.id.toString()); + }); + if (profile) { + profile.profileName.should.be.oneOf(knownProfiles); + if (profile.userId) profile.userId.toString().should.be.oneOf(knownUserIds); + if (profile.id) profile.id.toString().should.be.oneOf(knownProfileIds); + var user = profile.user(); + if (user) { + user.name.should.be.oneOf(knownUsers); + user.id.toString().should.be.oneOf(knownUserIds); + } } - } - done(); + done(); + }); }); }); }); - }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should fetch Users with include scope on Posts - belongsTo', + 'should fetch Users with include scope on Posts - belongsTo', function(done) { Post.find({include: {relation: 'author', scope: {fields: ['name']}}}, function(err, posts) { @@ -1018,7 +1021,7 @@ describe('include', function() { }); bdd.itIf(connectorCapabilities.adhocSort === false, - 'should fetch Users with include scope on Posts - belongsTo - no sort', + 'should fetch Users with include scope on Posts - belongsTo - no sort', function(done) { Post.find({include: {relation: 'author', scope: {fields: ['name']}}}, function(err, posts) { @@ -1310,55 +1313,55 @@ describe('include', function() { it('including hasManyThrough should make only 3 db calls', function(done) { var self = this; Assembly.create([{name: 'sedan'}, {name: 'hatchback'}, - {name: 'SUV'}], - function(err, assemblies) { - Part.create([{partNumber: 'engine'}, {partNumber: 'bootspace'}, - {partNumber: 'silencer'}], - function(err, parts) { - async.each(parts, function(part, next) { - async.each(assemblies, function(assembly, next) { - if (assembly.name === 'SUV') { - return next(); - } - if (assembly.name === 'hatchback' && + {name: 'SUV'}], + function(err, assemblies) { + Part.create([{partNumber: 'engine'}, {partNumber: 'bootspace'}, + {partNumber: 'silencer'}], + function(err, parts) { + async.each(parts, function(part, next) { + async.each(assemblies, function(assembly, next) { + if (assembly.name === 'SUV') { + return next(); + } + if (assembly.name === 'hatchback' && part.partNumber === 'bootspace') { - return next(); - } - assembly.parts.add(part, function(err, data) { - next(); - }); - }, next); - }, function(err) { - var autos = connectorCapabilities.supportTwoOrMoreInq !== false ? - ['sedan', 'hatchback', 'SUV'] : ['sedan']; - var resultLength = connectorCapabilities.supportTwoOrMoreInq !== false ? 3 : 1; - var dbCalls = connectorCapabilities.supportTwoOrMoreInq !== false ? 3 : 5; - self.called = 0; - Assembly.find({ - where: { - name: { - inq: autos, - }, - }, - include: 'parts', - }, function(err, result) { - should.not.exist(err); - should.exists(result); - result.length.should.equal(resultLength); - // Please note the order of assemblies is random - var assemblies = {}; - result.forEach(function(r) { - assemblies[r.name] = r; - }); - if (autos.indexOf('sedan') >= 0) assemblies.sedan.parts().should.have.length(3); - if (autos.indexOf('hatchback') >= 0) assemblies.hatchback.parts().should.have.length(2); - if (autos.indexOf('SUV') >= 0) assemblies.SUV.parts().should.have.length(0); - self.called.should.eql(dbCalls); - done(); - }); + return next(); + } + assembly.parts.add(part, function(err, data) { + next(); }); + }, next); + }, function(err) { + var autos = connectorCapabilities.supportTwoOrMoreInq !== false ? + ['sedan', 'hatchback', 'SUV'] : ['sedan']; + var resultLength = connectorCapabilities.supportTwoOrMoreInq !== false ? 3 : 1; + var dbCalls = connectorCapabilities.supportTwoOrMoreInq !== false ? 3 : 5; + self.called = 0; + Assembly.find({ + where: { + name: { + inq: autos, + }, + }, + include: 'parts', + }, function(err, result) { + should.not.exist(err); + should.exists(result); + result.length.should.equal(resultLength); + // Please note the order of assemblies is random + var assemblies = {}; + result.forEach(function(r) { + assemblies[r.name] = r; + }); + if (autos.indexOf('sedan') >= 0) assemblies.sedan.parts().should.have.length(3); + if (autos.indexOf('hatchback') >= 0) assemblies.hatchback.parts().should.have.length(2); + if (autos.indexOf('SUV') >= 0) assemblies.SUV.parts().should.have.length(0); + self.called.should.eql(dbCalls); + done(); }); + }); }); + }); }); var dbCalls = connectorCapabilities.supportTwoOrMoreInq !== false ? 3 : 11; @@ -1667,9 +1670,9 @@ describe('Model instance with included relation .toJSON()', function() { createChallengers, createGameParticipations, createResults], - function(err) { - done(err); - }); + function(err) { + done(err); + }); }); function createChallengers(callback) { diff --git a/test/include_util.test.js b/test/include_util.test.js index da4c9a3a..cca11720 100644 --- a/test/include_util.test.js +++ b/test/include_util.test.js @@ -13,8 +13,8 @@ describe('include_util', function() { describe('#buildOneToOneIdentityMapWithOrigKeys', function() { it('should return an object with keys', function() { var objs = [ - {id: 11, letter: 'A'}, - {id: 22, letter: 'B'}, + {id: 11, letter: 'A'}, + {id: 22, letter: 'B'}, ]; var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id'); result.get(11).should.be.ok; @@ -36,19 +36,17 @@ describe('include_util', function() { result.get(11)['letter'].should.equal('HA!'); result.get(33)['letter'].should.equal('C'); }); - }); - describe('#buildOneToOneIdentityMapWithOrigKeys', function() { - it('should return an object with keys', function() { + + it('should return an object with no additional keys', function() { var objs = [ {id: 11, letter: 'A'}, {id: 22, letter: 'B'}, ]; var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id'); - result.get(11).should.be.ok; - result.get(22).should.be.ok; - result.getKeys().should.have.lengthOf(2); // no additional properties + result.getKeys().should.eql([11, 22]); // no additional properties }); }); + describe('#buildOneToManyIdentityMap', function() { it('should return an object with keys', function() { var objs = [ diff --git a/test/kvao/_helpers.js b/test/kvao/_helpers.js index 31c3bcf2..987faf35 100644 --- a/test/kvao/_helpers.js +++ b/test/kvao/_helpers.js @@ -15,7 +15,7 @@ function givenCacheItem(dataSourceFactory) { }; function givenModel(dataSourceFactory, modelName, -modelProperties, options) { + modelProperties, options) { const dataSource = dataSourceFactory(); const Model = dataSource.createModel(modelName, modelProperties); const p = 'deleteAll' in dataSource.connector ? diff --git a/test/kvao/get-set.suite.js b/test/kvao/get-set.suite.js index dfb2c3d4..7a5824a8 100644 --- a/test/kvao/get-set.suite.js +++ b/test/kvao/get-set.suite.js @@ -69,9 +69,9 @@ module.exports = function(dataSourceFactory, connectorCapabilities) { it('honours options.ttl', function() { return CacheItem.set('a-key', 'a-value', {ttl: TTL_PRECISION}) - .delay(2 * TTL_PRECISION) - .then(function() { return CacheItem.get('a-key'); }) - .then(function(value) { should.equal(value, null); }); + .delay(2 * TTL_PRECISION) + .then(function() { return CacheItem.get('a-key'); }) + .then(function(value) { should.equal(value, null); }); }); describe('get', function() { diff --git a/test/kvao/ttl.suite.js b/test/kvao/ttl.suite.js index 7b13488d..bca2b3dd 100644 --- a/test/kvao/ttl.suite.js +++ b/test/kvao/ttl.suite.js @@ -24,25 +24,25 @@ module.exports = function(dataSourceFactory, connectorCapabilities) { beforeEach(setupCacheItem); it('gets TTL when key with unexpired TTL exists - Promise API', - function() { - return Promise.resolve( + function() { + return Promise.resolve( CacheItem.set('a-key', 'a-value', {ttl: INITIAL_TTL})) - .delay(SMALL_DELAY) - .then(function() { return CacheItem.ttl('a-key'); }) - .then(function(ttl) { ttl.should.be.within(1, INITIAL_TTL); }); - }); + .delay(SMALL_DELAY) + .then(function() { return CacheItem.ttl('a-key'); }) + .then(function(ttl) { ttl.should.be.within(1, INITIAL_TTL); }); + }); it('gets TTL when key with unexpired TTL exists - Callback API', - function(done) { - CacheItem.set('a-key', 'a-value', {ttl: INITIAL_TTL}, function(err) { - if (err) return done(err); - CacheItem.ttl('a-key', function(err, ttl) { + function(done) { + CacheItem.set('a-key', 'a-value', {ttl: INITIAL_TTL}, function(err) { if (err) return done(err); - ttl.should.be.within(1, INITIAL_TTL); - done(); + CacheItem.ttl('a-key', function(err, ttl) { + if (err) return done(err); + ttl.should.be.within(1, INITIAL_TTL); + done(); + }); }); }); - }); it('succeeds when key without TTL exists', function() { return CacheItem.set('a-key', 'a-value') @@ -52,7 +52,7 @@ module.exports = function(dataSourceFactory, connectorCapabilities) { it('fails when getting TTL for a key with expired TTL', function() { return Promise.resolve( - CacheItem.set('expired-key', 'a-value', {ttl: TTL_PRECISION})) + CacheItem.set('expired-key', 'a-value', {ttl: TTL_PRECISION})) .delay(2 * TTL_PRECISION) .then(function() { return CacheItem.ttl('expired-key'); diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index 17757b47..5bb423fb 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -339,7 +339,7 @@ describe('DataSource define model', function() { it('supports plain model definitions', function() { var ds = new DataSource('memory'); -// define models + // define models var Post = ds.define('Post', { title: {type: String, length: 255}, content: {type: ModelBuilder.Text}, @@ -350,7 +350,7 @@ describe('DataSource define model', function() { published: {type: Boolean, default: false, index: true}, }); -// simpler way to describe model + // simpler way to describe model var User = ds.define('User', { name: String, bio: ModelBuilder.Text, @@ -362,7 +362,7 @@ describe('DataSource define model', function() { var Group = ds.define('Group', {group: String}); User.mixin(Group); -// define any custom method + // define any custom method User.prototype.getNameAndAge = function() { return this.name + ', ' + this.age; }; @@ -418,7 +418,7 @@ describe('DataSource define model', function() { }); }); -// should be able to attach a data source to an existing model + // should be able to attach a data source to an existing model var modelBuilder = new ModelBuilder(); var Color = modelBuilder.define('Color', { @@ -427,7 +427,7 @@ describe('DataSource define model', function() { Color.should.not.have.property('create'); -// attach + // attach ds.attach(Color); Color.should.have.property('create'); @@ -971,7 +971,7 @@ describe('DataSource connector types', function() { }); }); -describe('DataSource constructor', function() { +describe('DataSource._resolveConnector', function() { // Mocked require var loader = function(name) { if (name.indexOf('./connectors/') !== -1) { diff --git a/test/manipulation.test.js b/test/manipulation.test.js index 0f59b27a..988cdd1e 100644 --- a/test/manipulation.test.js +++ b/test/manipulation.test.js @@ -228,11 +228,11 @@ describe('manipulation', function() { should.exist(p); should.not.exists(p.name); return Person.findById(p.id) - .then(function(person) { - person.id.should.eql(p.id); - should.not.exists(person.name); - done(); - }); + .then(function(person) { + person.id.should.eql(p.id); + should.not.exists(person.name); + done(); + }); }).catch(done); }); @@ -528,20 +528,20 @@ describe('manipulation', function() { }); it('should have updated password hashed with updateAttribute', - function(done) { - StubUser.create({password: 'foo'}, function(err, created) { - if (err) return done(err); - created.updateAttribute('password', 'test', function(err, created) { + function(done) { + StubUser.create({password: 'foo'}, function(err, created) { if (err) return done(err); - created.password.should.equal('test-TEST'); - StubUser.findById(created.id, function(err, found) { + created.updateAttribute('password', 'test', function(err, created) { if (err) return done(err); - found.password.should.equal('test-TEST'); - done(); + created.password.should.equal('test-TEST'); + StubUser.findById(created.id, function(err, found) { + if (err) return done(err); + found.password.should.equal('test-TEST'); + done(); + }); }); }); }); - }); it('should reject created StubUser with empty password', function(done) { StubUser.create({email: 'b@example.com', password: ''}, function(err, createdUser) { @@ -574,14 +574,14 @@ describe('manipulation', function() { it('should update one attribute (promise variant)', function(done) { person.updateAttribute('name', 'Teddy Graham') - .then(function(p) { - return Person.all() - .then(function(ps) { - ps.should.have.lengthOf(1); - ps.pop().name.should.equal('Teddy Graham'); - done(); - }); - }).catch(done); + .then(function(p) { + return Person.all() + .then(function(ps) { + ps.should.have.lengthOf(1); + ps.pop().name.should.equal('Teddy Graham'); + done(); + }); + }).catch(done); }); it('should ignore undefined values on updateAttributes', function(done) { @@ -732,10 +732,10 @@ describe('manipulation', function() { it('should fail if an id value is to be changed on updateAttributes', function(done) { person.updateAttributes({id: person.id + 1, name: 'John'}, - function(err, p) { - should.exist(err); - done(); - }); + function(err, p) { + should.exist(err); + done(); + }); }); it('has an alias "patchAttributes"', function(done) { @@ -996,14 +996,14 @@ describe('manipulation', function() { }); it('fails when id does not exist in db & validate is false when using updateAttributes', - function(done) { - var unknownId = uid.fromConnector(db) || 123; - var post = new Post({id: unknownId}); - post.updateAttributes({title: 'updated title', content: 'AAA'}, {validate: false}, (err) => { - should(err).have.property('statusCode', 404); - done(); + function(done) { + var unknownId = uid.fromConnector(db) || 123; + var post = new Post({id: unknownId}); + post.updateAttributes({title: 'updated title', content: 'AAA'}, {validate: false}, (err) => { + should(err).have.property('statusCode', 404); + done(); + }); }); - }); it('works on create if the request does not include an id', function(done) { var post = {title: 'a', content: 'AAA'}; @@ -1053,45 +1053,45 @@ describe('manipulation', function() { it('works without options on create (promise variant)', function(done) { var post = {id: unknownId, title: 'a', content: 'AAA'}; Post.replaceOrCreate(post) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.id.should.eql(post.id); - p.should.not.have.property('_id'); - p.title.should.equal(post.title); - p.content.should.equal(post.content); - return Post.findById(p.id) .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); p.id.should.eql(post.id); - p.id.should.not.have.property('_id'); - p.title.should.equal(p.title); - p.content.should.equal(p.content); - done(); - }); - }) - .catch(done); + p.should.not.have.property('_id'); + p.title.should.equal(post.title); + p.content.should.equal(post.content); + return Post.findById(p.id) + .then(function(p) { + p.id.should.eql(post.id); + p.id.should.not.have.property('_id'); + p.title.should.equal(p.title); + p.content.should.equal(p.content); + done(); + }); + }) + .catch(done); }); it('works with options on create (promise variant)', function(done) { var post = {id: unknownId, title: 'a', content: 'AAA'}; Post.replaceOrCreate(post, {validate: false}) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.id.should.eql(post.id); - p.should.not.have.property('_id'); - p.title.should.equal(post.title); - p.content.should.equal(post.content); - return Post.findById(p.id) .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); p.id.should.eql(post.id); - p.id.should.not.have.property('_id'); - p.title.should.equal(p.title); - p.content.should.equal(p.content); - done(); - }); - }) - .catch(done); + p.should.not.have.property('_id'); + p.title.should.equal(post.title); + p.content.should.equal(post.content); + return Post.findById(p.id) + .then(function(p) { + p.id.should.eql(post.id); + p.id.should.not.have.property('_id'); + p.title.should.equal(p.title); + p.content.should.equal(p.content); + done(); + }); + }) + .catch(done); }); it('works without options on update (promise variant)', function(done) { @@ -1103,26 +1103,26 @@ describe('manipulation', function() { delete created.content; created.title = 'b'; return Post.replaceOrCreate(created) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.id.should.eql(created.id); - p.should.not.have.property('_id'); - p.title.should.equal('b'); - p.should.have.property('content', undefined); - p.should.have.property('comments', undefined); - - return Post.findById(created.id) .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); + p.id.should.eql(created.id); p.should.not.have.property('_id'); p.title.should.equal('b'); - should.not.exist(p.content); - should.not.exist(p.comments); - done(); + p.should.have.property('content', undefined); + p.should.have.property('comments', undefined); + + return Post.findById(created.id) + .then(function(p) { + p.should.not.have.property('_id'); + p.title.should.equal('b'); + should.not.exist(p.content); + should.not.exist(p.comments); + done(); + }); }); - }); }) - .catch(done); + .catch(done); }); it('works with options on update (promise variant)', function(done) { @@ -1134,26 +1134,26 @@ describe('manipulation', function() { delete created.content; created.title = 'b'; return Post.replaceOrCreate(created, {validate: false}) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.id.should.eql(created.id); - p.should.not.have.property('_id'); - p.title.should.equal('b'); - p.should.have.property('content', undefined); - p.should.have.property('comments', undefined); - - return Post.findById(created.id) .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); + p.id.should.eql(created.id); p.should.not.have.property('_id'); p.title.should.equal('b'); - should.not.exist(p.content); - should.not.exist(p.comments); - done(); + p.should.have.property('content', undefined); + p.should.have.property('comments', undefined); + + return Post.findById(created.id) + .then(function(p) { + p.should.not.have.property('_id'); + p.title.should.equal('b'); + should.not.exist(p.content); + should.not.exist(p.comments); + done(); + }); }); - }); }) - .catch(done); + .catch(done); }); it('works without options on update (callback variant)', function(done) { @@ -1279,6 +1279,7 @@ describe('manipulation', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('works on create if the request does not include an id', function(done) { var post = {title: 'a', content: 'AAA'}; Post.replaceOrCreate(post, function(err, p) { @@ -1289,19 +1290,20 @@ describe('manipulation', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('works on update if the request includes an existing id in db', function(done) { Post.create({title: 'a', content: 'AAA'}, - function(err, post) { + function(err, post) { + if (err) return done(err); + post = post.toObject(); + delete post.content; + post.title = 'b'; + Post.replaceOrCreate(post, function(err, p) { if (err) return done(err); - post = post.toObject(); - delete post.content; - post.title = 'b'; - Post.replaceOrCreate(post, function(err, p) { - if (err) return done(err); - p.id.should.eql(post.id); - done(); - }); + p.id.should.eql(post.id); + done(); }); + }); }); }); @@ -1333,20 +1335,20 @@ describe('manipulation', function() { }); it('should have updated password hashed with replaceAttributes', - function(done) { - StubUser.create({password: 'foo'}, function(err, created) { - if (err) return done(err); - created.replaceAttributes({password: 'test'}, function(err, created) { + function(done) { + StubUser.create({password: 'foo'}, function(err, created) { if (err) return done(err); - created.password.should.equal('test-TEST'); - StubUser.findById(created.id, function(err, found) { + created.replaceAttributes({password: 'test'}, function(err, created) { if (err) return done(err); - found.password.should.equal('test-TEST'); - done(); + created.password.should.equal('test-TEST'); + StubUser.findById(created.id, function(err, found) { + if (err) return done(err); + found.password.should.equal('test-TEST'); + done(); + }); }); }); }); - }); it('should reject updated empty password with replaceAttributes', function(done) { StubUser.create({password: 'abc123'}, function(err, createdUser) { @@ -1427,42 +1429,42 @@ describe('manipulation', function() { it('works without options(promise variant)', function(done) { Post.findById(postInstance.id) - .then(function(p) { - p.replaceAttributes({title: 'b'}) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.title.should.equal('b'); - p.should.have.property('content', undefined); - return Post.findById(postInstance.id) .then(function(p) { - p.title.should.equal('b'); - should.not.exist(p.content); - done(); - }); - }); - }) - .catch(done); + p.replaceAttributes({title: 'b'}) + .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); + p.title.should.equal('b'); + p.should.have.property('content', undefined); + return Post.findById(postInstance.id) + .then(function(p) { + p.title.should.equal('b'); + should.not.exist(p.content); + done(); + }); + }); + }) + .catch(done); }); it('works with options(promise variant)', function(done) { Post.findById(postInstance.id) - .then(function(p) { - p.replaceAttributes({title: 'b'}, {validate: false}) - .then(function(p) { - should.exist(p); - p.should.be.instanceOf(Post); - p.title.should.equal('b'); - p.should.have.property('content', undefined); - return Post.findById(postInstance.id) .then(function(p) { - p.title.should.equal('b'); - should.not.exist(p.content); - done(); - }); - }); - }) - .catch(done); + p.replaceAttributes({title: 'b'}, {validate: false}) + .then(function(p) { + should.exist(p); + p.should.be.instanceOf(Post); + p.title.should.equal('b'); + p.should.have.property('content', undefined); + return Post.findById(postInstance.id) + .then(function(p) { + p.title.should.equal('b'); + should.not.exist(p.content); + done(); + }); + }); + }) + .catch(done); }); it('should fail when changing id', function(done) { @@ -1584,18 +1586,18 @@ describe('manipulation', function() { Person.findOrCreate( {where: {name: 'Jed'}}, {name: 'Jed', gender: 'male'}) - .then(function(res) { - res.should.be.instanceOf(Array); - res.should.have.lengthOf(2); - var p = res[0]; - var created = res[1]; - p.should.be.instanceOf(Person); - p.name.should.equal('Jed'); - p.gender.should.equal('male'); - created.should.equal(false); - done(); - }) - .catch(done); + .then(function(res) { + res.should.be.instanceOf(Array); + res.should.have.lengthOf(2); + var p = res[0]; + var created = res[1]; + p.should.be.instanceOf(Person); + p.name.should.equal('Jed'); + p.gender.should.equal('male'); + created.should.equal(false); + done(); + }) + .catch(done); }); }); @@ -1690,47 +1692,47 @@ describe('manipulation', function() { }); it('should only delete instances that satisfy the where condition', - function(done) { - Person.deleteAll({name: 'John'}, function(err, info) { + function(done) { + Person.deleteAll({name: 'John'}, function(err, info) { + if (err) return done(err); + info.should.have.property('count', 1); + Person.find({where: {name: 'John'}}, function(err, data) { if (err) return done(err); - info.should.have.property('count', 1); - Person.find({where: {name: 'John'}}, function(err, data) { + data.should.have.length(0); + Person.find({where: {name: 'Jane'}}, function(err, data) { if (err) return done(err); - data.should.have.length(0); - Person.find({where: {name: 'Jane'}}, function(err, data) { - if (err) return done(err); - data.should.have.length(1); - done(); - }); + data.should.have.length(1); + done(); }); }); }); + }); it('should report zero deleted instances when no matches are found', - function(done) { - Person.deleteAll({name: 'does-not-match'}, function(err, info) { + function(done) { + Person.deleteAll({name: 'does-not-match'}, function(err, info) { + if (err) return done(err); + info.should.have.property('count', 0); + Person.count(function(err, count) { if (err) return done(err); - info.should.have.property('count', 0); - Person.count(function(err, count) { - if (err) return done(err); - count.should.equal(2); - done(); - }); + count.should.equal(2); + done(); }); }); + }); it('should delete all instances when the where condition is not provided', - function(done) { - Person.deleteAll(function(err, info) { + function(done) { + Person.deleteAll(function(err, info) { + if (err) return done(err); + info.should.have.property('count', 2); + Person.count(function(err, count) { if (err) return done(err); - info.should.have.property('count', 2); - Person.count(function(err, count) { - if (err) return done(err); - count.should.equal(0); - done(); - }); + count.should.equal(0); + done(); }); }); + }); }); bdd.describeIf(connectorCapabilities.reportDeletedCount === false && @@ -1757,55 +1759,59 @@ describe('manipulation', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should be defined as function', function() { Person.deleteAll.should.be.a.Function; Person.destroyAll.should.be.a.Function; }); + // eslint-disable-next-line mocha/no-identical-title it('should only delete instances that satisfy the where condition', - function(done) { - Person.deleteAll({id: idJohn}, function(err, info) { + function(done) { + Person.deleteAll({id: idJohn}, function(err, info) { + if (err) return done(err); + should.not.exist(info.count); + Person.find({where: {name: 'John'}}, function(err, data) { if (err) return done(err); - should.not.exist(info.count); - Person.find({where: {name: 'John'}}, function(err, data) { + should.not.exist(data.count); + data.should.have.length(0); + Person.find({where: {name: 'Jane'}}, function(err, data) { if (err) return done(err); - should.not.exist(data.count); - data.should.have.length(0); - Person.find({where: {name: 'Jane'}}, function(err, data) { - if (err) return done(err); - data.should.have.length(1); - done(); - }); + data.should.have.length(1); + done(); }); }); }); + }); + // eslint-disable-next-line mocha/no-identical-title it('should report zero deleted instances when no matches are found', - function(done) { - var unknownId = uid.fromConnector(db) || 1234567890; - Person.deleteAll({id: unknownId}, function(err, info) { + function(done) { + var unknownId = uid.fromConnector(db) || 1234567890; + Person.deleteAll({id: unknownId}, function(err, info) { + if (err) return done(err); + should.not.exist(info.count); + Person.count(function(err, count) { if (err) return done(err); - should.not.exist(info.count); - Person.count(function(err, count) { - if (err) return done(err); - count.should.equal(2); - done(); - }); + count.should.equal(2); + done(); }); }); + }); + // eslint-disable-next-line mocha/no-identical-title it('should delete all instances when the where condition is not provided', - function(done) { - Person.deleteAll(function(err, info) { + function(done) { + Person.deleteAll(function(err, info) { + if (err) return done(err); + should.not.exist(info.count); + Person.count(function(err, count) { if (err) return done(err); - should.not.exist(info.count); - Person.count(function(err, count) { - if (err) return done(err); - count.should.equal(0); - done(); - }); + count.should.equal(0); + done(); }); }); + }); }); describe('deleteById', function() { @@ -1903,22 +1909,22 @@ describe('manipulation', function() { bdd.itIf(connectorCapabilities.supportStrictDelete !== false, 'should allow delete(id) - ' + 'fail with error', function(done) { - Person.settings.strictDelete = true; - Person.findOne(function(err, u) { + Person.settings.strictDelete = true; + Person.findOne(function(err, u) { + if (err) return done(err); + u.delete(function(err, info) { if (err) return done(err); - u.delete(function(err, info) { - if (err) return done(err); - info.should.have.property('count', 1); - u.delete(function(err) { - should.exist(err); - err.message.should.equal('No instance with id ' + u.id + ' found for Person'); - err.should.have.property('code', 'NOT_FOUND'); - err.should.have.property('statusCode', 404); - done(); - }); + info.should.have.property('count', 1); + u.delete(function(err) { + should.exist(err); + err.message.should.equal('No instance with id ' + u.id + ' found for Person'); + err.should.have.property('code', 'NOT_FOUND'); + err.should.have.property('statusCode', 404); + done(); }); }); }); + }); }); describe('initialize', function() { @@ -1933,7 +1939,7 @@ describe('manipulation', function() { person.isNewRecord().should.be.true; }); - describe('Date $now function', function() { + describe('Date $now function (type: Date)', function() { var CustomModel; before(function(done) { @@ -1957,7 +1963,7 @@ describe('manipulation', function() { }); }); - describe('Date $now function', function() { + describe('Date $now function (type: String)', function() { var CustomModel; before(function(done) { @@ -2202,46 +2208,46 @@ describe('manipulation', function() { }); it('should not update instances that do not satisfy the where condition', - function(done) { - idHarry = uid.fromConnector(db) || undefined; - var filter = connectorCapabilities.updateWithOtherThanId === false ? - {id: idHarry} : {name: 'Harry Hoe'}; - Person.update(filter, {name: 'Marta Moe'}, function(err, + function(done) { + idHarry = uid.fromConnector(db) || undefined; + var filter = connectorCapabilities.updateWithOtherThanId === false ? + {id: idHarry} : {name: 'Harry Hoe'}; + Person.update(filter, {name: 'Marta Moe'}, function(err, info) { + if (err) return done(err); + if (connectorCapabilities.reportDeletedCount !== false) { + info.should.have.property('count', 0); + } else { + should.not.exist(info.count); + } + Person.find({where: {name: 'Harry Hoe'}}, function(err, people) { if (err) return done(err); - if (connectorCapabilities.reportDeletedCount !== false) { - info.should.have.property('count', 0); - } else { - should.not.exist(info.count); - } - Person.find({where: {name: 'Harry Hoe'}}, function(err, people) { - if (err) return done(err); - people.should.be.empty; - done(); - }); + people.should.be.empty; + done(); }); }); + }); it('should only update instances that satisfy the where condition', - function(done) { - var filter = connectorCapabilities.deleteWithOtherThanId === false ? - {id: idBrett} : {name: 'Brett Boe'}; - Person.update(filter, {name: 'Harry Hoe'}, function(err, + function(done) { + var filter = connectorCapabilities.deleteWithOtherThanId === false ? + {id: idBrett} : {name: 'Brett Boe'}; + Person.update(filter, {name: 'Harry Hoe'}, function(err, info) { + if (err) return done(err); + if (connectorCapabilities.reportDeletedCount !== false) { + info.should.have.property('count', 1); + } else { + should.not.exist(info.count); + } + Person.find({where: {age: 19}}, function(err, people) { if (err) return done(err); - if (connectorCapabilities.reportDeletedCount !== false) { - info.should.have.property('count', 1); - } else { - should.not.exist(info.count); - } - Person.find({where: {age: 19}}, function(err, people) { - if (err) return done(err); - people.should.have.length(1); - people[0].name.should.equal('Harry Hoe'); - done(); - }); + people.should.have.length(1); + people[0].name.should.equal('Harry Hoe'); + done(); }); }); + }); it('should reject updated empty password with updateAll', function(done) { StubUser.create({password: 'abc123'}, function(err, createdUser) { @@ -2277,16 +2283,16 @@ describe('manipulation', function() { bdd.itIf(connectorCapabilities.ignoreUndefinedConditionValue !== false, 'should ignore where ' + 'conditions with undefined values', function(done) { Person.update(filterBrett, {name: undefined, gender: 'male'}, - function(err, info) { - if (err) return done(err); - info.should.have.property('count', 1); - Person.find({where: filterBrett}, function(err, people) { + function(err, info) { if (err) return done(err); - people.should.have.length(1); - people[0].name.should.equal('Brett Boe'); - done(); + info.should.have.property('count', 1); + Person.find({where: filterBrett}, function(err, people) { + if (err) return done(err); + people.should.have.length(1); + people[0].name.should.equal('Brett Boe'); + done(); + }); }); - }); }); it('should not coerce invalid values provided in where conditions', function(done) { @@ -2355,16 +2361,16 @@ describe('manipulation', function() { Person.upsertWithWhere({id: 10}, {name: 'updated name'}, - function(err, updated) { - if (err) return done(err); - var result = updated.toObject(); - result.should.have.properties({ - id: instance.id, - name: 'updated name', - }); - should.equal(result.city, null); - done(); + function(err, updated) { + if (err) return done(err); + var result = updated.toObject(); + result.should.have.properties({ + id: instance.id, + name: 'updated name', }); + should.equal(result.city, null); + done(); + }); }); }); diff --git a/test/memory.test.js b/test/memory.test.js index ef902d8f..3462ba87 100644 --- a/test/memory.test.js +++ b/test/memory.test.js @@ -320,19 +320,19 @@ describe('Memory connector', function() { it('should successfully extract 1 user (Lennon) from the db', function(done) { User.find({where: {birthday: {between: [new Date(1970, 0), new Date(1990, 0)]}}}, - function(err, users) { - should(users.length).be.equal(1); - should(users[0].name).be.equal('John Lennon'); - done(); - }); + function(err, users) { + should(users.length).be.equal(1); + should(users[0].name).be.equal('John Lennon'); + done(); + }); }); it('should successfully extract 2 users from the db', function(done) { User.find({where: {birthday: {between: [new Date(1940, 0), new Date(1990, 0)]}}}, - function(err, users) { - should(users.length).be.equal(2); - done(); - }); + function(err, users) { + should(users.length).be.equal(2); + done(); + }); }); it('should successfully extract 2 users using implied and', function(done) { @@ -358,18 +358,18 @@ describe('Memory connector', function() { it('should successfully extract 2 users using date range', function(done) { User.find({where: {birthday: {between: [new Date(1940, 0).toISOString(), new Date(1990, 0).toISOString()]}}}, - function(err, users) { - should(users.length).be.equal(2); - done(); - }); + function(err, users) { + should(users.length).be.equal(2); + done(); + }); }); it('should successfully extract 0 user from the db', function(done) { User.find({where: {birthday: {between: [new Date(1990, 0), Date.now()]}}}, - function(err, users) { - should(users.length).be.equal(0); - done(); - }); + function(err, users) { + should(users.length).be.equal(0); + done(); + }); }); it('should successfully extract 2 users matching over array values', function(done) { @@ -503,14 +503,14 @@ describe('Memory connector', function() { }); it('should work when a regex is provided without the regexp operator', - function(done) { - User.find({where: {name: /John.*/i}}, function(err, users) { - should.not.exist(err); - users.length.should.equal(1); - users[0].name.should.equal('John Lennon'); - done(); - }); + function(done) { + User.find({where: {name: /John.*/i}}, function(err, users) { + should.not.exist(err); + users.length.should.equal(1); + users[0].name.should.equal('John Lennon'); + done(); }); + }); it('should support the regexp operator with regex strings', function(done) { User.find({where: {name: {regexp: '^J'}}}, function(err, users) { @@ -532,7 +532,7 @@ describe('Memory connector', function() { it('should support the regexp operator with regex objects', function(done) { User.find({where: {name: {regexp: new RegExp(/^J/)}}}, function(err, - users) { + users) { should.not.exist(err); users.length.should.equal(1); users[0].name.should.equal('John Lennon'); @@ -568,8 +568,8 @@ describe('Memory connector', function() { state: 'CA', zipCode: '95131', tags: [ - {tag: 'business'}, - {tag: 'rent'}, + {tag: 'business'}, + {tag: 'rent'}, ], }, friends: [ @@ -962,14 +962,6 @@ describe('Memory connector with options', function() { }); }); - it('should receive options from the find method', function(done) { - var opts = {transaction: 'tx2'}; - Post.find({}, opts, function(err, p) { - savedOptions.find.should.be.eql(opts); - done(err); - }); - }); - it('should treat first object arg as filter for find', function(done) { var filter = {title: 't1'}; Post.find(filter, function(err, p) { diff --git a/test/model-inheritance.test.js b/test/model-inheritance.test.js index 9663bfc2..cd69d900 100644 --- a/test/model-inheritance.test.js +++ b/test/model-inheritance.test.js @@ -76,19 +76,19 @@ describe('Model class inheritance', function() { // saving original getMergePolicy method let originalGetMergePolicy = base.getMergePolicy; - // the injected getMergePolicy method captures the provided configureModelMerge option + // the injected getMergePolicy method captures the provided configureModelMerge option base.getMergePolicy = function(options) { mergePolicy = options && options.configureModelMerge; return originalGetMergePolicy(options); }; - // calling extend() on base model calls base.getMergePolicy() internally - // child model settings are passed as 3rd parameter + // calling extend() on base model calls base.getMergePolicy() internally + // child model settings are passed as 3rd parameter const child = base.extend('child', {}, {configureModelMerge: newMergePolicy}); should.deepEqual(mergePolicy, newMergePolicy); - // restoring original getMergePolicy method + // restoring original getMergePolicy method base.getMergePolicy = originalGetMergePolicy; }); @@ -109,7 +109,7 @@ describe('Model class inheritance', function() { it('is inherited by child model', function() { const child = base.extend('child', {}, {configureModelMerge: true}); - // get mergePolicy from child + // get mergePolicy from child const mergePolicy = child.getMergePolicy({configureModelMerge: true}); should.deepEqual(mergePolicy, recommendedMergePolicy); }); @@ -128,8 +128,8 @@ describe('Model class inheritance', function() { }); const baseChild = modelBuilder.define('baseChild'); baseChild.attachTo(memory); - // the name of this must begin with a letter < b - // for this test to fail + // the name of this must begin with a letter < b + // for this test to fail const anotherChild = baseChild.extend('anotherChild'); assert(anotherChild.prototype instanceof baseChild); @@ -220,23 +220,23 @@ describe('Model class inheritance', function() { }); var Customer = User.extend('Customer', - {customerId: {type: String, id: true}}, { - defaultPermission: 'DENY', - acls: [ - { - principalType: 'ROLE', - principalId: '$unauthenticated', - permission: 'DENY', - }, - ], - relations: { - orders: { - type: 'hasMany', - model: 'Order', - }, + {customerId: {type: String, id: true}}, { + defaultPermission: 'DENY', + acls: [ + { + principalType: 'ROLE', + principalId: '$unauthenticated', + permission: 'DENY', }, - } - ); + ], + relations: { + orders: { + type: 'hasMany', + model: 'Order', + }, + }, + } + ); assert.deepEqual(User.settings, { // forceId is set to 'auto' in memory if idProp.generated && forceId !== false @@ -291,8 +291,8 @@ describe('Model class inheritance', function() { }); it('defines rank of ACLs according to model\'s inheritance rank', function() { - // a simple test is enough as we already fully tested option `{rank: true}` - // in tests with flag `configureModelMerge` + // a simple test is enough as we already fully tested option `{rank: true}` + // in tests with flag `configureModelMerge` const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, {acls: [ { @@ -336,7 +336,7 @@ describe('Model class inheritance', function() { }); it('replaces baseClass relations with matching subClass relations', function() { - // merge policy of settings.relations is {patch: true} + // merge policy of settings.relations is {patch: true} const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, { relations: { @@ -462,7 +462,7 @@ describe('Model class inheritance', function() { it('`{replace: true}` replaces base model array with sub model matching ' + 'array', function() { - // merge policy of settings.description is {replace: true} + // merge policy of settings.description is {replace: true} const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, { description: ['base', 'model', 'description'], @@ -515,7 +515,7 @@ describe('Model class inheritance', function() { it('`{replace: false}` adds distinct members of matching arrays from ' + 'base model and sub model', function() { - // merge policy of settings.hidden is {replace: false} + // merge policy of settings.hidden is {replace: false} const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, { hidden: ['firstProperty', 'secondProperty'], @@ -534,7 +534,7 @@ describe('Model class inheritance', function() { it('`{patch: true}` adds distinct inner properties of matching objects ' + 'from base model and sub model', function() { - // merge policy of settings.relations is {patch: true} + // merge policy of settings.relations is {patch: true} const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, { relations: { @@ -576,7 +576,7 @@ describe('Model class inheritance', function() { it('`{patch: true}` replaces baseClass inner properties with matching ' + 'subClass inner properties', function() { - // merge policy of settings.relations is {patch: true} + // merge policy of settings.relations is {patch: true} const modelBuilder = memory.modelBuilder; const base = modelBuilder.define('base', {}, { relations: { diff --git a/test/optional-validation.test.js b/test/optional-validation.test.js index 8ea7195d..e1ad5c25 100644 --- a/test/optional-validation.test.js +++ b/test/optional-validation.test.js @@ -22,9 +22,9 @@ describe('optional-validation', function() { before(function(done) { db = getSchema(); ModelWithForceId = db.createModel( - 'ModelWithForceId', - {name: String}, - {forceId: true}); + 'ModelWithForceId', + {name: String}, + {forceId: true}); User = db.define('User', { seq: {type: Number, index: true}, name: {type: String, index: true, sort: true}, @@ -115,26 +115,26 @@ describe('optional-validation', function() { describe('forceId', function() { context('replaceAttributes', function() { it('should not fail if you do not pass the Primary key in data object', - function(done) { - ModelWithForceId.create({name: 'foo'}, function(err, created) { - if (err) return done(err); - created.replaceAttributes({name: 'bar'}, function(err, data) { - done(err); + function(done) { + ModelWithForceId.create({name: 'foo'}, function(err, created) { + if (err) return done(err); + created.replaceAttributes({name: 'bar'}, function(err, data) { + done(err); + }); }); }); - }); it('should fail if you pass the Primary key in data object', - function(done) { - ModelWithForceId.create({name: 'foo'}, function(err, created) { - if (err) return done(err); - created.replaceAttributes({name: 'bar', id: 999}, - function(err, data) { - should.exist(err); - done(); + function(done) { + ModelWithForceId.create({name: 'foo'}, function(err, created) { + if (err) return done(err); + created.replaceAttributes({name: 'bar', id: 999}, + function(err, data) { + should.exist(err); + done(); + }); }); }); - }); }); }); @@ -167,28 +167,28 @@ describe('optional-validation', function() { describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, - expectValidationError(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on findOrCreate with validate:false with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, - expectCreateSuccess(INVALID_DATA, done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, + expectCreateSuccess(INVALID_DATA, done)); + }); it('should NOT throw on findOrCreate with validate:true with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, + expectCreateSuccess(done)); + }); it('should NOT throw on findOrCreate with validate:false with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, + expectCreateSuccess(done)); + }); it('should throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, expectValidationError(done)); @@ -201,28 +201,28 @@ describe('optional-validation', function() { describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: true}, - expectValidationError(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: false}, - expectChangeSuccess(INVALID_DATA, done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: false}, + expectChangeSuccess(INVALID_DATA, done)); + }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, + expectChangeSuccess(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, + expectChangeSuccess(done)); + }); // backwards compatible with validateUpsert it('should NOT throw on updateOrCreate(id) with invalid data', function(done) { @@ -310,17 +310,17 @@ describe('optional-validation', function() { }); it('returns an error when trying to update the id property when forceId is set to true', - function(done) { - ModelWithForceId.create({name: 'foo'}, function(err, model) { - if (err) return done(err); - model.updateAttributes({id: 123}, function(err) { - err.should.be.instanceOf(Error); - err.message.should.eql('id cannot be updated from ' + model.id + + function(done) { + ModelWithForceId.create({name: 'foo'}, function(err, model) { + if (err) return done(err); + model.updateAttributes({id: 123}, function(err) { + err.should.be.instanceOf(Error); + err.message.should.eql('id cannot be updated from ' + model.id + ' to 123 when forceId is set to true'); - done(); + done(); + }); }); }); - }); }); }); @@ -358,32 +358,32 @@ describe('optional-validation', function() { describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, - expectValidationError(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on findOrCreate with validate:false with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, - expectCreateSuccess(INVALID_DATA, done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, + expectCreateSuccess(INVALID_DATA, done)); + }); it('should NOT throw on findOrCreate with validate:true with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, + expectCreateSuccess(done)); + }); it('should NOT throw on findOrCreate with validate:false with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, + expectCreateSuccess(done)); + }); it('should NOT throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, - expectCreateSuccess(INVALID_DATA, done)); + expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on findOrCreate with valid data', function(done) { @@ -393,28 +393,28 @@ describe('optional-validation', function() { describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: true}, - expectValidationError(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: false}, - expectChangeSuccess(INVALID_DATA, done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: false}, + expectChangeSuccess(INVALID_DATA, done)); + }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, + expectChangeSuccess(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, + expectChangeSuccess(done)); + }); it('should NOT throw on updateOrCreate(id) with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, expectChangeSuccess(INVALID_DATA, done)); @@ -498,28 +498,28 @@ describe('optional-validation', function() { describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, - expectValidationError(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on findOrCreate with validate:false with invalid data', - function(done) { - User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, - expectCreateSuccess(INVALID_DATA, done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), INVALID_DATA, {validate: false}, + expectCreateSuccess(INVALID_DATA, done)); + }); it('should NOT throw on findOrCreate with validate:true with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: true}, + expectCreateSuccess(done)); + }); it('should NOT throw on findOrCreate with validate:false with valid data', - function(done) { - User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, - expectCreateSuccess(done)); - }); + function(done) { + User.findOrCreate(getNewWhere(), VALID_DATA, {validate: false}, + expectCreateSuccess(done)); + }); it('should throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, expectValidationError(done)); @@ -532,28 +532,28 @@ describe('optional-validation', function() { describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: true}, - expectValidationError(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: true}, + expectValidationError(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', - function(done) { - callUpdateOrCreateWithExistingUserId(null, {validate: false}, - expectChangeSuccess(INVALID_DATA, done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(null, {validate: false}, + expectChangeSuccess(INVALID_DATA, done)); + }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: true}, + expectChangeSuccess(done)); + }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', - function(done) { - callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, - expectChangeSuccess(done)); - }); + function(done) { + callUpdateOrCreateWithExistingUserId(NEW_NAME, {validate: false}, + expectChangeSuccess(done)); + }); it('should throw on updateOrCreate(id) with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, expectValidationError(done)); diff --git a/test/persistence-hooks.suite.js b/test/persistence-hooks.suite.js index d783f895..1882ee75 100644 --- a/test/persistence-hooks.suite.js +++ b/test/persistence-hooks.suite.js @@ -140,26 +140,26 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers the loaded hook multiple times when multiple instances exist when near filter is used', - function(done) { - var hookMonitorGeoModel; - hookMonitorGeoModel = new HookMonitor({includeModelName: false}); + function(done) { + var hookMonitorGeoModel; + hookMonitorGeoModel = new HookMonitor({includeModelName: false}); - function monitorHookExecutionGeoModel(hookNames) { - hookMonitorGeoModel.install(GeoModel, hookNames); - } + function monitorHookExecutionGeoModel(hookNames) { + hookMonitorGeoModel.install(GeoModel, hookNames); + } - monitorHookExecutionGeoModel(); + monitorHookExecutionGeoModel(); - var query = { - where: {location: {near: '10,5'}}, - }; - GeoModel.find(query, function(err, list) { - if (err) return done(err); + var query = { + where: {location: {near: '10,5'}}, + }; + GeoModel.find(query, function(err, list) { + if (err) return done(err); - hookMonitorGeoModel.names.should.eql(['access', 'loaded', 'loaded']); - done(); + hookMonitorGeoModel.names.should.eql(['access', 'loaded', 'loaded']); + done(); + }); }); - }); it('applies updates from `loaded` hook when near filter is used', function(done) { GeoModel.observe('loaded', function(ctx, next) { @@ -179,23 +179,23 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates to one specific instance from `loaded` hook when near filter is used', - function(done) { - GeoModel.observe('loaded', function(ctx, next) { - if (ctx.data.name === 'Rome') - ctx.data.name = 'Berlin'; - next(); - }); + function(done) { + GeoModel.observe('loaded', function(ctx, next) { + if (ctx.data.name === 'Rome') + ctx.data.name = 'Berlin'; + next(); + }); - var query = { - where: {location: {near: '10,5'}}, - }; + var query = { + where: {location: {near: '10,5'}}, + }; - GeoModel.find(query, function(err, list) { - if (err) return done(err); - list.map(get('name')).should.containEql('Berlin', 'Tokyo'); - done(); + GeoModel.find(query, function(err, list) { + if (err) return done(err); + list.map(get('name')).should.containEql('Berlin', 'Tokyo'); + done(); + }); }); - }); it('applies updates from `loaded` hook when near filter is not used', function(done) { TestModel.observe('loaded', function(ctx, next) { @@ -211,33 +211,33 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates to one specific instance from `loaded` hook when near filter is not used', - function(done) { - TestModel.observe('loaded', function(ctx, next) { - if (ctx.data.name === 'first') - ctx.data.name = 'Paris'; - next(); - }); + function(done) { + TestModel.observe('loaded', function(ctx, next) { + if (ctx.data.name === 'first') + ctx.data.name = 'Paris'; + next(); + }); - TestModel.find(function(err, list) { - if (err) return done(err); - list.map(get('name')).should.eql(['Paris', 'second']); - done(); - }); - }); - - it('should not trigger hooks for geo queries, if notify is false', - function(done) { - monitorHookExecution(); - - TestModel.find( - {where: {geo: {near: '10,20'}}}, - {notify: false}, - function(err, list) { + TestModel.find(function(err, list) { if (err) return done(err); - hookMonitor.names.should.be.empty(); + list.map(get('name')).should.eql(['Paris', 'second']); done(); }); - }); + }); + + it('should not trigger hooks for geo queries, if notify is false', + function(done) { + monitorHookExecution(); + + TestModel.find( + {where: {geo: {near: '10,20'}}}, + {notify: false}, + function(err, list) { + if (err) return done(err); + hookMonitor.names.should.be.empty(); + done(); + }); + }); it('should apply updates from `access` hook', function(done) { TestModel.observe('access', function(ctx, next) { @@ -805,12 +805,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { record.id.should.eql(existingInstance.id); - // `findOrCreate` creates a new instance of the object everytime. - // So, `data.id` as well as `currentInstance.id` always matches - // the newly generated UID. - // Hence, the test below asserts both `data.id` and - // `currentInstance.id` to match getLastGeneratedUid(). - // On same lines, it also asserts `isNewInstance` to be true. + // `findOrCreate` creates a new instance of the object everytime. + // So, `data.id` as well as `currentInstance.id` always matches + // the newly generated UID. + // Hence, the test below asserts both `data.id` and + // `currentInstance.id` to match getLastGeneratedUid(). + // On same lines, it also asserts `isNewInstance` to be true. ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: getLastGeneratedUid(), @@ -952,9 +952,9 @@ module.exports = function(dataSource, should, connectorCapabilities) { record.id.should.eql(existingInstance.id); - // After the call to `connector.findOrCreate`, since the record - // already exists, `data.id` matches `existingInstance.id` - // as against the behaviour noted for `persist` hook + // After the call to `connector.findOrCreate`, since the record + // already exists, `data.id` matches `existingInstance.id` + // as against the behaviour noted for `persist` hook ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: existingInstance.id, @@ -2258,7 +2258,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); if (!dataSource.connector.replaceById) { - describe.skip('replaceById - not implemented', function() {}); + describe.skip('replaceOrCreate - not implemented', function() {}); } else { describe('PersistedModel.replaceOrCreate', function() { it('triggers hooks in the correct order on create', function(done) { @@ -2400,19 +2400,19 @@ module.exports = function(dataSource, should, connectorCapabilities) { it('triggers `before save` hookon create', function(done) { TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate({id: existingInstance.id, name: 'new name'}, - function(err, instance) { - if (err) - return done(err); + function(err, instance) { + if (err) + return done(err); - var expectedContext = aCtxForModel(TestModel, { - instance: instance, + var expectedContext = aCtxForModel(TestModel, { + instance: instance, + }); + + if (!dataSource.connector.replaceOrCreate) { + expectedContext.isNewInstance = false; + } + done(); }); - - if (!dataSource.connector.replaceOrCreate) { - expectedContext.isNewInstance = false; - } - done(); - }); }); it('triggers `before save` hook on replace', function(done) { @@ -2573,7 +2573,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { expected.isNewInstance = isNewInstanceFlag ? - true : undefined; + true : undefined; ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); @@ -2597,7 +2597,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { expected.isNewInstance = isNewInstanceFlag ? - false : undefined; + false : undefined; ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); @@ -2632,7 +2632,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { expected.isNewInstance = isNewInstanceFlag ? - false : undefined; + false : undefined; ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); @@ -2656,7 +2656,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }; expected.isNewInstance = isNewInstanceFlag ? - true : undefined; + true : undefined; ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); @@ -3162,14 +3162,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.upsertWithWhere({id: existingInstance.id}, - {name: 'new name', extra: 'new extra'}, - function(err, instance) { - if (err) return done(err); - ctxRecorder.records.should.eql(aCtxForModel(TestModel, {query: { - where: {id: existingInstance.id}, - }})); - done(); - }); + {name: 'new name', extra: 'new extra'}, + function(err, instance) { + if (err) return done(err); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, {query: { + where: {id: existingInstance.id}, + }})); + done(); + }); }); it('triggers hooks only once', function(done) { @@ -3236,27 +3236,27 @@ module.exports = function(dataSource, should, connectorCapabilities) { TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.upsertWithWhere({id: existingInstance.id}, - {id: existingInstance.id, name: 'updated name'}, - function(err, instance) { - if (err) return done(err); - var expectedContext = aCtxForModel(TestModel, { - where: {id: existingInstance.id}, - data: { - id: existingInstance.id, - name: 'updated name', - }, - }); - if (!dataSource.connector.upsertWithWhere) { - // the difference between `existingInstance` and the following - // plain-data object is `currentInstance` the missing fields are - // null in `currentInstance`, wehere as in `existingInstance` they - // are undefined; please see other tests for example see: - // test for "PersistedModel.create triggers `persist` hook" - expectedContext.currentInstance = {id: existingInstance.id, name: 'first', extra: null}; - } - ctxRecorder.records.should.eql(expectedContext); - done(); - }); + {id: existingInstance.id, name: 'updated name'}, + function(err, instance) { + if (err) return done(err); + var expectedContext = aCtxForModel(TestModel, { + where: {id: existingInstance.id}, + data: { + id: existingInstance.id, + name: 'updated name', + }, + }); + if (!dataSource.connector.upsertWithWhere) { + // the difference between `existingInstance` and the following + // plain-data object is `currentInstance` the missing fields are + // null in `currentInstance`, wehere as in `existingInstance` they + // are undefined; please see other tests for example see: + // test for "PersistedModel.create triggers `persist` hook" + expectedContext.currentInstance = {id: existingInstance.id, name: 'first', extra: null}; + } + ctxRecorder.records.should.eql(expectedContext); + done(); + }); }); it('triggers `before save` hook on create', function(done) { @@ -3287,12 +3287,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); TestModel.upsertWithWhere({id: existingInstance.id}, - {name: 'updated name'}, - function(err, instance) { - if (err) return done(err); - instance.name.should.equal('hooked'); - done(); - }); + {name: 'updated name'}, + function(err, instance) { + if (err) return done(err); + instance.name.should.equal('hooked'); + done(); + }); }); it('applies updates from `before save` hook on create', function(done) { @@ -3429,11 +3429,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { it('emits error when `loaded` hook fails', function(done) { TestModel.observe('loaded', nextWithError(expectedError)); TestModel.upsertWithWhere({id: 'new-id'}, - {id: 'new-id', name: 'a name'}, - function(err, instance) { - [err].should.eql([expectedError]); - done(); - }); + {id: 'new-id', name: 'a name'}, + function(err, instance) { + [err].should.eql([expectedError]); + done(); + }); }); it('triggers `after save` hook on update', function(done) { diff --git a/test/relations.test.js b/test/relations.test.js index b77988ba..96d95377 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -113,14 +113,14 @@ describe('relations', function() { it('should create record on scope with promises', function(done) { Book.create() - .then(function(book) { - return book.chapters.create() - .then(function(c) { - should.exist(c); - c.bookId.should.eql(book.id); - done(); - }); - }).catch(done); + .then(function(book) { + return book.chapters.create() + .then(function(c) { + should.exist(c); + c.bookId.should.eql(book.id); + done(); + }); + }).catch(done); }); it('should create a batch of records on scope', function(done) { @@ -150,14 +150,14 @@ describe('relations', function() { ]; Book.create(function(err, book) { book.chapters.create(chapters) - .then(function(chs) { - should.exist(chs); - chs.should.have.lengthOf(chapters.length); - chs.forEach(function(c) { - c.bookId.should.eql(book.id); - }); - done(); - }).catch(done); + .then(function(chs) { + should.exist(chs); + chs.should.have.lengthOf(chapters.length); + chs.forEach(function(c) { + c.bookId.should.eql(book.id); + }); + done(); + }).catch(done); }); }); @@ -196,37 +196,37 @@ describe('relations', function() { it('should fetch all scoped instances with promises', function(done) { Book.create() - .then(function(book) { - return book.chapters.create({name: 'a'}) - .then(function() { - return book.chapters.create({name: 'z'}); - }) - .then(function() { - return book.chapters.create({name: 'c'}); - }) - .then(function() { - return verify(book); - }); - }).catch(done); + .then(function(book) { + return book.chapters.create({name: 'a'}) + .then(function() { + return book.chapters.create({name: 'z'}); + }) + .then(function() { + return book.chapters.create({name: 'c'}); + }) + .then(function() { + return verify(book); + }); + }).catch(done); function verify(book) { return book.chapters.find() - .then(function(ch) { - should.exist(ch); - ch.should.have.lengthOf(3); - var chapters = book.chapters(); - chapters.should.eql(ch); - return book.chapters.find() - .then(function(c) { - should.exist(c); + .then(function(ch) { + should.exist(ch); ch.should.have.lengthOf(3); - var acz = ['a', 'c', 'z']; - acz.should.containEql(c[0].name); - acz.should.containEql(c[1].name); - acz.should.containEql(c[2].name); - done(); + var chapters = book.chapters(); + chapters.should.eql(ch); + return book.chapters.find() + .then(function(c) { + should.exist(c); + ch.should.have.lengthOf(3); + var acz = ['a', 'c', 'z']; + acz.should.containEql(c[0].name); + acz.should.containEql(c[1].name); + acz.should.containEql(c[2].name); + done(); + }); }); - }); } }); @@ -322,27 +322,27 @@ describe('relations', function() { it('should find scoped record with promises', function(done) { var id; Book.create() - .then(function(book) { - return book.chapters.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return book.chapters.create({name: 'z'}); - }) - .then(function() { - return book.chapters.create({name: 'c'}); - }) - .then(function() { - return verify(book); - }); - }).catch(done); + .then(function(book) { + return book.chapters.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return book.chapters.create({name: 'z'}); + }) + .then(function() { + return book.chapters.create({name: 'c'}); + }) + .then(function() { + return verify(book); + }); + }).catch(done); function verify(book) { return book.chapters.findById(id) - .then(function(ch) { - should.exist(ch); - ch.id.should.eql(id); - done(); - }); + .then(function(ch) { + should.exist(ch); + ch.id.should.eql(id); + done(); + }); } }); @@ -372,29 +372,29 @@ describe('relations', function() { it('should count scoped records - all and filtered with promises', function(done) { Book.create() - .then(function(book) { - book.chapters.create({name: 'a'}) - .then(function() { - return book.chapters.create({name: 'b'}); - }) - .then(function() { - return book.chapters.create({name: 'c'}); - }) - .then(function() { - return verify(book); - }); - }).catch(done); + .then(function(book) { + book.chapters.create({name: 'a'}) + .then(function() { + return book.chapters.create({name: 'b'}); + }) + .then(function() { + return book.chapters.create({name: 'c'}); + }) + .then(function() { + return verify(book); + }); + }).catch(done); function verify(book) { return book.chapters.count() - .then(function(count) { - count.should.equal(3); - return book.chapters.count({name: 'b'}); - }) - .then(function(count) { - count.should.equal(1); - done(); - }); + .then(function(count) { + count.should.equal(3); + return book.chapters.count({name: 'b'}); + }) + .then(function(count) { + count.should.equal(1); + done(); + }); } }); @@ -427,26 +427,26 @@ describe('relations', function() { it('should update scoped record with promises', function(done) { var id; Book.create() - .then(function(book) { - return book.chapters.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return book.chapters.updateById(id, {name: 'aa'}); + .then(function(book) { + return book.chapters.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return book.chapters.updateById(id, {name: 'aa'}); + }) + .then(function(ch) { + return verify(book); + }); }) - .then(function(ch) { - return verify(book); - }); - }) - .catch(done); + .catch(done); function verify(book) { return book.chapters.findById(id) - .then(function(ch) { - should.exist(ch); - ch.id.should.eql(id); - ch.name.should.equal('aa'); - done(); - }); + .then(function(ch) { + should.exist(ch); + ch.id.should.eql(id); + ch.name.should.equal('aa'); + done(); + }); } }); @@ -472,24 +472,24 @@ describe('relations', function() { it('should destroy scoped record with promises', function(done) { var id; Book.create() - .then(function(book) { - return book.chapters.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return book.chapters.destroy(id); + .then(function(book) { + return book.chapters.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return book.chapters.destroy(id); + }) + .then(function(ch) { + return verify(book); + }); }) - .then(function(ch) { - return verify(book); - }); - }) - .catch(done); + .catch(done); function verify(book) { return book.chapters.findById(id) - .catch(function(err) { - should.exist(err); - done(); - }); + .catch(function(err) { + should.exist(err); + done(); + }); } }); @@ -518,26 +518,26 @@ describe('relations', function() { it('should check existence of a scoped record with promises', function(done) { var id; Book.create() - .then(function(book) { - return book.chapters.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return book.chapters.create({name: 'z'}); - }) - .then(function() { - return book.chapters.create({name: 'c'}); - }) - .then(function() { - return verify(book); - }); - }).catch(done); + .then(function(book) { + return book.chapters.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return book.chapters.create({name: 'z'}); + }) + .then(function() { + return book.chapters.create({name: 'c'}); + }) + .then(function() { + return verify(book); + }); + }).catch(done); function verify(book) { return book.chapters.exists(id) - .then(function(flag) { - flag.should.be.eql(true); - done(); - }); + .then(function(flag) { + flag.should.be.eql(true); + done(); + }); } }); @@ -553,12 +553,12 @@ describe('relations', function() { it('should check ignore related data on creation with promises - array', function(done) { Book.create({chapters: []}) - .then(function(book) { - book.chapters.should.be.a.function; - var obj = book.toObject(); - should.not.exist(obj.chapters); - done(); - }).catch(done); + .then(function(book) { + book.chapters.should.be.a.function; + var obj = book.toObject(); + should.not.exist(obj.chapters); + done(); + }).catch(done); }); it('should check ignore related data on creation - object', function(done) { @@ -573,12 +573,12 @@ describe('relations', function() { it('should check ignore related data on creation with promises - object', function(done) { Book.create({chapters: {}}) - .then(function(book) { - book.chapters.should.be.a.function; - var obj = book.toObject(); - should.not.exist(obj.chapters); - done(); - }).catch(done); + .then(function(book) { + book.chapters.should.be.a.function; + var obj = book.toObject(); + should.not.exist(obj.chapters); + done(); + }).catch(done); }); }); }); @@ -630,17 +630,17 @@ describe('relations', function() { it('should create record on scope with promises', function(done) { Physician.create() - .then(function(physician) { - return physician.patients.create() - .then(function(patient) { - should.exist(patient); - return Appointment.find({where: {physicianId: physician.id, patientId: patient.id}}) - .then(function(apps) { - apps.should.have.lengthOf(1); - done(); - }); - }); - }).catch(done); + .then(function(physician) { + return physician.patients.create() + .then(function(patient) { + should.exist(patient); + return Appointment.find({where: {physicianId: physician.id, patientId: patient.id}}) + .then(function(apps) { + apps.should.have.lengthOf(1); + done(); + }); + }); + }).catch(done); }); it('should create multiple records on scope', function(done) { @@ -655,11 +655,11 @@ describe('relations', function() { physicianId: physician.id, patientId: patient.id, }}, - function(err, apps) { - if (err) return done(err); - apps.should.have.lengthOf(1); - next(); - }); + function(err, apps) { + if (err) return done(err); + apps.should.have.lengthOf(1); + next(); + }); } async.forEach(patients, verifyPatient, done); }); @@ -669,24 +669,24 @@ describe('relations', function() { it('should create multiple records on scope with promises', function(done) { var async = require('async'); Physician.create() - .then(function(physician) { - return physician.patients.create([{}, {}]) - .then(function(patients) { - should.exist(patients); - patients.should.have.lengthOf(2); - function verifyPatient(patient, next) { - Appointment.find({where: { - physicianId: physician.id, - patientId: patient.id, - }}) - .then(function(apps) { - apps.should.have.lengthOf(1); - next(); + .then(function(physician) { + return physician.patients.create([{}, {}]) + .then(function(patients) { + should.exist(patients); + patients.should.have.lengthOf(2); + function verifyPatient(patient, next) { + Appointment.find({where: { + physicianId: physician.id, + patientId: patient.id, + }}) + .then(function(apps) { + apps.should.have.lengthOf(1); + next(); + }); + } + async.forEach(patients, verifyPatient, done); }); - } - async.forEach(patients, verifyPatient, done); - }); - }).catch(done); + }).catch(done); }); it('should fetch all scoped instances', function(done) { @@ -714,28 +714,28 @@ describe('relations', function() { it('should fetch all scoped instances with promises', function(done) { Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function() { - return physician.patients.create({name: 'z'}); - }) - .then(function() { - return physician.patients.create({name: 'c'}); - }) - .then(function() { - return verify(physician); - }); - }).catch(done); + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function() { + return physician.patients.create({name: 'z'}); + }) + .then(function() { + return physician.patients.create({name: 'c'}); + }) + .then(function() { + return verify(physician); + }); + }).catch(done); function verify(physician) { return physician.patients.find() - .then(function(ch) { - var patients = physician.patients(); - should.equal(patients, ch); + .then(function(ch) { + var patients = physician.patients(); + should.equal(patients, ch); - should.exist(ch); - ch.should.have.lengthOf(3); - done(); - }); + should.exist(ch); + ch.should.have.lengthOf(3); + done(); + }); } }); @@ -747,16 +747,16 @@ describe('relations', function() { context('with filter skip', function() { bdd.itIf(connectorCapabilities.supportPagination !== false, - 'skips the first patient', function(done) { - physician.patients({skip: 1, order: 'sequence'}, function(err, ch) { - if (err) return done(err); - should.exist(ch); - ch.should.have.lengthOf(2); - ch[0].name.should.eql('z'); - ch[1].name.should.eql('c'); - done(); + 'skips the first patient', function(done) { + physician.patients({skip: 1, order: 'sequence'}, function(err, ch) { + if (err) return done(err); + should.exist(ch); + ch.should.have.lengthOf(2); + ch[0].name.should.eql('z'); + ch[1].name.should.eql('c'); + done(); + }); }); - }); }); context('with filter order', function() { it('orders the result by patient name', function(done) { @@ -1020,19 +1020,19 @@ describe('relations', function() { it('should find scoped record with promises', function(done) { var id; Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return physician.patients.create({name: 'z'}); - }) - .then(function() { - return physician.patients.create({name: 'c'}); - }) - .then(function() { - return verify(physician); - }); - }).catch(done); + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return physician.patients.create({name: 'z'}); + }) + .then(function() { + return physician.patients.create({name: 'c'}); + }) + .then(function() { + return verify(physician); + }); + }).catch(done); function verify(physician) { return physician.patients.findById(id, function(err, ch) { @@ -1073,32 +1073,32 @@ describe('relations', function() { it('should allow to use include syntax on related data with promises', function(done) { Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(patient) { - return Address.create({name: 'z'}) - .then(function(address) { - patient.address(address); - return patient.save() - .then(function() { - return verify(physician, address.id); + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(patient) { + return Address.create({name: 'z'}) + .then(function(address) { + patient.address(address); + return patient.save() + .then(function() { + return verify(physician, address.id); + }); + }); }); - }); - }); - }).catch(done); + }).catch(done); function verify(physician, addressId) { return physician.patients.find({include: 'address'}) - .then(function(ch) { - should.exist(ch); - ch.should.have.lengthOf(1); - ch[0].addressId.toString().should.eql(addressId.toString()); - var address = ch[0].address(); - should.exist(address); - address.should.be.an.instanceof(Address); - address.name.should.equal('z'); - done(); - }); + .then(function(ch) { + should.exist(ch); + ch.should.have.lengthOf(1); + ch[0].addressId.toString().should.eql(addressId.toString()); + var address = ch[0].address(); + should.exist(address); + address.should.be.an.instanceof(Address); + address.name.should.equal('z'); + done(); + }); } }); @@ -1131,75 +1131,75 @@ describe('relations', function() { it('should update scoped record with promises', function(done) { var id; Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return physician.patients.updateById(id, {name: 'aa'}) - .then(function(ch) { - return verify(physician); - }); - }); - }).catch(done); + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return physician.patients.updateById(id, {name: 'aa'}) + .then(function(ch) { + return verify(physician); + }); + }); + }).catch(done); function verify(physician) { return physician.patients.findById(id) - .then(function(ch) { - should.exist(ch); - ch.id.should.eql(id); - ch.name.should.equal('aa'); - done(); - }); + .then(function(ch) { + should.exist(ch); + ch.id.should.eql(id); + ch.name.should.equal('aa'); + done(); + }); } }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should destroy scoped record', function(done) { - var id; - Physician.create(function(err, physician) { - physician.patients.create({name: 'a'}, function(err, ch) { - id = ch.id; - physician.patients.destroy(id, function(err, ch) { - verify(physician); + 'should destroy scoped record', function(done) { + var id; + Physician.create(function(err, physician) { + physician.patients.create({name: 'a'}, function(err, ch) { + id = ch.id; + physician.patients.destroy(id, function(err, ch) { + verify(physician); + }); }); }); + + function verify(physician) { + physician.patients.findById(id, function(err, ch) { + should.exist(err); + done(); + }); + } }); - function verify(physician) { - physician.patients.findById(id, function(err, ch) { - should.exist(err); - done(); - }); - } - }); - bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should destroy scoped record with promises', function(done) { - var id; - Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return physician.patients.destroy(id) - .then(function(ch) { - return verify(physician); - }); - }); - }).catch(done); + 'should destroy scoped record with promises', function(done) { + var id; + Physician.create() + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return physician.patients.destroy(id) + .then(function(ch) { + return verify(physician); + }); + }); + }).catch(done); - function verify(physician) { - return physician.patients.findById(id) - .then(function(ch) { - should.not.exist(ch); - done(); - }) - .catch(function(err) { - should.exist(err); - done(); - }); - } - }); + function verify(physician) { + return physician.patients.findById(id) + .then(function(ch) { + should.not.exist(ch); + done(); + }) + .catch(function(err) { + should.exist(err); + done(); + }); + } + }); it('should check existence of a scoped record', function(done) { var id; @@ -1227,26 +1227,26 @@ describe('relations', function() { it('should check existence of a scoped record with promises', function(done) { var id; Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(ch) { - id = ch.id; - return physician.patients.create({name: 'z'}); - }) - .then(function() { - return physician.patients.create({name: 'c'}); - }) - .then(function() { - return verify(physician); - }); - }).catch(done); + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return physician.patients.create({name: 'z'}); + }) + .then(function() { + return physician.patients.create({name: 'c'}); + }) + .then(function() { + return verify(physician); + }); + }).catch(done); function verify(physician) { return physician.patients.exists(id) - .then(function(flag) { - flag.should.be.eql(true); - done(); - }); + .then(function(flag) { + flag.should.be.eql(true); + done(); + }); } }); @@ -1267,19 +1267,19 @@ describe('relations', function() { it('should allow to add connection with instance with promises', function(done) { Physician.create({name: 'ph1'}) - .then(function(physician) { - return Patient.create({name: 'pa1'}) - .then(function(patient) { - return physician.patients.add(patient) - .then(function(app) { - should.exist(app); - app.should.be.an.instanceOf(Appointment); - app.physicianId.should.eql(physician.id); - app.patientId.should.eql(patient.id); - done(); - }); - }); - }).catch(done); + .then(function(physician) { + return Patient.create({name: 'pa1'}) + .then(function(patient) { + return physician.patients.add(patient) + .then(function(app) { + should.exist(app); + app.should.be.an.instanceOf(Appointment); + app.physicianId.should.eql(physician.id); + app.patientId.should.eql(patient.id); + done(); + }); + }); + }).catch(done); }); it('should allow to add connection with through data', function(done) { @@ -1302,68 +1302,68 @@ describe('relations', function() { it('should allow to add connection with through data with promises', function(done) { Physician.create({name: 'ph1'}) - .then(function(physician) { - return Patient.create({name: 'pa1'}) - .then(function(patient) { - var now = Date.now(); - return physician.patients.add(patient, {date: new Date(now)}) - .then(function(app) { - should.exist(app); - app.should.be.an.instanceOf(Appointment); - app.physicianId.should.eql(physician.id); - app.patientId.should.eql(patient.id); - app.patientId.should.eql(patient.id); - app.date.getTime().should.equal(now); + .then(function(physician) { + return Patient.create({name: 'pa1'}) + .then(function(patient) { + var now = Date.now(); + return physician.patients.add(patient, {date: new Date(now)}) + .then(function(app) { + should.exist(app); + app.should.be.an.instanceOf(Appointment); + app.physicianId.should.eql(physician.id); + app.patientId.should.eql(patient.id); + app.patientId.should.eql(patient.id); + app.date.getTime().should.equal(now); + done(); + }); + }); + }).catch(done); + }); + + bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, + 'should allow to remove connection with instance', function(done) { + var id; + Physician.create(function(err, physician) { + physician.patients.create({name: 'a'}, function(err, patient) { + id = patient.id; + physician.patients.remove(id, function(err, ch) { + verify(physician); + }); + }); + }); + + function verify(physician) { + physician.patients.exists(id, function(err, flag) { + if (err) return done(err); + flag.should.be.eql(false); done(); }); - }); - }).catch(done); - }); - - bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should allow to remove connection with instance', function(done) { - var id; - Physician.create(function(err, physician) { - physician.patients.create({name: 'a'}, function(err, patient) { - id = patient.id; - physician.patients.remove(id, function(err, ch) { - verify(physician); - }); - }); + } }); - function verify(physician) { - physician.patients.exists(id, function(err, flag) { - if (err) return done(err); - flag.should.be.eql(false); - done(); - }); - } - }); - bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should allow to remove connection with instance with promises', function(done) { - var id; - Physician.create() - .then(function(physician) { - return physician.patients.create({name: 'a'}) - .then(function(patient) { - id = patient.id; - return physician.patients.remove(id) - .then(function(ch) { - return verify(physician); - }); - }); - }).catch(done); + 'should allow to remove connection with instance with promises', function(done) { + var id; + Physician.create() + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(patient) { + id = patient.id; + return physician.patients.remove(id) + .then(function(ch) { + return verify(physician); + }); + }); + }).catch(done); - function verify(physician) { - return physician.patients.exists(id) - .then(function(flag) { - flag.should.be.eql(false); - done(); - }); - } - }); + function verify(physician) { + return physician.patients.exists(id) + .then(function(flag) { + flag.should.be.eql(false); + done(); + }); + } + }); beforeEach(function(done) { Appointment.destroyAll(function(err) { @@ -1644,15 +1644,15 @@ describe('relations', function() { it('should create record on scope with promises', function(done) { Book.create({type: 'fiction'}) - .then(function(book) { - return book.chapters.create() - .then(function(c) { - should.exist(c); - c.bookId.should.eql(book.id); - c.bookType.should.equal('fiction'); - done(); - }); - }).catch(done); + .then(function(book) { + return book.chapters.create() + .then(function(c) { + should.exist(c); + c.bookId.should.eql(book.id); + c.bookType.should.equal('fiction'); + done(); + }); + }).catch(done); }); }); @@ -1693,19 +1693,19 @@ describe('relations', function() { it('should create record on scope with promises', function(done) { Category.create() - .then(function(c) { - return c.jobs.create({type: 'book'}) - .then(function(p) { - p.categoryId.should.eql(c.id); - p.type.should.equal('book'); - return c.jobs.create({type: 'widget'}) - .then(function(p) { - p.categoryId.should.eql(c.id); - p.type.should.equal('widget'); - done(); - }); - }); - }).catch(done); + .then(function(c) { + return c.jobs.create({type: 'book'}) + .then(function(p) { + p.categoryId.should.eql(c.id); + p.type.should.equal('book'); + return c.jobs.create({type: 'widget'}) + .then(function(p) { + p.categoryId.should.eql(c.id); + p.type.should.equal('widget'); + done(); + }); + }); + }).catch(done); }); it('should find records on scope', function(done) { @@ -1721,14 +1721,14 @@ describe('relations', function() { it('should find records on scope with promises', function(done) { Category.findOne() - .then(function(c) { - return c.jobs.find(); - }) - .then(function(jobs) { - jobs.should.have.length(2); - done(); - }) - .catch(done); + .then(function(c) { + return c.jobs.find(); + }) + .then(function(jobs) { + jobs.should.have.length(2); + done(); + }) + .catch(done); }); it('should find record on scope - filtered', function(done) { @@ -1745,15 +1745,15 @@ describe('relations', function() { it('should find record on scope with promises - filtered', function(done) { Category.findOne() - .then(function(c) { - return c.jobs.find({where: {type: 'book'}}); - }) - .then(function(jobs) { - jobs.should.have.length(1); - jobs[0].type.should.equal('book'); - done(); - }) - .catch(done); + .then(function(c) { + return c.jobs.find({where: {type: 'book'}}); + }) + .then(function(jobs) { + jobs.should.have.length(1); + jobs[0].type.should.equal('book'); + done(); + }) + .catch(done); }); // So why not just do the above? In LoopBack, the context @@ -1777,6 +1777,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find records on scope', function(done) { Category.findOne(function(err, c) { should.not.exists(err); @@ -1801,6 +1802,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find record on scope - scoped', function(done) { Category.findOne(function(err, c) { should.not.exists(err); @@ -1827,27 +1829,27 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should delete records on scope - scoped', function(done) { - Category.findOne(function(err, c) { - should.not.exists(err); - c.jobType = 'tool'; // temporary, for scoping - c.jobs.destroyAll(function(err, result) { - done(err); + 'should delete records on scope - scoped', function(done) { + Category.findOne(function(err, c) { + should.not.exists(err); + c.jobType = 'tool'; // temporary, for scoping + c.jobs.destroyAll(function(err, result) { + done(err); + }); }); }); - }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should find record on scope - verify', function(done) { - Category.findOne(function(err, c) { - should.not.exists(err); - c.jobs(function(err, jobs) { + 'should find record on scope - verify', function(done) { + Category.findOne(function(err, c) { should.not.exists(err); - jobs.should.have.length(2); - done(err); + c.jobs(function(err, jobs) { + should.not.exists(err); + jobs.should.have.length(2); + done(err); + }); }); }); - }); }); describe('relations validation', function() { @@ -2060,15 +2062,15 @@ describe('relations', function() { it('should create polymorphic relation with promises - article', function(done) { Article.create({name: 'Article 1'}) - .then(function(article) { - return article.packshot.create({name: 'Packshot'}) - .then(function(pic) { - should.exist(pic); - pic.imageableId.should.eql(article.id); - pic.imageableType.should.equal('Article'); - done(); - }); - }).catch(done); + .then(function(article) { + return article.packshot.create({name: 'Packshot'}) + .then(function(pic) { + should.exist(pic); + pic.imageableId.should.eql(article.id); + pic.imageableType.should.equal('Article'); + done(); + }); + }).catch(done); }); it('should create polymorphic relation - reader', function(done) { @@ -2126,15 +2128,15 @@ describe('relations', function() { it('should find polymorphic relation with promises - employee', function(done) { Employee.findOne() - .then(function(employee) { - return employee.mugshot.get() - .then(function(pic) { - pic.name.should.equal('Mugshot'); - pic.imageableId.toString().should.eql(employee.id.toString()); - pic.imageableType.should.equal('Employee'); - done(); - }); - }).catch(done); + .then(function(employee) { + return employee.mugshot.get() + .then(function(pic) { + pic.name.should.equal('Mugshot'); + pic.imageableId.toString().should.eql(employee.id.toString()); + pic.imageableType.should.equal('Employee'); + done(); + }); + }).catch(done); }); it('should find inverse polymorphic relation - article', function(done) { @@ -2274,15 +2276,15 @@ describe('relations', function() { it('should create polymorphic relation with promises - article', function(done) { Article.create({name: 'Article 1'}) - .then(function(article) { - return article.packshot.create({name: 'Packshot'}) - .then(function(pic) { - should.exist(pic); - pic.oid.toString().should.equal(article.username.toString()); - pic.type.should.equal('Article'); - done(); - }); - }).catch(done); + .then(function(article) { + return article.packshot.create({name: 'Packshot'}) + .then(function(pic) { + should.exist(pic); + pic.oid.toString().should.equal(article.username.toString()); + pic.type.should.equal('Article'); + done(); + }); + }).catch(done); }); it('should create polymorphic relation - employee', function(done) { @@ -2602,39 +2604,39 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should include the inverse of polymorphic relation', function(done) { - Picture.find({include: 'imageable'}, function(err, pics) { - if (err) return done(err); - pics.should.have.length(2); + 'should include the inverse of polymorphic relation', function(done) { + Picture.find({include: 'imageable'}, function(err, pics) { + if (err) return done(err); + pics.should.have.length(2); - const actual = pics.map( - function(pic) { - return {imageName: pic.name, name: pic.imageable().name}; - }); + const actual = pics.map( + function(pic) { + return {imageName: pic.name, name: pic.imageable().name}; + }); - actual.should.containDeep([ - {name: 'Article 1', imageName: 'Article Pic'}, - {name: 'Employee 1', imageName: 'Employee Pic'}, - ]); + actual.should.containDeep([ + {name: 'Article 1', imageName: 'Article Pic'}, + {name: 'Employee 1', imageName: 'Employee Pic'}, + ]); - done(); + done(); + }); }); - }); bdd.itIf(connectorCapabilities.adhocSort === false, - 'should include the inverse of polymorphic relation w/o adhocSort', function(done) { - Picture.find({include: 'imageable'}, function(err, pics) { - if (err) return done(err); - pics.should.have.length(2); - var names = ['Article Pic', 'Employee Pic']; - var imageables = ['Article 1', 'Employee 1']; - names.should.containEql(pics[0].name); - names.should.containEql(pics[1].name); - imageables.should.containEql(pics[0].imageable().name); - imageables.should.containEql(pics[1].imageable().name); - done(); + 'should include the inverse of polymorphic relation w/o adhocSort', function(done) { + Picture.find({include: 'imageable'}, function(err, pics) { + if (err) return done(err); + pics.should.have.length(2); + var names = ['Article Pic', 'Employee Pic']; + var imageables = ['Article 1', 'Employee 1']; + names.should.containEql(pics[0].name); + names.should.containEql(pics[1].name); + imageables.should.containEql(pics[0].imageable().name); + imageables.should.containEql(pics[1].imageable().name); + done(); + }); }); - }); it('should assign a polymorphic relation', function(done) { Article.create({name: 'Article 2'}, function(err, article) { @@ -2647,6 +2649,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find polymorphic items - article', function(done) { Article.findOne({where: {name: 'Article 2'}}, function(err, article) { should.not.exists(err); @@ -2659,6 +2662,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find the inverse of polymorphic relation - article', function(done) { Picture.findOne({where: {name: 'Sample'}}, function(err, p) { if (err) return done(err); @@ -2902,19 +2906,21 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should create polymorphic through model', function(done) { if (!anotherPicture) return done(); PictureLink.findOne({where: {pictureId: anotherPicture.id, imageableType: 'Article'}}, - function(err, link) { - if (err) return done(err); - link.pictureId.toString().should.eql(anotherPicture.id.toString()); - link.imageableId.toString().should.eql(article.id.toString()); - link.imageableType.should.equal('Article'); - done(); - }); + function(err, link) { + if (err) return done(err); + link.pictureId.toString().should.eql(anotherPicture.id.toString()); + link.imageableId.toString().should.eql(article.id.toString()); + link.imageableType.should.equal('Article'); + done(); + }); }); var anotherArticle, anotherEmployee; + // eslint-disable-next-line mocha/no-identical-title it('should add to a polymorphic relation - article', function(done) { Article.create({name: 'Article 2'}, function(err, article) { if (err) return done(err); @@ -2927,6 +2933,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should add to a polymorphic relation - article', function(done) { Employee.create({name: 'Employee 2'}, function(err, reader) { if (err) return done(err); @@ -3000,15 +3007,15 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should remove from a polymorphic relation - article', function(done) { - if (!article || !anotherPicture) return done(); - Article.findById(article.id, function(err, article) { - article.pictures.remove(anotherPicture.id, function(err) { - if (err) return done(err); - done(); + 'should remove from a polymorphic relation - article', function(done) { + if (!article || !anotherPicture) return done(); + Article.findById(article.id, function(err, article) { + article.pictures.remove(anotherPicture.id, function(err) { + if (err) return done(err); + done(); + }); }); }); - }); bdd.itIf(connectorCapabilities.cloudantCompatible !== false, 'should find polymorphic items - article', function(done) { @@ -3018,7 +3025,7 @@ describe('relations', function() { // If deleteWithOtherThanId is not implemented, the above test is skipped and // the remove did not take place. Thus +1. var expectedLength = connectorCapabilities.deleteWithOtherThanId !== false ? - 2 : 3; + 2 : 3; pics.should.have.length(expectedLength); const names = pics.map(p => p.name); @@ -3032,6 +3039,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should check if polymorphic relation exists - article', function(done) { if (!article) return done(); Article.findById(article.id, function(err, article) { @@ -3242,23 +3250,23 @@ describe('relations', function() { List.hasMany('todos', {model: Item}); db.automigrate(['List', 'Item', 'Fear', 'Find'], function() { List.create({name: 'List 1'}) - .then(function(list) { - listId = list.id; - should.exist(list); - return list.todos.create({name: 'Item 1'}); - }) - .then(function(todo) { - itemId = todo.id; - return todo.list.get() - .then(function(l) { - should.exist(l); - l.should.be.an.instanceOf(List); - todo.list().id.should.eql(l.id); - todo.list().name.should.equal('List 1'); - done(); - }); - }) - .catch(done); + .then(function(list) { + listId = list.id; + should.exist(list); + return list.todos.create({name: 'Item 1'}); + }) + .then(function(todo) { + itemId = todo.id; + return todo.list.get() + .then(function(l) { + should.exist(l); + l.should.be.an.instanceOf(List); + todo.list().id.should.eql(l.id); + todo.list().name.should.equal('List 1'); + done(); + }); + }) + .catch(done); }); }); @@ -3358,18 +3366,18 @@ describe('relations', function() { var mind; Fear.beforeCreate = function(next) { this.mind.create() - .then(function(m) { - mind = m; - next(); - }).catch(next); + .then(function(m) { + mind = m; + next(); + }).catch(next); }; Fear.create() - .then(function(fear) { - should.exists(fear); - fear.mindId.should.eql(mind.id); - should.exists(fear.mind()); - done(); - }).catch(done); + .then(function(fear) { + should.exists(fear); + fear.mindId.should.eql(mind.id); + should.exists(fear.mind()); + done(); + }).catch(done); }); }); @@ -3416,35 +3424,35 @@ describe('relations', function() { it('should create record on scope with promises', function(done) { var p = new Passport({name: 'Passport', notes: 'Some notes...'}); p.person.create({name: 'Fred', age: 36}) - .then(function(person) { - p.personId.should.eql(person.id); - person.name.should.equal('Fred'); - person.passportNotes.should.equal('Some notes...'); - return p.save(); - }) - .then(function(passport) { - done(); - }) - .catch(done); + .then(function(person) { + p.personId.should.eql(person.id); + person.name.should.equal('Fred'); + person.passportNotes.should.equal('Some notes...'); + return p.save(); + }) + .then(function(passport) { + done(); + }) + .catch(done); }); it('should find record on scope with promises', function(done) { Passport.findOne() - .then(function(p) { - if (connectorCapabilities.adhocSort !== false) { + .then(function(p) { + if (connectorCapabilities.adhocSort !== false) { // We skip the check if adhocSort is not supported because // the first row returned may or may not be the same - p.personId.should.eql(personCreated.id); - } - return p.person.get(); - }) - .then(function(person) { - person.name.should.equal('Fred'); - person.should.have.property('age', undefined); - person.should.have.property('passportNotes', undefined); - done(); - }) - .catch(done); + p.personId.should.eql(personCreated.id); + } + return p.person.get(); + }) + .then(function(person) { + person.name.should.equal('Fred'); + person.should.have.property('age', undefined); + person.should.have.property('passportNotes', undefined); + done(); + }) + .catch(done); }); }); @@ -3491,12 +3499,12 @@ describe('relations', function() { it('should find record with embedded data with promises', function(done) { Passport.findOne() - .then(function(p) { - var data = p.toObject(true); - data.person.id.should.eql(p.personId); - data.person.name.should.equal('Fred'); - done(); - }).catch(done); + .then(function(p) { + var data = p.toObject(true); + data.person.id.should.eql(p.personId); + data.person.name.should.equal('Fred'); + done(); + }).catch(done); }); }); @@ -3578,23 +3586,23 @@ describe('relations', function() { it('can be used to query data with promises', function(done) { db.automigrate(['Supplier', 'Account'], function() { Supplier.create({name: 'Supplier 1'}) - .then(function(supplier) { - supplierId = supplier.id; - should.exist(supplier); - return supplier.account.create({accountNo: 'a01'}) - .then(function(account) { - return supplier.account.get(); + .then(function(supplier) { + supplierId = supplier.id; + should.exist(supplier); + return supplier.account.create({accountNo: 'a01'}) + .then(function(account) { + return supplier.account.get(); + }) + .then(function(act) { + accountId = act.id; + should.exist(act); + act.should.be.an.instanceOf(Account); + supplier.account().id.should.eql(act.id); + act.supplierName.should.equal(supplier.name); + done(); + }); }) - .then(function(act) { - accountId = act.id; - should.exist(act); - act.should.be.an.instanceOf(Account); - supplier.account().id.should.eql(act.id); - act.supplierName.should.equal(supplier.name); - done(); - }); - }) - .catch(done); + .catch(done); }); }); @@ -3628,15 +3636,15 @@ describe('relations', function() { it('should update the related item on scope with promises', function(done) { Supplier.findById(supplierId) - .then(function(supplier) { - should.exist(supplier); - return supplier.account.update({supplierName: 'Supplier B'}); - }) - .then(function(act) { - act.supplierName.should.equal('Supplier B'); - done(); - }) - .catch(done); + .then(function(supplier) { + should.exist(supplier); + return supplier.account.update({supplierName: 'Supplier B'}); + }) + .then(function(act) { + act.supplierName.should.equal('Supplier B'); + done(); + }) + .catch(done); }); it('should error trying to change the foreign key in the update', function(done) { @@ -3647,11 +3655,11 @@ describe('relations', function() { should.exist(supplier); supplier.account.update({supplierName: 'Supplier A', supplierId: sid}, - function(err, act) { - should.exist(err); - err.message.should.startWith('Cannot override foreign key'); - done(); - }); + function(err, act) { + should.exist(err); + err.message.should.startWith('Cannot override foreign key'); + done(); + }); }); }); }); @@ -3663,12 +3671,12 @@ describe('relations', function() { should.exist(supplier); supplier.account.update({supplierName: 'Supplier A', supplierId: supplierId}, - function(err, act) { - if (err) return done(err); - act.supplierName.should.equal('Supplier A'); - act.supplierId.toString().should.eql(supplierId.toString()); - done(); - }); + function(err, act) { + if (err) return done(err); + act.supplierName.should.equal('Supplier A'); + act.supplierId.toString().should.eql(supplierId.toString()); + done(); + }); }); }); }); @@ -3688,16 +3696,16 @@ describe('relations', function() { it('should get the related item on scope with promises', function(done) { Supplier.findById(supplierId) - .then(function(supplier) { - should.exist(supplier); - return supplier.account.get(); - }) - .then(function(act) { - should.exist(act); - act.supplierName.should.equal('Supplier A'); - done(); - }) - .catch(done); + .then(function(supplier) { + should.exist(supplier); + return supplier.account.get(); + }) + .then(function(act) { + should.exist(act); + act.supplierName.should.equal('Supplier A'); + done(); + }) + .catch(done); }); it('should destroy the related item on scope', function(done) { @@ -3713,17 +3721,17 @@ describe('relations', function() { it('should destroy the related item on scope with promises', function(done) { Supplier.findById(supplierId) - .then(function(supplier) { - should.exist(supplier); - return supplier.account.create({accountNo: 'a01'}) - .then(function(account) { - return supplier.account.destroy(); + .then(function(supplier) { + should.exist(supplier); + return supplier.account.create({accountNo: 'a01'}) + .then(function(account) { + return supplier.account.destroy(); + }) + .then(function(err) { + done(); + }); }) - .then(function(err) { - done(); - }); - }) - .catch(done); + .catch(done); }); it('should get the related item on scope - verify', function(done) { @@ -3740,15 +3748,15 @@ describe('relations', function() { it('should get the related item on scope with promises - verify', function(done) { Supplier.findById(supplierId) - .then(function(supplier) { - should.exist(supplier); - return supplier.account.get(); - }) - .then(function(act) { - should.not.exist(act); - done(); - }) - .catch(done); + .then(function(supplier) { + should.exist(supplier); + return supplier.account.get(); + }) + .then(function(act) { + should.not.exist(act); + done(); + }) + .catch(done); }); it('should have deleted related item', function(done) { @@ -3804,74 +3812,74 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.supportUpdateWithoutId !== false, - 'should not find record that does not match scope', function(done) { - Account.updateAll({block: true}, function(err) { - if (err) return done(err); - Supplier.findById(supplierId, function(err, supplier) { - supplier.account(function(err, account) { - should.not.exists(account); - done(); + 'should not find record that does not match scope', function(done) { + Account.updateAll({block: true}, function(err) { + if (err) return done(err); + Supplier.findById(supplierId, function(err, supplier) { + supplier.account(function(err, account) { + should.not.exists(account); + done(); + }); }); }); }); - }); bdd.itIf(connectorCapabilities.supportUpdateWithoutId !== false, - 'should not include record that does not match scope', function(done) { - Account.updateAll({block: true}, function(err) { - if (err) return done(err); - Supplier.findById(supplierId, {include: 'account'}, function(err, supplier) { - should.not.exists(supplier.toJSON().account); - supplier.account(function(err, account) { - should.not.exists(account); - done(); + 'should not include record that does not match scope', function(done) { + Account.updateAll({block: true}, function(err) { + if (err) return done(err); + Supplier.findById(supplierId, {include: 'account'}, function(err, supplier) { + should.not.exists(supplier.toJSON().account); + supplier.account(function(err, account) { + should.not.exists(account); + done(); + }); }); }); }); - }); it('can be used to query data with promises', function(done) { db.automigrate(['Supplier', 'Account'], function() { Supplier.create({name: 'Supplier 1'}) - .then(function(supplier) { - supplierId = supplier.id; - should.exist(supplier); - return supplier.account.create({accountNo: 'a01', block: false}) - .then(function(account) { - return supplier.account.get(); + .then(function(supplier) { + supplierId = supplier.id; + should.exist(supplier); + return supplier.account.create({accountNo: 'a01', block: false}) + .then(function(account) { + return supplier.account.get(); + }) + .then(function(act) { + accountId = act.id; + should.exist(act); + act.should.be.an.instanceOf(Account); + should.exist(act.block); + act.block.should.be.false; + supplier.account().id.should.eql(act.id); + act.supplierName.should.equal(supplier.name); + done(); + }); }) - .then(function(act) { - accountId = act.id; - should.exist(act); - act.should.be.an.instanceOf(Account); - should.exist(act.block); - act.block.should.be.false; - supplier.account().id.should.eql(act.id); - act.supplierName.should.equal(supplier.name); - done(); - }); - }) - .catch(done); + .catch(done); }); }); bdd.itIf(connectorCapabilities.supportUpdateWithoutId !== false, - 'should find record that match scope with promises', function(done) { - Account.updateAll({block: true}) - .then(function() { - return Supplier.findById(supplierId); - }) - .then(function(supplier) { - return supplier.account.get(); - }) - .then(function(account) { - should.not.exist(account); - done(); - }) - .catch(function(err) { - done(); + 'should find record that match scope with promises', function(done) { + Account.updateAll({block: true}) + .then(function() { + return Supplier.findById(supplierId); + }) + .then(function(supplier) { + return supplier.account.get(); + }) + .then(function(account) { + should.not.exist(account); + done(); + }) + .catch(function(err) { + done(); + }); }); - }); }); describe('hasOne with non standard id', function() { @@ -4163,22 +4171,22 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should destroy all related instances', function(done) { - Article.create(function(err, article) { - if (err) return done(err); - article.tagNames.create({name: 'popular'}, function(err, t) { + 'should destroy all related instances', function(done) { + Article.create(function(err, article) { if (err) return done(err); - article.tagNames.destroyAll(function(err) { + article.tagNames.create({name: 'popular'}, function(err, t) { if (err) return done(err); - article.tagNames(true, function(err, list) { + article.tagNames.destroyAll(function(err) { if (err) return done(err); - list.should.have.length(0); - done(); + article.tagNames(true, function(err, list) { + if (err) return done(err); + list.should.have.length(0); + done(); + }); }); }); }); }); - }); it('should allow to add connection with instance', function(done) { Article.findOne(function(e, article) { @@ -4196,91 +4204,91 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should allow to remove connection with instance', function(done) { - Article.findOne(function(e, article) { - article.tagNames(function(e, tags) { - var len = tags.length; - tags.should.not.be.empty; - article.tagNames.remove(tags[0], function(e) { - should.not.exist(e); - article.tagNames(true, function(e, tags) { - tags.should.have.lengthOf(len - 1); - done(); + 'should allow to remove connection with instance', function(done) { + Article.findOne(function(e, article) { + article.tagNames(function(e, tags) { + var len = tags.length; + tags.should.not.be.empty; + article.tagNames.remove(tags[0], function(e) { + should.not.exist(e); + article.tagNames(true, function(e, tags) { + tags.should.have.lengthOf(len - 1); + done(); + }); }); }); }); }); - }); it('should allow to create instances on scope with promises', function(done) { db.automigrate(['Article', 'TagName', 'ArticleTagName'], function() { Article.create() - .then(function(article) { - return article.tagNames.create({name: 'popular'}) - .then(function(t) { - t.should.be.an.instanceOf(TagName); - return ArticleTag.findOne() - .then(function(at) { - should.exist(at); - at.tagNameId.toString().should.eql(t.id.toString()); - at.articleId.toString().should.eql(article.id.toString()); - done(); - }); - }); - }).catch(done); + .then(function(article) { + return article.tagNames.create({name: 'popular'}) + .then(function(t) { + t.should.be.an.instanceOf(TagName); + return ArticleTag.findOne() + .then(function(at) { + should.exist(at); + at.tagNameId.toString().should.eql(t.id.toString()); + at.articleId.toString().should.eql(article.id.toString()); + done(); + }); + }); + }).catch(done); }); }); it('should allow to fetch scoped instances with promises', function(done) { Article.findOne() - .then(function(article) { - return article.tagNames.find() - .then(function(tags) { - should.exist(tags); - article.tagNames().should.eql(tags); - done(); - }); - }).catch(done); + .then(function(article) { + return article.tagNames.find() + .then(function(tags) { + should.exist(tags); + article.tagNames().should.eql(tags); + done(); + }); + }).catch(done); }); it('should allow to add connection with instance with promises', function(done) { Article.findOne() - .then(function(article) { - return TagName.create({name: 'awesome'}) - .then(function(tag) { - return article.tagNames.add(tag) - .then(function(at) { - should.exist(at); - at.should.be.an.instanceOf(ArticleTag); - at.tagNameId.should.eql(tag.id); - at.articleId.should.eql(article.id); - done(); - }); - }); - }) - .catch(done); + .then(function(article) { + return TagName.create({name: 'awesome'}) + .then(function(tag) { + return article.tagNames.add(tag) + .then(function(at) { + should.exist(at); + at.should.be.an.instanceOf(ArticleTag); + at.tagNameId.should.eql(tag.id); + at.articleId.should.eql(article.id); + done(); + }); + }); + }) + .catch(done); }); bdd.itIf(connectorCapabilities.deleteWithOtherThanId !== false, - 'should allow to remove connection with instance with promises', function(done) { - Article.findOne() - .then(function(article) { - return article.tagNames.find() - .then(function(tags) { - var len = tags.length; - tags.should.not.be.empty; - return article.tagNames.remove(tags[0]) - .then(function() { - return article.tagNames.find(); + 'should allow to remove connection with instance with promises', function(done) { + Article.findOne() + .then(function(article) { + return article.tagNames.find() + .then(function(tags) { + var len = tags.length; + tags.should.not.be.empty; + return article.tagNames.remove(tags[0]) + .then(function() { + return article.tagNames.find(); + }) + .then(function(tags) { + tags.should.have.lengthOf(len - 1); + done(); + }); + }); }) - .then(function(tags) { - tags.should.have.lengthOf(len - 1); - done(); - }); - }); - }) - .catch(done); - }); + .catch(done); + }); it('should set targetClass on scope property', function() { should.equal(Article.prototype.tagNames._targetClass, 'TagName'); @@ -4294,19 +4302,19 @@ describe('relations', function() { Article.find({ where: {id: article.id}, include: {relation: 'tagNames', scope: {fields: ['name']}}}, - function(e, articles) { - should.not.exist(e); - articles.should.have.property('length', 1); - var a = articles[0].toJSON(); - a.should.have.property('title', 'a1'); - a.should.have.property('tagNames'); - a.tagNames.should.have.property('length', 1); - var n = a.tagNames[0]; - n.should.have.property('name', 't1'); - n.should.have.property('flag', undefined); - n.id.should.eql(t.id); - done(); - }); + function(e, articles) { + should.not.exist(e); + articles.should.have.property('length', 1); + var a = articles[0].toJSON(); + a.should.have.property('title', 'a1'); + a.should.have.property('tagNames'); + a.tagNames.should.have.property('length', 1); + var n = a.tagNames[0]; + n.should.have.property('name', 't1'); + n.should.have.property('flag', undefined); + n.id.should.eql(t.id); + done(); + }); }); }); }); @@ -4320,19 +4328,19 @@ describe('relations', function() { Article.find({ where: {id: article.id}, include: {relation: 'tagNames', scope: {where: {flag: '2'}}}}, - function(e, articles) { - should.not.exist(e); - articles.should.have.property('length', 1); - var a = articles[0].toJSON(); - a.should.have.property('title', 'a2'); - a.should.have.property('tagNames'); - a.tagNames.should.have.property('length', 1); - var n = a.tagNames[0]; - n.should.have.property('name', 't2'); - n.should.have.property('flag', '2'); - n.id.should.eql(t2.id); - done(); - }); + function(e, articles) { + should.not.exist(e); + articles.should.have.property('length', 1); + var a = articles[0].toJSON(); + a.should.have.property('title', 'a2'); + a.should.have.property('tagNames'); + a.tagNames.should.have.property('length', 1); + var n = a.tagNames[0]; + n.should.have.property('name', 't2'); + n.should.have.property('flag', '2'); + n.id.should.eql(t2.id); + done(); + }); }); }); }); @@ -4519,6 +4527,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should get an embedded item on scope - verify', function(done) { Person.findById(personId, function(err, p) { if (err) return done(err); @@ -4540,104 +4549,105 @@ describe('relations', function() { it('should create an embedded item on scope with promises', function(done) { Person.create({name: 'Fred'}) - .then(function(p) { - personId = p.id; - p.passportItem.create({name: 'Fredric'}) - .then(function(passport) { - p.passport.toObject().should.eql({name: 'Fredric'}); - p.passport.should.be.an.instanceOf(Passport); - done(); - }); - }).catch(done); + .then(function(p) { + personId = p.id; + p.passportItem.create({name: 'Fredric'}) + .then(function(passport) { + p.passport.toObject().should.eql({name: 'Fredric'}); + p.passport.should.be.an.instanceOf(Passport); + done(); + }); + }).catch(done); }); it('should get an embedded item on scope with promises', function(done) { Person.findById(personId) - .then(function(p) { - var passport = p.passportItem(); - passport.toObject().should.eql({name: 'Fredric'}); - passport.should.be.an.instanceOf(Passport); - passport.should.equal(p.passport); - passport.should.equal(p.passportItem.value()); - done(); - }).catch(done); + .then(function(p) { + var passport = p.passportItem(); + passport.toObject().should.eql({name: 'Fredric'}); + passport.should.be.an.instanceOf(Passport); + passport.should.equal(p.passport); + passport.should.equal(p.passportItem.value()); + done(); + }).catch(done); }); it('should validate an embedded item on scope with promises - on creation', function(done) { var p = new Person({name: 'Fred'}); p.passportItem.create({}) - .then(function(passport) { - should.not.exist(passport); - done(); - }) - .catch(function(err) { - should.exist(err); - err.name.should.equal('ValidationError'); - err.details.messages.name.should.eql(['can\'t be blank']); - done(); - }).catch(done); - }); - - it('should validate an embedded item on scope with promises - on update', function(done) { - Person.findById(personId) - .then(function(p) { - var passport = p.passportItem(); - passport.name = null; - return p.save() - .then(function(p) { - should.not.exist(p); + .then(function(passport) { + should.not.exist(passport); done(); }) .catch(function(err) { should.exist(err); err.name.should.equal('ValidationError'); - err.details.messages.passportItem - .should.eql(['is invalid: `name` can\'t be blank']); + err.details.messages.name.should.eql(['can\'t be blank']); done(); - }); - }).catch(done); + }).catch(done); + }); + + it('should validate an embedded item on scope with promises - on update', function(done) { + Person.findById(personId) + .then(function(p) { + var passport = p.passportItem(); + passport.name = null; + return p.save() + .then(function(p) { + should.not.exist(p); + done(); + }) + .catch(function(err) { + should.exist(err); + err.name.should.equal('ValidationError'); + err.details.messages.passportItem + .should.eql(['is invalid: `name` can\'t be blank']); + done(); + }); + }).catch(done); }); it('should update an embedded item on scope with promises', function(done) { Person.findById(personId) - .then(function(p) { - return p.passportItem.update({name: 'Jason'}) - .then(function(passport) { - passport = p.passportItem(); - passport.toObject().should.eql({name: 'Jason'}); - passport.should.be.an.instanceOf(Passport); - passport.should.equal(p.passport); - done(); - }); - }).catch(done); + .then(function(p) { + return p.passportItem.update({name: 'Jason'}) + .then(function(passport) { + passport = p.passportItem(); + passport.toObject().should.eql({name: 'Jason'}); + passport.should.be.an.instanceOf(Passport); + passport.should.equal(p.passport); + done(); + }); + }).catch(done); }); it('should get an embedded item on scope with promises - verify', function(done) { Person.findById(personId) - .then(function(p) { - var passport = p.passportItem(); - passport.toObject().should.eql({name: 'Jason'}); - done(); - }).catch(done); + .then(function(p) { + var passport = p.passportItem(); + passport.toObject().should.eql({name: 'Jason'}); + done(); + }).catch(done); }); it('should destroy an embedded item on scope with promises', function(done) { Person.findById(personId) - .then(function(p) { - return p.passportItem.destroy() - .then(function() { - should.equal(p.passport, null); - done(); - }); - }).catch(done); + .then(function(p) { + return p.passportItem.destroy() + .then(function() { + should.equal(p.passport, null); + done(); + }); + }).catch(done); }); + // eslint-disable-next-line mocha/no-identical-title it('should get an embedded item on scope with promises - verify', function(done) { Person.findById(personId) - .then(function(p) { - should.equal(p.passport, null); - done(); - }).catch(done); + .then(function(p) { + should.equal(p.passport, null); + done(); + }).catch(done); }); it('should also save changes when directly saving the embedded model', function(done) { @@ -4731,14 +4741,14 @@ describe('relations', function() { it('should create an embedded item on scope with promises', function(done) { Person.create({name: 'Barney'}) - .then(function(p) { - return p.passportItem.create({name: 'Barnabus'}) - .then(function(passport) { - p.passport.id.should.eql(3); - p.passport.name.should.equal('Barnabus'); - done(); - }); - }).catch(done); + .then(function(p) { + return p.passportItem.create({name: 'Barnabus'}) + .then(function(passport) { + p.passport.id.should.eql(3); + p.passport.name.should.equal('Barnabus'); + done(); + }); + }).catch(done); }); }); @@ -4828,6 +4838,7 @@ describe('relations', function() { Person.definition.properties.addresses.postgresql.should.eql({dataType: 'json'}); }); + // eslint-disable-next-line mocha/no-identical-title it('should create embedded items on scope', function(done) { Person.findOne(function(err, p) { p.addressList.create({street: 'Street 2'}, function(err, address) { @@ -4970,6 +4981,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should create embedded items on scope', function(done) { Person.findOne(function(err, p) { p.addressList.create({street: 'Street 3'}, function(err, address) { @@ -5224,6 +5236,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should have embedded items - verify', function(done) { Person.findOne({where: {name: 'Wilma'}}, function(err, p) { p.name.should.equal('Wilma'); @@ -5549,6 +5562,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope', function(done) { Category.findOne(function(err, cat) { if (err) return done(err); @@ -5604,6 +5618,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope', function(done) { Category.findById(category.id, function(err, cat) { if (err) return done(err); @@ -5699,8 +5714,8 @@ describe('relations', function() { scope: {include: 'linked'}, }); Link.belongsTo('linked', { - polymorphic: {idType: idType}, // native type - properties: {name: 'name'}, // denormalized + polymorphic: {idType: idType}, // native type + properties: {name: 'name'}, // denormalized options: {invertProperties: true}, }); db.automigrate(['Book', 'Author', 'Reader'], done); @@ -5776,33 +5791,33 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.supportInclude === true, - 'should include nested related items on scope', function(done) { + '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(); + Book.find({include: 'people'}, function(err, books) { + var obj = books[0].toObject(); - obj.should.have.property('links'); - obj.should.have.property('people'); + obj.should.have.property('links'); + obj.should.have.property('people'); - obj.links.should.have.length(2); - obj.links[0].name.should.be.oneOf('Author 1', 'Reader 1'); - obj.links[1].name.should.be.oneOf('Author 1', 'Reader 1'); + obj.links.should.have.length(2); + obj.links[0].name.should.be.oneOf('Author 1', 'Reader 1'); + obj.links[1].name.should.be.oneOf('Author 1', 'Reader 1'); - obj.people.should.have.length(2); + obj.people.should.have.length(2); - obj.people[0].name.should.equal('Author 1'); - obj.people[0].notes.should.equal('Something ...'); + 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'); + obj.people[0].linked.name.should.equal('Author 1'); + obj.people[1].linked.name.should.equal('Reader 1'); - done(); + done(); + }); }); - }); }); describe('referencesMany', function() { @@ -5952,6 +5967,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should add a record to scope - object', function(done) { Category.findOne(function(err, cat) { cat.jobs.add(job3.id, function(err, prod) { @@ -5967,6 +5983,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope - findById', function(done) { Category.findOne(function(err, cat) { cat.jobs.findById(job3.id, function(err, p) { @@ -6022,57 +6039,57 @@ describe('relations', function() { }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should find items on scope and ordered them by name DESC', function(done) { - Category.find(function(err, categories) { - categories.should.have.length(1); - categories[0].jobs({order: 'name DESC'}, function(err, jobs) { - if (err) return done(err); - jobs.should.have.length(2); - jobs[0].id.should.eql(job3.id); - jobs[1].id.should.eql(job2.id); - done(); + 'should find items on scope and ordered them by name DESC', function(done) { + Category.find(function(err, categories) { + categories.should.have.length(1); + categories[0].jobs({order: 'name DESC'}, function(err, jobs) { + if (err) return done(err); + jobs.should.have.length(2); + jobs[0].id.should.eql(job3.id); + jobs[1].id.should.eql(job2.id); + done(); + }); }); }); - }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should allow custom scope methods - reverse', function(done) { - Category.findOne(function(err, cat) { - cat.jobs.reverse(function(err, ids) { - var expected = [job3.id, job2.id]; - ids.toArray().should.eql(expected); - cat.jobIds.toArray().should.eql(expected); - done(); + 'should allow custom scope methods - reverse', function(done) { + Category.findOne(function(err, cat) { + cat.jobs.reverse(function(err, ids) { + var expected = [job3.id, job2.id]; + ids.toArray().should.eql(expected); + cat.jobIds.toArray().should.eql(expected); + done(); + }); }); }); - }); bdd.itIf(connectorCapabilities.adhocSort === false, - 'should allow custom scope methods - reverse', function(done) { - Category.findOne(function(err, cat) { - cat.jobs.reverse(function(err, ids) { - var expected = [job3.id, job2.id]; - ids[0].should.be.oneOf(expected); - ids[1].should.be.oneOf(expected); - cat.jobIds[0].should.be.oneOf(expected); - cat.jobIds[1].should.be.oneOf(expected); + 'should allow custom scope methods - reverse', function(done) { + Category.findOne(function(err, cat) { + cat.jobs.reverse(function(err, ids) { + var expected = [job3.id, job2.id]; + ids[0].should.be.oneOf(expected); + ids[1].should.be.oneOf(expected); + cat.jobIds[0].should.be.oneOf(expected); + cat.jobIds[1].should.be.oneOf(expected); + done(); + }); + }); + }); + + bdd.itIf(connectorCapabilities.supportInclude === true, + 'should include related items from scope', function(done) { + Category.find({include: 'jobs'}, function(err, categories) { + categories.should.have.length(1); + var cat = categories[0].toObject(); + cat.name.should.equal('Category A'); + cat.jobs.should.have.length(2); + cat.jobs[0].id.should.eql(job3.id); + cat.jobs[1].id.should.eql(job2.id); done(); }); }); - }); - - bdd.itIf(connectorCapabilities.supportInclude === true, - 'should include related items from scope', function(done) { - Category.find({include: 'jobs'}, function(err, categories) { - categories.should.have.length(1); - var cat = categories[0].toObject(); - cat.name.should.equal('Category A'); - cat.jobs.should.have.length(2); - cat.jobs[0].id.should.eql(job3.id); - cat.jobs[1].id.should.eql(job2.id); - done(); - }); - }); it('should destroy items from scope - destroyById', function(done) { Category.findOne(function(err, cat) { @@ -6090,6 +6107,7 @@ describe('relations', function() { }); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope - verify', function(done) { Category.findOne(function(err, cat) { cat.jobIds.should.have.lengthOf(1); @@ -6106,31 +6124,31 @@ describe('relations', function() { it('should setup test records with promises', function(done) { db.automigrate(['Job', 'Category'], function() { return Job.create({name: 'Job 1'}) - .then(function(p) { - job1 = p; - return Job.create({name: 'Job 3'}); - }) - .then(function(p) { - job3 = p; - done(); - }).catch(done); + .then(function(p) { + job1 = p; + return Job.create({name: 'Job 3'}); + }) + .then(function(p) { + job3 = p; + done(); + }).catch(done); }); }); it('should create record on scope with promises', function(done) { Category.create({name: 'Category A'}) - .then(function(cat) { - cat.jobIds.should.be.an.array; - cat.jobIds.should.have.length(0); - return cat.jobs.create({name: 'Job 2'}) - .then(function(p) { - cat.jobIds.should.have.length(1); - cat.jobIds[0].should.eql(p.id); - p.name.should.equal('Job 2'); - job2 = p; - done(); - }); - }).catch(done); + .then(function(cat) { + cat.jobIds.should.be.an.array; + cat.jobIds.should.have.length(0); + return cat.jobs.create({name: 'Job 2'}) + .then(function(p) { + cat.jobIds.should.have.length(1); + cat.jobIds[0].should.eql(p.id); + p.name.should.equal('Job 2'); + job2 = p; + done(); + }); + }).catch(done); }); it('should not allow duplicate record on scope with promises', function(done) { @@ -6140,277 +6158,280 @@ describe('relations', function() { return cat.save(); }) .then( - function(p) { done(new Error('save() should have failed')); }, - function(err) { - err.name.should.equal('ValidationError'); - err.details.codes.jobs.should.eql(['uniqueness']); - done(); - }); + function(p) { done(new Error('save() should have failed')); }, + function(err) { + err.name.should.equal('ValidationError'); + err.details.codes.jobs.should.eql(['uniqueness']); + done(); + }); }); bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should find items on scope with promises', function(done) { - Category.findOne() - .then(function(cat) { - cat.jobIds.toArray().should.eql([job2.id]); - return cat.jobs.find(); - }) - .then(function(jobs) { - var p = jobs[0]; - p.id.should.eql(job2.id); - p.name.should.equal('Job 2'); - done(); - }) - .catch(done); - }); + 'should find items on scope with promises', function(done) { + Category.findOne() + .then(function(cat) { + cat.jobIds.toArray().should.eql([job2.id]); + return cat.jobs.find(); + }) + .then(function(jobs) { + var p = jobs[0]; + p.id.should.eql(job2.id); + p.name.should.equal('Job 2'); + done(); + }) + .catch(done); + }); bdd.itIf(connectorCapabilities.adhocSort === false, - 'should find items on scope with promises', function(done) { - var theExpectedIds = [job1.id, job2.id, job3.id]; - var theExpectedNames = ['Job 1', 'Job 2', 'Job 3']; - Category.findOne() - .then(function(cat) { - cat.jobIds[0].should.be.oneOf(theExpectedIds); - return cat.jobs.find(); - }) - .then(function(jobs) { - var p = jobs[0]; - p.id.should.be.oneOf(theExpectedIds); - p.name.should.be.oneOf(theExpectedNames); - done(); - }) - .catch(done); - }); + 'should find items on scope with promises', function(done) { + var theExpectedIds = [job1.id, job2.id, job3.id]; + var theExpectedNames = ['Job 1', 'Job 2', 'Job 3']; + Category.findOne() + .then(function(cat) { + cat.jobIds[0].should.be.oneOf(theExpectedIds); + return cat.jobs.find(); + }) + .then(function(jobs) { + var p = jobs[0]; + p.id.should.be.oneOf(theExpectedIds); + p.name.should.be.oneOf(theExpectedNames); + done(); + }) + .catch(done); + }); it('should find items on scope with promises - findById', function(done) { Category.findOne() - .then(function(cat) { - cat.jobIds.should.have.lengthOf(1); - cat.jobIds[0].should.eql(job2.id); - return cat.jobs.findById(job2.id); - }) - .then(function(p) { - p.should.be.instanceof(Job); - p.id.should.eql(job2.id); - p.name.should.equal('Job 2'); - done(); - }) - .catch(done); + .then(function(cat) { + cat.jobIds.should.have.lengthOf(1); + cat.jobIds[0].should.eql(job2.id); + return cat.jobs.findById(job2.id); + }) + .then(function(p) { + p.should.be.instanceof(Job); + p.id.should.eql(job2.id); + p.name.should.equal('Job 2'); + done(); + }) + .catch(done); }); it('should check if a record exists on scope with promises', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.exists(job2.id) - .then(function(exists) { - should.exist(exists); - done(); - }); - }).catch(done); + .then(function(cat) { + return cat.jobs.exists(job2.id) + .then(function(exists) { + should.exist(exists); + done(); + }); + }).catch(done); }); it('should update a record on scope with promises', function(done) { Category.findOne() - .then(function(cat) { - var attrs = {name: 'Job 2 - edit'}; - return cat.jobs.updateById(job2.id, attrs) - .then(function(p) { - p.name.should.equal(attrs.name); - done(); - }); - }) - .catch(done); + .then(function(cat) { + var attrs = {name: 'Job 2 - edit'}; + return cat.jobs.updateById(job2.id, attrs) + .then(function(p) { + p.name.should.equal(attrs.name); + done(); + }); + }) + .catch(done); }); it('should get a record by index with promises - at', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.at(0); - }) - .then(function(p) { - p.should.be.instanceof(Job); - p.id.should.eql(job2.id); - p.name.should.equal('Job 2 - edit'); - done(); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.at(0); + }) + .then(function(p) { + p.should.be.instanceof(Job); + p.id.should.eql(job2.id); + p.name.should.equal('Job 2 - edit'); + done(); + }) + .catch(done); }); it('should add a record to scope with promises - object', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.add(job1) - .then(function(prod) { - var expected = [job2.id, job1.id]; - cat.jobIds.should.have.lengthOf(expected.length); - cat.jobIds.should.containDeep(expected); - prod.id.should.eql(job1.id); - prod.should.have.property('name'); - done(); - }); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.add(job1) + .then(function(prod) { + var expected = [job2.id, job1.id]; + cat.jobIds.should.have.lengthOf(expected.length); + cat.jobIds.should.containDeep(expected); + prod.id.should.eql(job1.id); + prod.should.have.property('name'); + done(); + }); + }) + .catch(done); }); + // eslint-disable-next-line mocha/no-identical-title it('should add a record to scope with promises - object', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.add(job3.id) - .then(function(prod) { - var expected = [job2.id, job1.id, job3.id]; - cat.jobIds.should.have.lengthOf(expected.length); - cat.jobIds.should.containDeep(expected); - prod.id.should.eql(job3.id); - prod.should.have.property('name'); - done(); - }); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.add(job3.id) + .then(function(prod) { + var expected = [job2.id, job1.id, job3.id]; + cat.jobIds.should.have.lengthOf(expected.length); + cat.jobIds.should.containDeep(expected); + prod.id.should.eql(job3.id); + prod.should.have.property('name'); + done(); + }); + }) + .catch(done); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope with promises - findById', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.findById(job3.id); - }) - .then(function(p) { - p.id.should.eql(job3.id); - p.name.should.equal('Job 3'); - done(); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.findById(job3.id); + }) + .then(function(p) { + p.id.should.eql(job3.id); + p.name.should.equal('Job 3'); + done(); + }) + .catch(done); }); it('should find items on scope with promises - filter', function(done) { Category.findOne() - .then(function(cat) { - var filter = {where: {name: 'Job 1'}}; - return cat.jobs.find(filter); - }) - .then(function(jobs) { - jobs.should.have.length(1); - var p = jobs[0]; - p.id.should.eql(job1.id); - p.name.should.equal('Job 1'); - done(); - }) - .catch(done); + .then(function(cat) { + var filter = {where: {name: 'Job 1'}}; + return cat.jobs.find(filter); + }) + .then(function(jobs) { + jobs.should.have.length(1); + var p = jobs[0]; + p.id.should.eql(job1.id); + p.name.should.equal('Job 1'); + done(); + }) + .catch(done); }); it('should remove items from scope with promises', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.remove(job1.id) - .then(function(ids) { - var expected = [job2.id, job3.id]; - cat.jobIds.should.have.lengthOf(expected.length); - cat.jobIds.should.containDeep(expected); - cat.jobIds.should.eql(ids); - done(); - }); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.remove(job1.id) + .then(function(ids) { + var expected = [job2.id, job3.id]; + cat.jobIds.should.have.lengthOf(expected.length); + cat.jobIds.should.containDeep(expected); + cat.jobIds.should.eql(ids); + done(); + }); + }) + .catch(done); }); it('should find items on scope with promises - verify', function(done) { Category.findOne() - .then(function(cat) { - var expected = [job2.id, job3.id]; - cat.jobIds.should.have.lengthOf(expected.length); - cat.jobIds.should.containDeep(expected); - return cat.jobs.find(); - }) - .then(function(jobs) { - jobs.should.have.length(2); - jobs[0].id.should.eql(job2.id); - jobs[1].id.should.eql(job3.id); - done(); - }) - .catch(done); - }); - - bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should find items on scope and ordered them by name DESC', function(done) { - Category.find() - .then(function(categories) { - categories.should.have.length(1); - return categories[0].jobs.find({order: 'name DESC'}); - }) - .then(function(jobs) { - jobs.should.have.length(2); - jobs[0].id.should.eql(job3.id); - jobs[1].id.should.eql(job2.id); - done(); - }) - .catch(done); - }); - - bdd.itIf(connectorCapabilities.adhocSort !== false, - 'should allow custom scope methods with promises - reverse', function(done) { - Category.findOne() - .then(function(cat) { - return cat.jobs.reverse() - .then(function(ids) { - var expected = [job3.id, job2.id]; - ids.toArray().should.eql(expected); - cat.jobIds.toArray().should.eql(expected); + .then(function(cat) { + var expected = [job2.id, job3.id]; + cat.jobIds.should.have.lengthOf(expected.length); + cat.jobIds.should.containDeep(expected); + return cat.jobs.find(); + }) + .then(function(jobs) { + jobs.should.have.length(2); + jobs[0].id.should.eql(job2.id); + jobs[1].id.should.eql(job3.id); done(); - }); - }) - .catch(done); + }) + .catch(done); }); + bdd.itIf(connectorCapabilities.adhocSort !== false, + 'should find items on scope and ordered them by name DESC', function(done) { + Category.find() + .then(function(categories) { + categories.should.have.length(1); + return categories[0].jobs.find({order: 'name DESC'}); + }) + .then(function(jobs) { + jobs.should.have.length(2); + jobs[0].id.should.eql(job3.id); + jobs[1].id.should.eql(job2.id); + done(); + }) + .catch(done); + }); + + bdd.itIf(connectorCapabilities.adhocSort !== false, + 'should allow custom scope methods with promises - reverse', function(done) { + Category.findOne() + .then(function(cat) { + return cat.jobs.reverse() + .then(function(ids) { + var expected = [job3.id, job2.id]; + ids.toArray().should.eql(expected); + cat.jobIds.toArray().should.eql(expected); + done(); + }); + }) + .catch(done); + }); + bdd.itIf(connectorCapabilities.adhocSort === true && connectorCapabilities.supportInclude === true, 'should include related items from scope with promises', function(done) { Category.find({include: 'jobs'}) - .then(function(categories) { - categories.should.have.length(1); - var cat = categories[0].toObject(); - cat.name.should.equal('Category A'); - cat.jobs.should.have.length(2); - cat.jobs[0].id.should.eql(job3.id); - cat.jobs[1].id.should.eql(job2.id); - done(); - }).catch(done); + .then(function(categories) { + categories.should.have.length(1); + var cat = categories[0].toObject(); + cat.name.should.equal('Category A'); + cat.jobs.should.have.length(2); + cat.jobs[0].id.should.eql(job3.id); + cat.jobs[1].id.should.eql(job2.id); + done(); + }).catch(done); }); it('should destroy items from scope with promises - destroyById', function(done) { Category.findOne() - .then(function(cat) { - return cat.jobs.destroy(job2.id) - .then(function() { - var expected = [job3.id]; - if (connectorCapabilities.adhocSort !== false) { - cat.jobIds.toArray().should.eql(expected); - } else { - cat.jobIds.toArray().should.containDeep(expected); - } - return Job.exists(job2.id); + .then(function(cat) { + return cat.jobs.destroy(job2.id) + .then(function() { + var expected = [job3.id]; + if (connectorCapabilities.adhocSort !== false) { + cat.jobIds.toArray().should.eql(expected); + } else { + cat.jobIds.toArray().should.containDeep(expected); + } + return Job.exists(job2.id); + }) + .then(function(exists) { + should.exist(exists); + exists.should.be.false; + done(); + }); }) - .then(function(exists) { - should.exist(exists); - exists.should.be.false; - done(); - }); - }) - .catch(done); + .catch(done); }); + // eslint-disable-next-line mocha/no-identical-title it('should find items on scope with promises - verify', function(done) { Category.findOne() - .then(function(cat) { - var expected = [job3.id]; - cat.jobIds.should.have.lengthOf(expected.length); - cat.jobIds.should.containDeep(expected); - return cat.jobs.find(); - }) - .then(function(jobs) { - jobs.should.have.length(1); - jobs[0].id.should.eql(job3.id); - done(); - }) - .catch(done); + .then(function(cat) { + var expected = [job3.id]; + cat.jobIds.should.have.lengthOf(expected.length); + cat.jobIds.should.containDeep(expected); + return cat.jobs.find(); + }) + .then(function(jobs) { + jobs.should.have.length(1); + jobs[0].id.should.eql(job3.id); + done(); + }) + .catch(done); }); }); @@ -6496,21 +6517,21 @@ describe('relations', function() { ]; Category.findOne() - .then(function(cat) { - return cat.jobs.summarize(); - }) - .then(function(summary) { - var result = summary.map(function(item) { - delete item.id; - item.categoryId = item.categoryId.toString(); - return item; - }); - // order-independent match - result.should.containDeep(expected); - expected.should.containDeep(result); - done(); - }) - .catch(done); + .then(function(cat) { + return cat.jobs.summarize(); + }) + .then(function(summary) { + var result = summary.map(function(item) { + delete item.id; + item.categoryId = item.categoryId.toString(); + return item; + }); + // order-independent match + result.should.containDeep(expected); + expected.should.containDeep(result); + done(); + }) + .catch(done); }); }); diff --git a/test/util.test.js b/test/util.test.js index 34ea2bb4..9da2d512 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -127,7 +127,7 @@ describe('util.parseSettings', function() { should.equal(settings.url, 'mysql://127.0.0.1:3306/mydb?x[a]=1&x[b]=2&engine=InnoDB'); }); - it('Parse a url without auth into a settings object', function() { + it('Parse a Memory url without auth into a settings object', function() { var url = 'memory://?x=1'; var settings = utils.parseSettings(url); should.equal(settings.hostname, ''); @@ -145,7 +145,7 @@ describe('util.deepMerge', function() { var extras = {base: 'User', relations: {accessTokens: {model: 'accessToken', type: 'hasMany', foreignKey: 'userId'}, - account: {model: 'account', type: 'belongsTo'}}, + account: {model: 'account', type: 'belongsTo'}}, acls: [ {accessType: '*', permission: 'DENY', @@ -206,7 +206,7 @@ describe('util.deepMerge', function() { base: 'User', relations: {accessTokens: {model: 'accessToken', type: 'hasMany', foreignKey: 'userId'}, - account: {model: 'account', type: 'belongsTo'}}}; + account: {model: 'account', type: 'belongsTo'}}}; should.deepEqual(merged, expected, 'Merged objects should match the expectation'); }); @@ -495,19 +495,19 @@ describe('util.toRegExp', function() { context('with a regex string', function() { it('should return a RegExp object when no regex flags are provided', - function() { - utils.toRegExp('^regex$').should.be.an.instanceOf(RegExp); - }); + function() { + utils.toRegExp('^regex$').should.be.an.instanceOf(RegExp); + }); it('should throw an error when invalid regex flags are provided', - function() { - utils.toRegExp('^regex$/abc').should.be.an.Error; - }); + function() { + utils.toRegExp('^regex$/abc').should.be.an.Error; + }); it('should return a RegExp object when valid flags are provided', - function() { - utils.toRegExp('regex/igm').should.be.an.instanceOf(RegExp); - }); + function() { + utils.toRegExp('regex/igm').should.be.an.instanceOf(RegExp); + }); }); context('with a regex literal', function() {