UNPKG

16.2 kBJavaScriptView Raw
1var t = require('../test-lib/test.js');
2var assert = require('assert');
3var _ = require('@sailshq/lodash');
4var async = require('async');
5
6var apos;
7
8describe('Pieces', function() {
9
10 this.timeout(t.timeout);
11
12 after(function(done) {
13 return t.destroy(apos, done);
14 });
15
16 /// ///
17 // EXISTENCE
18 /// ///
19
20 it('should initialize with a schema', function(done) {
21 apos = require('../index.js')({
22 root: module,
23 shortName: 'test',
24
25 modules: {
26 'apostrophe-express': {
27 secret: 'xxx',
28 port: 7900
29 },
30 'things': {
31 extend: 'apostrophe-pieces',
32 name: 'thing',
33 label: 'Thing',
34 addFields: {
35 name: 'foo',
36 label: 'Foo',
37 type: 'string'
38 }
39 },
40 'people': {
41 extend: 'apostrophe-pieces',
42 name: 'person',
43 label: 'Person',
44 addFields: {
45 name: '_things',
46 type: 'joinByArray'
47 }
48 }
49 },
50 afterInit: function(callback) {
51 assert(apos.modules['things']);
52 assert(apos.modules['things'].schema);
53 apos.argv._ = [];
54 return callback(null);
55 },
56 afterListen: function(err) {
57 assert(!err);
58 done();
59 }
60 });
61 });
62
63 // little test-helper function to get piece by id regardless of trash status
64 function findPiece(req, id, callback) {
65 return apos.modules['things'].find(req, { _id: id })
66 .permission('edit')
67 .published(null)
68 .trash(null)
69 .toObject(function(err, piece) {
70 if (err) {
71 return callback(err);
72 }
73 if (!piece) {
74 return callback('notfound');
75 }
76 return callback(err, piece);
77 }
78 );
79 };
80
81 var testThing = {
82 _id: 'testThing',
83 title: 'hello',
84 foo: 'bar'
85 };
86
87 var testThing2 = {
88 _id: 'testThing2',
89 title: 'hello2',
90 foo: 'bar2'
91 };
92
93 var additionalThings = [
94 {
95 _id: 'thing1',
96 title: 'Red'
97 },
98 {
99 _id: 'thing2',
100 title: 'Blue',
101 published: true
102 },
103 {
104 _id: 'thing3',
105 title: 'Green',
106 published: true
107 }
108 ];
109
110 var testPeople = [
111 {
112 _id: 'person1',
113 title: 'Bob',
114 type: 'person',
115 thingsIds: [ 'thing2', 'thing3' ],
116 published: true
117 }
118 ];
119
120 // Wipe the database so we can run this test suite independent of bootstrap
121 it('should make sure there is no test data hanging around from last time', function(done) {
122 // Attempt to purge the entire aposDocs collection
123 apos.docs.db.remove({}, function(err) {
124 assert(!err);
125 // Make sure it went away
126 apos.docs.db.findWithProjection({ _id: 'testThing' }).toArray(function(err, docs) {
127 assert(!err);
128 assert(docs.length === 0);
129 done();
130 });
131 });
132 });
133
134 // Test pieces.newInstance()
135 it('should be able to create a new piece', function() {
136 assert(apos.modules['things'].newInstance);
137 var thing = apos.modules['things'].newInstance();
138 assert(thing);
139 assert(thing.type === 'thing');
140 });
141
142 // Test pieces.insert()
143 it('should be able to insert a piece into the database', function(done) {
144 assert(apos.modules['things'].insert);
145 apos.modules['things'].insert(apos.tasks.getReq(), testThing, function(err, piece) {
146 assert(!err);
147 assert(testThing === piece);
148 done();
149 });
150 });
151
152 it('same thing with promises', function(done) {
153 assert(apos.modules['things'].insert);
154 apos.modules['things'].insert(apos.tasks.getReq(), testThing2)
155 .then(function(piece2) {
156 assert(testThing2 === piece2);
157 done();
158 })
159 .catch(function(err) {
160 assert(!err);
161 });
162 });
163
164 // Test pieces.requirePiece()
165 it('should be able to retrieve a piece by id from the database', function(done) {
166 assert(apos.modules['things'].requirePiece);
167 var req = apos.tasks.getReq();
168 req.body = {};
169 req.body._id = "testThing";
170 apos.modules['things'].requirePiece(req, req.res, function() {
171 assert(req.piece);
172 assert(req.piece._id === 'testThing');
173 assert(req.piece.title === 'hello');
174 assert(req.piece.foo === 'bar');
175 done();
176 });
177 });
178
179 // Test pieces.update()
180 it('should be able to update a piece in the database', function(done) {
181 assert(apos.modules['things'].update);
182 testThing.foo = 'moo';
183 apos.modules['things'].update(apos.tasks.getReq(), testThing, function(err, piece) {
184 assert(!err);
185 assert(testThing === piece);
186 // Now let's get the piece and check if it was updated
187 var req = apos.tasks.getReq();
188 req.body = {};
189 req.body._id = "testThing";
190 apos.modules['things'].requirePiece(req, req.res, function() {
191 assert(req.piece);
192 assert(req.piece._id === 'testThing');
193 assert(req.piece.foo === 'moo');
194 done();
195 });
196 });
197 });
198
199 it('same thing with promises', function(done) {
200 assert(apos.modules['things'].update);
201 testThing.foo = 'goo';
202 apos.modules['things'].update(apos.tasks.getReq(), testThing)
203 .then(function(piece) {
204 assert(testThing === piece);
205 // Now let's get the piece and check if it was updated
206 var req = apos.tasks.getReq();
207 req.body = {};
208 req.body._id = "testThing";
209 apos.modules['things'].requirePiece(req, req.res, function() {
210 assert(req.piece);
211 assert(req.piece._id === 'testThing');
212 assert(req.piece.foo === 'goo');
213 done();
214 });
215 })
216 .catch(function(err) {
217 assert(!err);
218 });
219 });
220
221 // Test pieces.addListFilters()
222 it('should only execute filters that are safe and have a launder method', function() {
223 var publicTest = false;
224 var manageTest = false;
225 // addListFilters should execute launder and filters for filter
226 // definitions that are safe for 'public' or 'manage' contexts
227 var mockCursor = apos.docs.find(apos.tasks.getAnonReq());
228 _.merge(mockCursor, {
229 filters: {
230 publicTest: {
231 launder: function(s) {
232 return 'laundered';
233 },
234 safeFor: 'public'
235 },
236 manageTest: {
237 launder: function(s) {
238 return 'laundered';
239 },
240 safeFor: 'manage'
241 },
242 unsafeTest: {}
243 },
244 publicTest: function(value) {
245 assert(value === 'laundered');
246 publicTest = true;
247 },
248 manageTest: function(value) {
249 assert(value === 'laundered');
250 manageTest = true;
251 },
252 unsafeTest: function(value) {
253 assert.fail('unsafe filter ran');
254 }
255 });
256
257 var filters = {
258 publicTest: 'foo',
259 manageTest: 'bar',
260 unsafeTest: 'nope',
261 fakeTest: 'notEvenReal'
262 };
263
264 mockCursor.queryToFilters(filters);
265 assert(publicTest === true);
266 assert(manageTest === true);
267 });
268
269 // Test pieces.list()
270 it('should add some more things for testing', function(done) {
271 assert(apos.modules['things'].insert);
272 async.each(additionalThings, function(thing, callback) {
273 apos.modules['things'].insert(apos.tasks.getReq(), thing, function(err) {
274 callback(err);
275 });
276 }, function(err) {
277 assert(!err);
278 done();
279 });
280 });
281
282 it('should list all the pieces if skip and limit are set to large enough values', function(done) {
283 assert(apos.modules['things'].list);
284 var req = apos.tasks.getReq();
285 var filters = {
286 limit: 10,
287 skip: 0
288 };
289 apos.modules['things'].list(req, filters, function(err, results) {
290 assert(!err);
291 assert(results.total === 5);
292 assert(results.limit === 10);
293 assert(results.skip === 0);
294 assert(results.pieces.length === 5);
295 done();
296 });
297 });
298
299 // pieces.trash()
300 it('should be able to trash a piece', function(done) {
301 assert(apos.modules['things'].trash);
302 assert(apos.modules['things'].requirePiece);
303 var req = apos.tasks.getReq();
304 var id = 'testThing';
305 req.body = {_id: id};
306 // let's make sure the piece is not trashed to start
307 findPiece(req, id, function(err, piece) {
308 assert(!err);
309 assert(!piece.trash);
310 apos.modules['things'].trash(req, id, function(err) {
311 assert(!err);
312 // let's get the piece to make sure it is trashed
313 findPiece(req, id, function(err, piece) {
314 assert(!err);
315 assert(piece);
316 assert(piece.trash === true);
317 done();
318 });
319 });
320 });
321 });
322
323 // pieces.rescue()
324 it('should be able to rescue a trashed piece', function(done) {
325 assert(apos.modules['things'].rescue);
326 var req = apos.tasks.getReq();
327 var id = 'testThing';
328 req.body = {_id: id};
329 // let's make sure the piece is trashed to start
330 findPiece(req, id, function(err, piece) {
331 assert(!err);
332 assert(piece.trash === true);
333 apos.modules['things'].rescue(req, id, function(err) {
334 assert(!err);
335 // let's get the piece to make sure it is rescued
336 findPiece(req, id, function(err, piece) {
337 assert(!err);
338 assert(piece);
339 assert(!piece.trash);
340 done();
341 });
342 });
343 });
344 });
345
346 // pieces.apiResponse()
347 it('should pass through an error message if the error is passed as a string', function(done) {
348 assert(apos.modules['things'].apiResponse);
349 var res = apos.tasks.getAnonReq().res;
350 var errMsg = "Test Error";
351 res.send = function(response) {
352 assert(response);
353 assert(response.status === errMsg);
354 assert(!response.data);
355 done();
356 };
357
358 apos.modules['things'].apiResponse(res, errMsg, { foo: 'bar' });
359 });
360
361 it('should not pass through an error message if the error is not passed as a string', function(done) {
362 assert(apos.modules['things'].apiResponse);
363 var res = apos.tasks.getAnonReq().res;
364 var errMsg = new Error('it is good to see this error in the log');
365 res.send = function(response) {
366 assert(response);
367 assert(response.status === 'error');
368 assert(!response.data);
369 done();
370 };
371
372 apos.modules['things'].apiResponse(res, errMsg, { foo: 'bar' });
373 });
374
375 it('should properly pass a result as a json if there is no error', function(done) {
376 assert(apos.modules['things'].apiResponse);
377 var res = apos.tasks.getAnonReq().res;
378 res.send = function(response) {
379 assert(response);
380 assert(response.status === 'ok');
381 assert(response.data);
382 assert(response.data.foo === 'bar');
383 done();
384 };
385
386 apos.modules['things'].apiResponse(res, null, { foo: 'bar' });
387 });
388
389 // done with api.js tests, now let's test routes
390 var routeThing = {
391 title: 'purple',
392 foo: 'bar'
393 };
394
395 var insertedRouteThing;
396
397 // routes.insert
398 it('should insert an item from the routes.insert method', function(done) {
399 assert(apos.modules['things'].routes.insert);
400
401 var req = apos.tasks.getReq();
402 req.body = routeThing;
403 var res = req.res;
404 res.send = function(result) {
405 assert(result);
406 assert(result.status === 'ok');
407 assert(result.data);
408 assert(result.data._id);
409 insertedRouteThing = result.data;
410 done();
411 };
412
413 return apos.modules['things'].routes.insert(req, res);
414 });
415
416 // routes.retrieve
417 it('should get an item from the routes.retrieve method', function(done) {
418 assert(apos.modules['things'].routes.retrieve);
419
420 var req = apos.tasks.getReq();
421 // note we set the req.piece here, because the middleware would do the query nd supply the piece
422 req.piece = insertedRouteThing;
423 var res = req.res;
424 res.send = function(result) {
425 assert(result);
426 assert(result.status === 'ok');
427 assert(result.data.title === 'purple');
428 done();
429 };
430
431 return apos.modules['things'].routes.retrieve(req, res);
432 });
433
434 // routes.list
435 it('should get a list of all the items from routes.list', function(done) {
436 assert(apos.modules['things'].routes.list);
437
438 var req = apos.tasks.getReq();
439 // note we set the req.piece here, because the middleware would do the query nd supply the piece
440 req.body = { limit: 10, skip: 0 };
441 var res = req.res;
442 res.send = function(result) {
443 assert(result);
444 assert(result.status === 'ok');
445 assert(result.data.total === 6);
446 assert(result.data.skip === 0);
447 assert(result.data.limit === 10);
448 assert(result.data.pieces.length === 6);
449 done();
450 };
451
452 return apos.modules['things'].routes.list(req, res);
453 });
454
455 // routes.update
456 it('should update an item in the database from route.update', function(done) {
457 assert(apos.modules['things'].routes.update);
458
459 // simulate that middleware first
460 assert(apos.modules['things'].requirePiece);
461 var req = apos.tasks.getReq();
462 req.body = insertedRouteThing;
463 // make a change to the thing we are inserting
464 req.body.title = "blue";
465 var res = req.res;
466 res.send = function(result) {
467 assert(result);
468 assert(result.status === 'ok');
469 assert(result.data.title === 'blue');
470 done();
471 };
472 apos.modules['things'].requirePiece(req, res, function() {
473 return apos.modules['things'].routes.update(req, res);
474 });
475 });
476
477 // routes.trash
478 it('should trash an item in the database from route.trash', function(done) {
479 assert(apos.modules['things'].routes.trash);
480 assert(apos.modules['things'].requirePiece);
481
482 var req = apos.tasks.getReq();
483 var id = insertedRouteThing._id;
484 req.body = {_id: id};
485 var res = req.res;
486 res.send = function(response) {
487 assert(response.status === 'ok');
488 // let's get the piece to make sure it is trashed
489 findPiece(req, id, function(err, piece) {
490 assert(!err);
491 assert(piece);
492 assert(piece.trash === true);
493 done();
494 });
495 };
496 // let's make sure the piece is not trashed to start
497 findPiece(req, id, function(err, piece) {
498 assert(!err);
499 assert(!piece.trash);
500 apos.modules['things'].routes.trash(req, res);
501 });
502
503 });
504
505 // routes.rescue
506 it('should rescue an item in the database from route.rescue', function(done) {
507 assert(apos.modules['things'].routes.rescue);
508 assert(apos.modules['things'].requirePiece);
509
510 var req = apos.tasks.getReq();
511 var id = insertedRouteThing._id;
512 req.body = {_id: id};
513 var res = req.res;
514 res.send = function(response) {
515 assert(response.status === 'ok');
516 // let's get the piece to make sure it no longer trashed
517 findPiece(req, id, function(err, piece) {
518 assert(!err);
519 assert(piece);
520 assert(!piece.trash);
521 done();
522 });
523 };
524 // let's make sure the piece trashed to start
525 findPiece(req, id, function(err, piece) {
526 assert(!err);
527 assert(piece.trash === true);
528 apos.modules['things'].routes.rescue(req, res);
529 });
530
531 });
532
533 it('people can find things via a join', function() {
534 var req = apos.tasks.getReq();
535 return apos.docs.db.insert(testPeople)
536 .then(function() {
537 return apos.docs.getManager('person').find(req, {}).toObject();
538 })
539 .then(function(person) {
540 assert(person);
541 assert(person.title === 'Bob');
542 assert(person._things);
543 assert(person._things.length === 2);
544 });
545 });
546
547 it('people cannot find things via a join with an inadequate projection', function() {
548 var req = apos.tasks.getReq();
549 return apos.docs.getManager('person').find(req, {}, {title: 1}).toObject()
550 .then(function(person) {
551 assert(person);
552 assert(person.title === 'Bob');
553 assert((!person._things) || (person._things.length === 0));
554 });
555 });
556
557 it('people can find things via a join with a "projection" of the join name', function() {
558 var req = apos.tasks.getReq();
559 return apos.docs.getManager('person').find(req, {}, {title: 1, _things: 1}).toObject()
560 .then(function(person) {
561 assert(person);
562 assert(person.title === 'Bob');
563 assert(person._things);
564 assert(person._things.length === 2);
565 });
566 });
567
568});