1 | var t = require('../test-lib/test.js');
|
2 | var assert = require('assert');
|
3 | var _ = require('@sailshq/lodash');
|
4 | var async = require('async');
|
5 |
|
6 | var apos;
|
7 |
|
8 | describe('Pieces', function() {
|
9 |
|
10 | this.timeout(t.timeout);
|
11 |
|
12 | after(function(done) {
|
13 | return t.destroy(apos, done);
|
14 | });
|
15 |
|
16 |
|
17 |
|
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 |
|
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 |
|
121 | it('should make sure there is no test data hanging around from last time', function(done) {
|
122 |
|
123 | apos.docs.db.remove({}, function(err) {
|
124 | assert(!err);
|
125 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
222 | it('should only execute filters that are safe and have a launder method', function() {
|
223 | var publicTest = false;
|
224 | var manageTest = false;
|
225 |
|
226 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
390 | var routeThing = {
|
391 | title: 'purple',
|
392 | foo: 'bar'
|
393 | };
|
394 |
|
395 | var insertedRouteThing;
|
396 |
|
397 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
456 | it('should update an item in the database from route.update', function(done) {
|
457 | assert(apos.modules['things'].routes.update);
|
458 |
|
459 |
|
460 | assert(apos.modules['things'].requirePiece);
|
461 | var req = apos.tasks.getReq();
|
462 | req.body = insertedRouteThing;
|
463 |
|
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 |
|
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 |
|
489 | findPiece(req, id, function(err, piece) {
|
490 | assert(!err);
|
491 | assert(piece);
|
492 | assert(piece.trash === true);
|
493 | done();
|
494 | });
|
495 | };
|
496 |
|
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 |
|
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 |
|
517 | findPiece(req, id, function(err, piece) {
|
518 | assert(!err);
|
519 | assert(piece);
|
520 | assert(!piece.trash);
|
521 | done();
|
522 | });
|
523 | };
|
524 |
|
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 | });
|