UNPKG

apostrophe

Version:

The Apostrophe Content Management System.

569 lines (513 loc) • 16.2 kB
var t = require('../test-lib/test.js'); var assert = require('assert'); var _ = require('@sailshq/lodash'); var async = require('async'); var apos; describe('Pieces', function() { this.timeout(t.timeout); after(function(done) { return t.destroy(apos, done); }); /// /// // EXISTENCE /// /// it('should initialize with a schema', function(done) { apos = require('../index.js')({ root: module, shortName: 'test', modules: { 'apostrophe-express': { secret: 'xxx', port: 7900 }, 'things': { extend: 'apostrophe-pieces', name: 'thing', label: 'Thing', addFields: { name: 'foo', label: 'Foo', type: 'string' } }, 'people': { extend: 'apostrophe-pieces', name: 'person', label: 'Person', addFields: { name: '_things', type: 'joinByArray' } } }, afterInit: function(callback) { assert(apos.modules['things']); assert(apos.modules['things'].schema); apos.argv._ = []; return callback(null); }, afterListen: function(err) { assert(!err); done(); } }); }); // little test-helper function to get piece by id regardless of trash status function findPiece(req, id, callback) { return apos.modules['things'].find(req, { _id: id }) .permission('edit') .published(null) .trash(null) .toObject(function(err, piece) { if (err) { return callback(err); } if (!piece) { return callback('notfound'); } return callback(err, piece); } ); }; var testThing = { _id: 'testThing', title: 'hello', foo: 'bar' }; var testThing2 = { _id: 'testThing2', title: 'hello2', foo: 'bar2' }; var additionalThings = [ { _id: 'thing1', title: 'Red' }, { _id: 'thing2', title: 'Blue', published: true }, { _id: 'thing3', title: 'Green', published: true } ]; var testPeople = [ { _id: 'person1', title: 'Bob', type: 'person', thingsIds: [ 'thing2', 'thing3' ], published: true } ]; // Wipe the database so we can run this test suite independent of bootstrap it('should make sure there is no test data hanging around from last time', function(done) { // Attempt to purge the entire aposDocs collection apos.docs.db.remove({}, function(err) { assert(!err); // Make sure it went away apos.docs.db.findWithProjection({ _id: 'testThing' }).toArray(function(err, docs) { assert(!err); assert(docs.length === 0); done(); }); }); }); // Test pieces.newInstance() it('should be able to create a new piece', function() { assert(apos.modules['things'].newInstance); var thing = apos.modules['things'].newInstance(); assert(thing); assert(thing.type === 'thing'); }); // Test pieces.insert() it('should be able to insert a piece into the database', function(done) { assert(apos.modules['things'].insert); apos.modules['things'].insert(apos.tasks.getReq(), testThing, function(err, piece) { assert(!err); assert(testThing === piece); done(); }); }); it('same thing with promises', function(done) { assert(apos.modules['things'].insert); apos.modules['things'].insert(apos.tasks.getReq(), testThing2) .then(function(piece2) { assert(testThing2 === piece2); done(); }) .catch(function(err) { assert(!err); }); }); // Test pieces.requirePiece() it('should be able to retrieve a piece by id from the database', function(done) { assert(apos.modules['things'].requirePiece); var req = apos.tasks.getReq(); req.body = {}; req.body._id = "testThing"; apos.modules['things'].requirePiece(req, req.res, function() { assert(req.piece); assert(req.piece._id === 'testThing'); assert(req.piece.title === 'hello'); assert(req.piece.foo === 'bar'); done(); }); }); // Test pieces.update() it('should be able to update a piece in the database', function(done) { assert(apos.modules['things'].update); testThing.foo = 'moo'; apos.modules['things'].update(apos.tasks.getReq(), testThing, function(err, piece) { assert(!err); assert(testThing === piece); // Now let's get the piece and check if it was updated var req = apos.tasks.getReq(); req.body = {}; req.body._id = "testThing"; apos.modules['things'].requirePiece(req, req.res, function() { assert(req.piece); assert(req.piece._id === 'testThing'); assert(req.piece.foo === 'moo'); done(); }); }); }); it('same thing with promises', function(done) { assert(apos.modules['things'].update); testThing.foo = 'goo'; apos.modules['things'].update(apos.tasks.getReq(), testThing) .then(function(piece) { assert(testThing === piece); // Now let's get the piece and check if it was updated var req = apos.tasks.getReq(); req.body = {}; req.body._id = "testThing"; apos.modules['things'].requirePiece(req, req.res, function() { assert(req.piece); assert(req.piece._id === 'testThing'); assert(req.piece.foo === 'goo'); done(); }); }) .catch(function(err) { assert(!err); }); }); // Test pieces.addListFilters() it('should only execute filters that are safe and have a launder method', function() { var publicTest = false; var manageTest = false; // addListFilters should execute launder and filters for filter // definitions that are safe for 'public' or 'manage' contexts var mockCursor = apos.docs.find(apos.tasks.getAnonReq()); _.merge(mockCursor, { filters: { publicTest: { launder: function(s) { return 'laundered'; }, safeFor: 'public' }, manageTest: { launder: function(s) { return 'laundered'; }, safeFor: 'manage' }, unsafeTest: {} }, publicTest: function(value) { assert(value === 'laundered'); publicTest = true; }, manageTest: function(value) { assert(value === 'laundered'); manageTest = true; }, unsafeTest: function(value) { assert.fail('unsafe filter ran'); } }); var filters = { publicTest: 'foo', manageTest: 'bar', unsafeTest: 'nope', fakeTest: 'notEvenReal' }; mockCursor.queryToFilters(filters); assert(publicTest === true); assert(manageTest === true); }); // Test pieces.list() it('should add some more things for testing', function(done) { assert(apos.modules['things'].insert); async.each(additionalThings, function(thing, callback) { apos.modules['things'].insert(apos.tasks.getReq(), thing, function(err) { callback(err); }); }, function(err) { assert(!err); done(); }); }); it('should list all the pieces if skip and limit are set to large enough values', function(done) { assert(apos.modules['things'].list); var req = apos.tasks.getReq(); var filters = { limit: 10, skip: 0 }; apos.modules['things'].list(req, filters, function(err, results) { assert(!err); assert(results.total === 5); assert(results.limit === 10); assert(results.skip === 0); assert(results.pieces.length === 5); done(); }); }); // pieces.trash() it('should be able to trash a piece', function(done) { assert(apos.modules['things'].trash); assert(apos.modules['things'].requirePiece); var req = apos.tasks.getReq(); var id = 'testThing'; req.body = {_id: id}; // let's make sure the piece is not trashed to start findPiece(req, id, function(err, piece) { assert(!err); assert(!piece.trash); apos.modules['things'].trash(req, id, function(err) { assert(!err); // let's get the piece to make sure it is trashed findPiece(req, id, function(err, piece) { assert(!err); assert(piece); assert(piece.trash === true); done(); }); }); }); }); // pieces.rescue() it('should be able to rescue a trashed piece', function(done) { assert(apos.modules['things'].rescue); var req = apos.tasks.getReq(); var id = 'testThing'; req.body = {_id: id}; // let's make sure the piece is trashed to start findPiece(req, id, function(err, piece) { assert(!err); assert(piece.trash === true); apos.modules['things'].rescue(req, id, function(err) { assert(!err); // let's get the piece to make sure it is rescued findPiece(req, id, function(err, piece) { assert(!err); assert(piece); assert(!piece.trash); done(); }); }); }); }); // pieces.apiResponse() it('should pass through an error message if the error is passed as a string', function(done) { assert(apos.modules['things'].apiResponse); var res = apos.tasks.getAnonReq().res; var errMsg = "Test Error"; res.send = function(response) { assert(response); assert(response.status === errMsg); assert(!response.data); done(); }; apos.modules['things'].apiResponse(res, errMsg, { foo: 'bar' }); }); it('should not pass through an error message if the error is not passed as a string', function(done) { assert(apos.modules['things'].apiResponse); var res = apos.tasks.getAnonReq().res; var errMsg = new Error('it is good to see this error in the log'); res.send = function(response) { assert(response); assert(response.status === 'error'); assert(!response.data); done(); }; apos.modules['things'].apiResponse(res, errMsg, { foo: 'bar' }); }); it('should properly pass a result as a json if there is no error', function(done) { assert(apos.modules['things'].apiResponse); var res = apos.tasks.getAnonReq().res; res.send = function(response) { assert(response); assert(response.status === 'ok'); assert(response.data); assert(response.data.foo === 'bar'); done(); }; apos.modules['things'].apiResponse(res, null, { foo: 'bar' }); }); // done with api.js tests, now let's test routes var routeThing = { title: 'purple', foo: 'bar' }; var insertedRouteThing; // routes.insert it('should insert an item from the routes.insert method', function(done) { assert(apos.modules['things'].routes.insert); var req = apos.tasks.getReq(); req.body = routeThing; var res = req.res; res.send = function(result) { assert(result); assert(result.status === 'ok'); assert(result.data); assert(result.data._id); insertedRouteThing = result.data; done(); }; return apos.modules['things'].routes.insert(req, res); }); // routes.retrieve it('should get an item from the routes.retrieve method', function(done) { assert(apos.modules['things'].routes.retrieve); var req = apos.tasks.getReq(); // note we set the req.piece here, because the middleware would do the query nd supply the piece req.piece = insertedRouteThing; var res = req.res; res.send = function(result) { assert(result); assert(result.status === 'ok'); assert(result.data.title === 'purple'); done(); }; return apos.modules['things'].routes.retrieve(req, res); }); // routes.list it('should get a list of all the items from routes.list', function(done) { assert(apos.modules['things'].routes.list); var req = apos.tasks.getReq(); // note we set the req.piece here, because the middleware would do the query nd supply the piece req.body = { limit: 10, skip: 0 }; var res = req.res; res.send = function(result) { assert(result); assert(result.status === 'ok'); assert(result.data.total === 6); assert(result.data.skip === 0); assert(result.data.limit === 10); assert(result.data.pieces.length === 6); done(); }; return apos.modules['things'].routes.list(req, res); }); // routes.update it('should update an item in the database from route.update', function(done) { assert(apos.modules['things'].routes.update); // simulate that middleware first assert(apos.modules['things'].requirePiece); var req = apos.tasks.getReq(); req.body = insertedRouteThing; // make a change to the thing we are inserting req.body.title = "blue"; var res = req.res; res.send = function(result) { assert(result); assert(result.status === 'ok'); assert(result.data.title === 'blue'); done(); }; apos.modules['things'].requirePiece(req, res, function() { return apos.modules['things'].routes.update(req, res); }); }); // routes.trash it('should trash an item in the database from route.trash', function(done) { assert(apos.modules['things'].routes.trash); assert(apos.modules['things'].requirePiece); var req = apos.tasks.getReq(); var id = insertedRouteThing._id; req.body = {_id: id}; var res = req.res; res.send = function(response) { assert(response.status === 'ok'); // let's get the piece to make sure it is trashed findPiece(req, id, function(err, piece) { assert(!err); assert(piece); assert(piece.trash === true); done(); }); }; // let's make sure the piece is not trashed to start findPiece(req, id, function(err, piece) { assert(!err); assert(!piece.trash); apos.modules['things'].routes.trash(req, res); }); }); // routes.rescue it('should rescue an item in the database from route.rescue', function(done) { assert(apos.modules['things'].routes.rescue); assert(apos.modules['things'].requirePiece); var req = apos.tasks.getReq(); var id = insertedRouteThing._id; req.body = {_id: id}; var res = req.res; res.send = function(response) { assert(response.status === 'ok'); // let's get the piece to make sure it no longer trashed findPiece(req, id, function(err, piece) { assert(!err); assert(piece); assert(!piece.trash); done(); }); }; // let's make sure the piece trashed to start findPiece(req, id, function(err, piece) { assert(!err); assert(piece.trash === true); apos.modules['things'].routes.rescue(req, res); }); }); it('people can find things via a join', function() { var req = apos.tasks.getReq(); return apos.docs.db.insert(testPeople) .then(function() { return apos.docs.getManager('person').find(req, {}).toObject(); }) .then(function(person) { assert(person); assert(person.title === 'Bob'); assert(person._things); assert(person._things.length === 2); }); }); it('people cannot find things via a join with an inadequate projection', function() { var req = apos.tasks.getReq(); return apos.docs.getManager('person').find(req, {}, {title: 1}).toObject() .then(function(person) { assert(person); assert(person.title === 'Bob'); assert((!person._things) || (person._things.length === 0)); }); }); it('people can find things via a join with a "projection" of the join name', function() { var req = apos.tasks.getReq(); return apos.docs.getManager('person').find(req, {}, {title: 1, _things: 1}).toObject() .then(function(person) { assert(person); assert(person.title === 'Bob'); assert(person._things); assert(person._things.length === 2); }); }); });