UNPKG

sails

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

1,206 lines (1,058 loc) 80.3 kB
/** * Test dependencies */ var util = require('util'); var assert = require('assert'); var tmp = require('tmp'); var _ = require('@sailshq/lodash'); var Filesystem = require('machinepack-fs'); var appHelper = require('./helpers/appHelper'); var Sails = require('../../lib').constructor; /** * Errors */ var Err = { badResponse: function(response) { return 'Wrong server response! Response :::\n' + util.inspect(response.body); } }; describe('blueprints :: ', function() { var curDir, tmpDir, sailsApp; var extraSailsConfig = {}; describe('restful routes :: ', function() { describe('when turned off globaly :: ', function() { before(function(done) { // Cache the current working directory. curDir = process.cwd(); // Create a temp directory. tmpDir = tmp.dirSync({gracefulCleanup: true, unsafeCleanup: true}); // Switch to the temp directory. process.chdir(tmpDir.name); appHelper.linkDeps(tmpDir.name); (new Sails()).load({ hooks: { grunt: false, views: false, policies: false, pubsub: false, i18n: false }, orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' } } } }, } }, models: { migrate: 'drop', schema: true, attributes: { createdAt: { type: 'number', autoCreatedAt: true, }, updatedAt: { type: 'number', autoUpdatedAt: true, }, // id: { type: 'string', unique: true, columnName: '_id'}, id: { type: 'number', autoIncrement: true} } }, blueprints: { rest: false, shortcuts: false, actions: false }, log: {level: 'error'} }, function(err, _sails) { if (err) { return done(err); } sailsApp = _sails; return done(); }); }); after(function(done) { extraSailsConfig = {}; sailsApp.lower(function() { process.chdir(curDir); return done(); }); }); it('a get request to /:model should return a 404', function(done) { sailsApp.models.user.create({name: 'al'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(err); assert.equal(err.status, 404); done(); }); }); }); }); describe('when turned off for a specific controller :: ', function() { before(function(done) { // Cache the current working directory. curDir = process.cwd(); // Create a temp directory. tmpDir = tmp.dirSync({gracefulCleanup: true, unsafeCleanup: true}); // Switch to the temp directory. process.chdir(tmpDir.name); appHelper.linkDeps(tmpDir.name); Filesystem.writeSync({ force: true, destination: 'api/controllers/UserController.js', string: 'module.exports = { _config: { rest: false } }' }).execSync(); (new Sails()).load({ hooks: { grunt: false, views: false, policies: false, pubsub: false, i18n: false }, orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' } } } }, } }, models: { migrate: 'drop', schema: true, attributes: { createdAt: { type: 'number', autoCreatedAt: true, }, updatedAt: { type: 'number', autoUpdatedAt: true, }, // id: { type: 'string', unique: true, columnName: '_id'}, id: { type: 'number', autoIncrement: true} } }, blueprints: { shortcuts: false, actions: false }, log: {level: 'error'} }, function(err, _sails) { if (err) { return done(err); } sailsApp = _sails; return done(); }); }); after(function(done) { extraSailsConfig = {}; sailsApp.lower(function() { process.chdir(curDir); return done(); }); }); it('a get request to the /:model with REST disabled should return a 404', function(done) { sailsApp.models.user.create({name: 'al'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(err); assert.equal(err.status, 404); done(); }); }); }); it('a get request to the /:model with REST enabled should return JSON for all of the instances of the test model', function(done) { sailsApp.models.pet.create({name: 'rex'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /pet', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 1); assert.equal(data[0].name, 'rex'); assert.equal(data[0].id, 1); done(); }); }); }); }); describe('when turned on :: ', function() { beforeEach(function(done) { // Cache the current working directory. curDir = process.cwd(); // Create a temp directory. tmpDir = tmp.dirSync({gracefulCleanup: true, unsafeCleanup: true}); // Switch to the temp directory. process.chdir(tmpDir.name); appHelper.linkDeps(tmpDir.name); (new Sails()).load(_.merge({ hooks: { grunt: false, views: false, policies: false, i18n: false }, orm: { moduleDefinitions: { models: { 'user': {} } } }, models: { migrate: 'drop', schema: true, attributes: { createdAt: { type: 'number', autoCreatedAt: true, }, updatedAt: { type: 'number', autoUpdatedAt: true, }, // id: { type: 'string', unique: true, columnName: '_id'}, id: { type: 'number', autoIncrement: true} } }, blueprints: { shortcuts: false, actions: false }, log: {level: 'error'} }, extraSailsConfig), function(err, _sails) { if (err) { return done(err); } sailsApp = _sails; return done(); }); }); afterEach(function(done) { sailsApp.lower(function() { process.chdir(curDir); return done(); }); }); describe('basic usage :: ', function() { before(function() { extraSailsConfig = { orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' }, animalFriends: { collection: 'pet', via: 'humanFriends' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' }, humanFriends: { collection: 'user', via: 'animalFriends' } } } }, } } }; }); after(function() { extraSailsConfig = {}; }); describe('a get request to /archive (the default archive model', function() { it('should return a 404', function(done) { sailsApp.request('get /archive', function (err) { assert(err, 'Should have received an error trying to access blueprint for archive model, but didn\'t!'); assert.equal(err.status, 404); done(); }); }); }); describe('a get request to /:model', function() { describe('where a single instance of the model exists', function() { it('should return JSON for all of the instances of the test model', function(done) { sailsApp.models.user.create({name: 'al'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 1); assert.equal(data[0].name, 'al'); assert.equal(data[0].id, 1); done(); }); }); }); it('should populate all associations of the test model', function(done) { sailsApp.models.pet.createEach([{name: 'alice'}, {name: 'tex'}, {name: 'bailey'}]).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'al', pets: _.pluck(pets, 'id')}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 1); assert.equal(data[0].name, 'al'); assert.equal(data[0].id, 1); assert.equal(data[0].pets.length, 3); done(); }); }); }); }); it('should limit populate records to the default limit (30)', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'pet' + i }; }); sailsApp.models.pet.createEach(instancesToCreate).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'al', pets: _.pluck(pets, 'id')}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 1); assert.equal(data[0].name, 'al'); assert.equal(data[0].id, 1); assert.equal(data[0].pets.length, 30); done(); }); }); }); }); }); describe('where 40 instances of the model exist, with no limit set', function() { it('should return JSON for 30 instances of the test model (becase the default limit is 30)', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'user_' + i }; }); sailsApp.models.user.createEach(instancesToCreate).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 30); done(); }); }); }); }); describe('where 40 instances of the model exist, with limit set to 35', function() { it('should return JSON for 35 instances of the test model', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'user_' + i }; }); sailsApp.models.user.createEach(instancesToCreate).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user?limit=35', function (err, resp, data) { assert(!err, err); assert.equal(data.length, 35); done(); }); }); }); }); }); describe('a get request to /:model?id=1', function() { it('should return an array of 1 item', function(done) { sailsApp.models.user.create({name: 'jeremy'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user?id=1', function (err, resp, data) { assert(!err, err); assert(_.isArray(data), 'Should have receieved an array, but got: ' + util.inspect(data, {depth: null})); assert.equal(data.length, 1); assert.equal(data[0].name, 'jeremy'); assert.equal(data[0].id, 1); done(); }); }); }); }); describe('a get request to /:model/:id', function() { it('should return JSON for the requested instance of the test model', function(done) { sailsApp.models.user.create({name: 'ron'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user/1', function (err, resp, data) { assert(!err, err); assert.equal(data.name, 'ron'); assert.equal(data.id, 1); done(); }); }); }); }); describe('a patch request to /:model/:id', function() { it('should return JSON for an updated instance of the test model', function(done) { sailsApp.models.user.create({name: 'dave'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('patch /user/1', {name: 'larry'}, function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'larry'); assert.equal(data.id, 1); sailsApp.models.user.findOne({id: 1}).exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'larry'); return done(); }); }); }); }); }); describe('a put request to /:model/:id', function() { it('should return JSON for an updated instance of the test model', function(done) { sailsApp.models.user.create({name: 'dave'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1', {name: 'bob'}, function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'bob'); assert.equal(data.id, 1); sailsApp.models.user.findOne({id: 1}).exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'bob'); return done(); }); }); }); }); }); describe('a post request to /:model', function() { it('should return JSON for a newly created instance of the test model', function(done) { sailsApp.request('post /user', {name: 'joe'}, function (err, resp, data) { assert(!err, err); assert.equal(data.name, 'joe'); assert.equal(data.id, 1); sailsApp.models.user.findOne({id: 1}).exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'joe'); return done(); }); }); }); }); describe('a delete request to /:model', function() { it('should return JSON for the deleted instance of the test model', function(done) { sailsApp.models.user.create({name: 'bubba'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('delete /user/1', function (err, resp, data) { assert(!err, err); assert.equal(data.name, 'bubba'); assert.equal(data.id, 1); sailsApp.models.user.findOne({id: 1}).exec(function(err, user) { if (err) {return done (err);} assert(!user); return done(); }); }); }); }); }); // █████╗ ███████╗███████╗ ██████╗ ██████╗██╗ █████╗ ████████╗██╗ ██████╗ ███╗ ██╗███████╗ // ██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔════╝██║██╔══██╗╚══██╔══╝██║██╔═══██╗████╗ ██║██╔════╝ // ███████║███████╗███████╗██║ ██║██║ ██║███████║ ██║ ██║██║ ██║██╔██╗ ██║███████╗ // ██╔══██║╚════██║╚════██║██║ ██║██║ ██║██╔══██║ ██║ ██║██║ ██║██║╚██╗██║╚════██║ // ██║ ██║███████║███████║╚██████╔╝╚██████╗██║██║ ██║ ██║ ██║╚██████╔╝██║ ╚████║███████║ // ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ // describe('associations :: ', function() { describe('one to many :: ', function() { describe('a post request to /:model with an array specified for a collection attribute', function() { it('should return JSON for the new record including the associated collection', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.request('post /user', {name: 'will', pets: [spot.id]}, function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'will'); assert.equal(data.id, 1); assert.equal(data.pets.length, 1); assert.equal(data.pets[0].name, 'spot'); return done(); }); }); }); }); describe('a get request to /:model/:parentid/:association for a plural association', function() { describe('where a single child instance exists', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.models.user.create({name: 'will', pets: [spot.id]}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/pets', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 1); assert.equal(data[0].name, 'spot'); assert.equal(data[0].id, 1); assert.equal(data[0].owner, 1); return done(); }); }); }); }); }); describe('where a 40 instances exist, and no limit is given', function() { it('should return JSON for 30 records of the specified collection of the test model (since the default limit is 30)', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'pet_' + i }; }); sailsApp.models.pet.createEach(instancesToCreate).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'will', pets: _.pluck(pets, 'id')}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/pets', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 30); return done(); }); }); }); }); }); describe('where a 40 instances exist, and a limit of 35 is given', function() { it('should return JSON for 35 records of the specified collection of the test model', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'pet_' + i }; }); sailsApp.models.pet.createEach(instancesToCreate).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'will', pets: _.pluck(pets, 'id')}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/pets?limit=35', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 35); return done(); }); }); }); }); }); }); describe('a get request to /:model/:parentid/:association for a plural association with no associated records', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.user.create({name: 'will'}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/pets', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 0); return done(); }); }); }); }); describe('a get request to /:model/:parentid/:association for a singular association', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.models.user.create({name: 'will', pets: [spot.id]}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /pet/1/owner', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'will'); assert.equal(data.id, 1); return done(); }); }); }); }); }); describe('a get request to /:model/:parentid/:association for a singular association with no associated record', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.request('get /pet/1/owner', function (err, resp, data) { if (err) { if (err.status && err.status === 404) { return done(); } return done(new Error('Should have responded with a 404 error, but instead got:' + util.inspect(err, {depth: null}))); } return done(new Error('Should have responded with a 404 error, but instead got:' + util.inspect(data, {depth: null}))); }); }); }); }); describe('a get request to /:model/:parentid/:association/:id', function() { it('should return a 404', function(done) { sailsApp.models.pet.createEach([{name: 'bubbles'}, {name: 'dempsey'}]).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'roger', pets: _.pluck(pets,'id')}).meta({fetch: true}).exec(function(err) { if (err) {return done (err);} sailsApp.request('get /user/1/pets/2', function (err, resp, data) { if (err) { if (err.status && err.status === 404) { return done(); } return done(new Error('Should have responded with a 404 error, but instead got:' + util.inspect(err, {depth: null}))); } return done(new Error('Should have responded with a 404 error, but instead got:' + util.inspect(data, {depth: null}))); }); }); }); }); }); describe('a put request to /:model/:parentid/:association/:id', function() { it('should return JSON for an instance of the test model, with its collection updated', function(done) { sailsApp.models.user.create({name: 'ira'}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.create({name: 'flipper'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/pets/1', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'ira'); assert.equal(data.id, 1); assert.equal(data.pets.length, 1); assert.equal(data.pets[0].name, 'flipper'); sailsApp.models.user.findOne({id: 1}).populate('pets').exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'ira'); assert.equal(user.id, 1); assert.equal(user.pets.length, 1); assert.equal(user.pets[0].name, 'flipper'); return done(); }); }); }); }); }); }); describe('a put request to /:model/:parentid/:association (with empty array)', function() { it('should return JSON for an instance of the test model, with its collection replaced', function(done) { sailsApp.models.user.create({name: 'ira', id: 1}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.create({name: 'flipper', id: 1, owner: 1}).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/pets', [], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'ira'); assert.equal(data.pets.length, 0); sailsApp.models.pet.findOne({id: 1}).populate('owner').exec(function(err, pet) { if (err) {return done (err);} assert(pet); assert.equal(pet.name, 'flipper'); assert.equal(pet.id, 1); assert.equal(pet.owner, null); return done(); }); }); }); }); }); }); describe('a put request to /:model/:parentid/:association (with new array)', function() { it('should return JSON for an instance of the test model, with its collection replaced', function(done) { sailsApp.models.user.create({name: 'zooey'}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.createEach([{name: 'ralph', id: 1, owner: 1}, {name: 'fiona', id: 2}]).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/pets', [2], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'zooey'); assert.equal(data.pets.length, 1); assert.equal(data.pets[0].id, 2); assert.equal(data.pets[0].name, 'fiona'); sailsApp.models.pet.findOne({id: 2}).populate('owner').exec(function(err, pet) { if (err) {return done (err);} assert(pet); assert.equal(pet.name, 'fiona'); assert.equal(pet.id, 2); assert.equal(pet.owner.name, 'zooey'); assert.equal(pet.owner.id, 1); return done(); }); }); }); }); }); }); describe('a delete request to /:model/:parentid/:association/:id', function() { it('should return JSON for an instance of the test model, with its collection updated', function(done) { sailsApp.models.pet.create({name: 'alice'}).meta({fetch: true}).exec(function(err, alice) { sailsApp.models.user.create({name: 'larry', pets: [alice.id]}).meta({fetch: true}).exec(function(err) { if (err) {return done (err);} sailsApp.request('delete /user/1/pets/1', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'larry'); assert.equal(data.id, 1); assert.equal(data.pets.length, 0); sailsApp.models.user.findOne({id: 1}).populate('pets').exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'larry'); assert.equal(user.id, 1); assert.equal(user.pets.length, 0); return done(); }); }); }); }); }); }); }); describe('many-to-many :: ', function() { describe('a post request to /:model with an array specified for a collection attribute', function() { it('should return JSON for the new record including the associated collection', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.request('post /user', {name: 'will', animalFriends: [spot.id]}, function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'will'); assert.equal(data.id, 1); assert.equal(data.animalFriends.length, 1); assert.equal(data.animalFriends[0].name, 'spot'); return done(); }); }); }); }); describe('a get request to /:model/:parentid/:association for a plural association', function() { describe('where a single child instance exists', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.pet.create({name: 'spot'}).meta({fetch: true}).exec(function(err, spot) { sailsApp.models.user.create({name: 'will', animalFriends: [spot.id]}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/animalFriends', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 1); assert.equal(data[0].name, 'spot'); assert.equal(data[0].id, 1); return done(); }); }); }); }); }); describe('where a 40 instances exist, and no limit is given', function() { it('should return JSON for 30 records of the specified collection of the test model (since the default limit is 30)', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'pet_' + i }; }); sailsApp.models.pet.createEach(instancesToCreate).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'will', animalFriends: _.pluck(pets, 'id')}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/animalFriends', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 30); return done(); }); }); }); }); }); describe('where a 40 instances exist, and a limit of 35 is given', function() { it('should return JSON for 35 records of the specified collection of the test model', function(done) { var instancesToCreate = _.map(_.range(1,41), function(i) { return { name: 'pet_' + i }; }); sailsApp.models.pet.createEach(instancesToCreate).meta({fetch: true}).exec(function(err, pets) { sailsApp.models.user.create({name: 'will', animalFriends: _.pluck(pets, 'id')}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/animalFriends?limit=35', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 35); return done(); }); }); }); }); }); }); describe('a get request to /:model/:parentid/:association for a plural association with no associated records', function() { it('should return JSON for the specified collection of the test model', function(done) { sailsApp.models.user.create({name: 'will'}).meta({fetch: true}).exec(function(err, will) { if (err) {return done (err);} sailsApp.request('get /user/1/animalFriends', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.length, 0); return done(); }); }); }); }); describe('a put request to /:model/:parentid/:association/:id', function() { it('should return JSON for an instance of the test model, with its collection updated', function(done) { sailsApp.models.user.create({name: 'ira'}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.create({name: 'flipper'}).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/animalFriends/1', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'ira'); assert.equal(data.id, 1); assert.equal(data.animalFriends.length, 1); assert.equal(data.animalFriends[0].name, 'flipper'); sailsApp.models.user.findOne({id: 1}).populate('animalFriends').exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'ira'); assert.equal(user.id, 1); assert.equal(user.animalFriends.length, 1); assert.equal(user.animalFriends[0].name, 'flipper'); return done(); }); }); }); }); }); }); describe('a put request to /:model/:parentid/:association (with empty array)', function() { it('should return JSON for an instance of the test model, with its collection replaced', function(done) { sailsApp.models.user.create({name: 'ira', id: 1}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.create({name: 'flipper', id: 1, humanFriends: [1]}).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/animalFriends', [], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'ira'); assert.equal(data.animalFriends.length, 0); sailsApp.models.pet.findOne({id: 1}).populate('humanFriends').exec(function(err, pet) { if (err) {return done (err);} assert(pet); assert.equal(pet.name, 'flipper'); assert.equal(pet.id, 1); assert.equal(pet.humanFriends.length, 0); return done(); }); }); }); }); }); }); describe('a put request to /:model/:parentid/:association (with new array)', function() { it('should return JSON for an instance of the test model, with its collection replaced', function(done) { sailsApp.models.user.create({name: 'zooey'}).exec(function(err) { if (err) {return done (err);} sailsApp.models.pet.createEach([{name: 'ralph', id: 1, humanFriends: [1]}, {name: 'fiona', id: 2}]).exec(function(err) { if (err) {return done (err);} sailsApp.request('put /user/1/animalFriends', [2], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'zooey'); assert.equal(data.animalFriends.length, 1); assert.equal(data.animalFriends[0].id, 2); assert.equal(data.animalFriends[0].name, 'fiona'); sailsApp.models.pet.findOne({id: 2}).populate('humanFriends').exec(function(err, pet) { if (err) {return done (err);} assert(pet); assert.equal(pet.name, 'fiona'); assert.equal(pet.id, 2); assert.equal(pet.humanFriends.length, 1); assert.equal(pet.humanFriends[0].id, 1); return done(); }); }); }); }); }); }); describe('a delete request to /:model/:parentid/:association/:id', function() { it('should return JSON for an instance of the test model, with its collection updated', function(done) { sailsApp.models.pet.create({name: 'alice'}).meta({fetch: true}).exec(function(err, alice) { sailsApp.models.user.create({name: 'larry', animalFriends: [alice.id]}).meta({fetch: true}).exec(function(err) { if (err) {return done (err);} sailsApp.request('delete /user/1/animalFriends/1', function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'larry'); assert.equal(data.id, 1); assert.equal(data.animalFriends.length, 0); sailsApp.models.user.findOne({id: 1}).populate('animalFriends').exec(function(err, user) { if (err) {return done (err);} assert(user); assert.equal(user.name, 'larry'); assert.equal(user.id, 1); assert.equal(user.animalFriends.length, 0); return done(); }); }); }); }); }); }); }); }); describe('with a custom parseBlueprintOptions for all blueprints', function() { before(function() { extraSailsConfig = { blueprints: { parseBlueprintOptions: function(req) { var queryOptions = req._sails.hooks.blueprints.parseBlueprintOptions(req); if (queryOptions.populates.pets) { queryOptions.populates.pets.limit = 1; } return queryOptions; } }, routes: { 'GET /yolo/:id': 'user/findOne', }, orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' } } } }, } } }; }); after(function() { extraSailsConfig = {}; }); it('the custom `parseBlueprintOptions` should be applied to the `find` blueprint', function(done) { sailsApp.models.pet.createEach([{name: 'alice'}, {name: 'rex'}]).meta({fetch: true}).exec(function(err, pets) { if (err) {return done(err);} sailsApp.models.user.create({name: 'bill', pets: _.pluck(pets, sailsApp.models.pet.primaryKey)}).exec(function(err, bill) { if (err) {return done(err);} sailsApp.request('get /user/' + bill[sailsApp.models.user.primaryKey], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'bill'); assert(data.pets, 'Record should have `pets` key, but none was found. Full record: ' + util.inspect(data, {depth: null})); assert.equal(data.pets.length, 1); return done(); }); }); }); }); it('the custom `parseBlueprintOptions` should be applied to the `create` blueprint', function(done) { sailsApp.models.pet.createEach([{name: 'june'}, {name: 'jane'}]).meta({fetch: true}).exec(function(err, pets) { if (err) {return done(err);} sailsApp.request('post /user', {name: 'bob', pets: _.pluck(pets, sailsApp.models.pet.primaryKey)}, function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'bob'); assert(data.pets, 'Record should have `pets` key, but none was found. Full record: ' + util.inspect(data, {depth: null})); assert.equal(data.pets.length, 1); return done(); }); }); }); it('the custom `parseBlueprintOptions` should be applied to a user-defined (i.e. not shadow) route', function(done) { sailsApp.models.pet.createEach([{name: 'lolly'}, {name: 'dolly'}]).meta({fetch: true}).exec(function(err, pets) { if (err) {return done(err);} sailsApp.models.user.create({name: 'bruce', pets: _.pluck(pets, sailsApp.models.pet.primaryKey)}).exec(function(err, bruce) { if (err) {return done(err);} sailsApp.request('get /yolo/' + bruce[sailsApp.models.user.primaryKey], function (err, resp, data) { if (err) {return done (err);} assert.equal(data.name, 'bruce'); assert(data.pets, 'Record should have `pets` key, but none was found. Full record: ' + util.inspect(data, {depth: null})); assert.equal(data.pets.length, 1); return done(); }); }); }); }); }); describe('with a custom parseBlueprintOptions that disables auto-population (tests #4138)', function() { before(function() { extraSailsConfig = { hooks: { pubsub: undefined }, blueprints: { parseBlueprintOptions: function(req) { var queryOptions = req._sails.hooks.blueprints.parseBlueprintOptions(req); if (!req.param('populate', false) && !queryOptions.alias) { queryOptions.populates = {}; } return queryOptions; } }, orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' } } } }, } } }; }); after(function() { extraSailsConfig = {}; }); it('the delete blueprint should not cause any errors', function(done) { sailsApp.models.pet.createEach([{name: 'alice'}, {name: 'rex'}]).meta({fetch: true}).exec(function(err, pets) { if (err) {return done(err);} sailsApp.models.user.create({name: 'bill', pets: _.pluck(pets, sailsApp.models.pet.primaryKey)}).exec(function(err, bill) { if (err) {return done(err);} sailsApp.request('delete /user/' + bill[sailsApp.models.user.primaryKey], function (err, resp, data) { if (err) {return done (err);} return done(); }); }); }); }); }); describe('with a custom parseBlueprintOptions for a specific route', function() { before(function() { extraSailsConfig = { routes: { 'GET /user/:id': { action: 'user/findOne', parseBlueprintOptions: function(req) { var queryOptions = req._sails.hooks.blueprints.parseBlueprintOptions(req); queryOptions.populates.pets.limit = 1; return queryOptions; } } }, orm: { moduleDefinitions: { models: { user: { attributes: { name: 'string', pets: { collection: 'pet', via: 'owner' } } }, pet: { attributes: { name: 'string', owner: { model: 'user' } } } }, } } }; }); after(function() { extraSailsConfig = {}; }); it('the custom `parseBlueprintOptions` should be applied to the specific route', function(done) { sailsApp.models.pet.createEach([{name: 'alice'}, {name: 'rex'}]).meta({fetch: true}).exec(function(err, pets) { if (err) {return done(err);}