tests: fix tests that did not bubble errors
[express.git] / test / app.router.js
blob8c98aa869b25e88f42a1453fcdc8e29ebcb61ac9
2 var after = require('after');
3 var express = require('../')
4   , request = require('supertest')
5   , assert = require('assert')
6   , methods = require('methods');
8 describe('app.router', function(){
9   it('should restore req.params after leaving router', function(done){
10     var app = express();
11     var router = new express.Router();
13     function handler1(req, res, next){
14       res.setHeader('x-user-id', String(req.params.id));
15       next()
16     }
18     function handler2(req, res){
19       res.send(req.params.id);
20     }
22     router.use(function(req, res, next){
23       res.setHeader('x-router', String(req.params.id));
24       next();
25     });
27     app.get('/user/:id', handler1, router, handler2);
29     request(app)
30     .get('/user/1')
31     .expect('x-router', 'undefined')
32     .expect('x-user-id', '1')
33     .expect(200, '1', done);
34   })
36   describe('methods', function(){
37     methods.concat('del').forEach(function(method){
38       if (method === 'connect') return;
40       it('should include ' + method.toUpperCase(), function(done){
41         var app = express();
43         app[method]('/foo', function(req, res){
44           res.send(method)
45         });
47         request(app)
48         [method]('/foo')
49         .expect(200, done)
50       })
52       it('should reject numbers for app.' + method, function(){
53         var app = express();
54         assert.throws(app[method].bind(app, '/', 3), /Number/)
55       })
56     });
58     it('should re-route when method is altered', function (done) {
59       var app = express();
60       var cb = after(3, done);
62       app.use(function (req, res, next) {
63         if (req.method !== 'POST') return next();
64         req.method = 'DELETE';
65         res.setHeader('X-Method-Altered', '1');
66         next();
67       });
69       app.delete('/', function (req, res) {
70         res.end('deleted everything');
71       });
73       request(app)
74       .get('/')
75       .expect(404, cb)
77       request(app)
78       .delete('/')
79       .expect(200, 'deleted everything', cb);
81       request(app)
82       .post('/')
83       .expect('X-Method-Altered', '1')
84       .expect(200, 'deleted everything', cb);
85     });
86   })
88   describe('decode params', function () {
89     it('should decode correct params', function(done){
90       var app = express();
92       app.get('/:name', function(req, res, next){
93         res.send(req.params.name);
94       });
96       request(app)
97       .get('/foo%2Fbar')
98       .expect('foo/bar', done);
99     })
101     it('should not accept params in malformed paths', function(done) {
102       var app = express();
104       app.get('/:name', function(req, res, next){
105         res.send(req.params.name);
106       });
108       request(app)
109       .get('/%foobar')
110       .expect(400, done);
111     })
113     it('should not decode spaces', function(done) {
114       var app = express();
116       app.get('/:name', function(req, res, next){
117         res.send(req.params.name);
118       });
120       request(app)
121       .get('/foo+bar')
122       .expect('foo+bar', done);
123     })
125     it('should work with unicode', function(done) {
126       var app = express();
128       app.get('/:name', function(req, res, next){
129         res.send(req.params.name);
130       });
132       request(app)
133       .get('/%ce%b1')
134       .expect('\u03b1', done);
135     })
136   })
138   it('should be .use()able', function(done){
139     var app = express();
141     var calls = [];
143     app.use(function(req, res, next){
144       calls.push('before');
145       next();
146     });
148     app.get('/', function(req, res, next){
149       calls.push('GET /')
150       next();
151     });
153     app.use(function(req, res, next){
154       calls.push('after');
155       res.json(calls)
156     });
158     request(app)
159     .get('/')
160     .expect(200, ['before', 'GET /', 'after'], done)
161   })
163   describe('when given a regexp', function(){
164     it('should match the pathname only', function(done){
165       var app = express();
167       app.get(/^\/user\/[0-9]+$/, function(req, res){
168         res.end('user');
169       });
171       request(app)
172       .get('/user/12?foo=bar')
173       .expect('user', done);
174     })
176     it('should populate req.params with the captures', function(done){
177       var app = express();
179       app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function(req, res){
180         var id = req.params[0]
181           , op = req.params[1];
182         res.end(op + 'ing user ' + id);
183       });
185       request(app)
186       .get('/user/10/edit')
187       .expect('editing user 10', done);
188     })
190     it('should ensure regexp matches path prefix', function (done) {
191       var app = express()
192       var p = []
194       app.use(/\/api.*/, function (req, res, next) {
195         p.push('a')
196         next()
197       })
198       app.use(/api/, function (req, res, next) {
199         p.push('b')
200         next()
201       })
202       app.use(/\/test/, function (req, res, next) {
203         p.push('c')
204         next()
205       })
206       app.use(function (req, res) {
207         res.end()
208       })
210       request(app)
211         .get('/test/api/1234')
212         .expect(200, function (err) {
213           if (err) return done(err)
214           assert.deepEqual(p, ['c'])
215           done()
216         })
217     })
218   })
220   describe('case sensitivity', function(){
221     it('should be disabled by default', function(done){
222       var app = express();
224       app.get('/user', function(req, res){
225         res.end('tj');
226       });
228       request(app)
229       .get('/USER')
230       .expect('tj', done);
231     })
233     describe('when "case sensitive routing" is enabled', function(){
234       it('should match identical casing', function(done){
235         var app = express();
237         app.enable('case sensitive routing');
239         app.get('/uSer', function(req, res){
240           res.end('tj');
241         });
243         request(app)
244         .get('/uSer')
245         .expect('tj', done);
246       })
248       it('should not match otherwise', function(done){
249         var app = express();
251         app.enable('case sensitive routing');
253         app.get('/uSer', function(req, res){
254           res.end('tj');
255         });
257         request(app)
258         .get('/user')
259         .expect(404, done);
260       })
261     })
262   })
264   describe('params', function(){
265     it('should overwrite existing req.params by default', function(done){
266       var app = express();
267       var router = new express.Router();
269       router.get('/:action', function(req, res){
270         res.send(req.params);
271       });
273       app.use('/user/:user', router);
275       request(app)
276       .get('/user/1/get')
277       .expect(200, '{"action":"get"}', done);
278     })
280     it('should allow merging existing req.params', function(done){
281       var app = express();
282       var router = new express.Router({ mergeParams: true });
284       router.get('/:action', function(req, res){
285         var keys = Object.keys(req.params).sort();
286         res.send(keys.map(function(k){ return [k, req.params[k]] }));
287       });
289       app.use('/user/:user', router);
291       request(app)
292       .get('/user/tj/get')
293       .expect(200, '[["action","get"],["user","tj"]]', done);
294     })
296     it('should use params from router', function(done){
297       var app = express();
298       var router = new express.Router({ mergeParams: true });
300       router.get('/:thing', function(req, res){
301         var keys = Object.keys(req.params).sort();
302         res.send(keys.map(function(k){ return [k, req.params[k]] }));
303       });
305       app.use('/user/:thing', router);
307       request(app)
308       .get('/user/tj/get')
309       .expect(200, '[["thing","get"]]', done);
310     })
312     it('should merge numeric indices req.params', function(done){
313       var app = express();
314       var router = new express.Router({ mergeParams: true });
316       router.get('/*.*', function(req, res){
317         var keys = Object.keys(req.params).sort();
318         res.send(keys.map(function(k){ return [k, req.params[k]] }));
319       });
321       app.use('/user/id:(\\d+)', router);
323       request(app)
324       .get('/user/id:10/profile.json')
325       .expect(200, '[["0","10"],["1","profile"],["2","json"]]', done);
326     })
328     it('should merge numeric indices req.params when more in parent', function(done){
329       var app = express();
330       var router = new express.Router({ mergeParams: true });
332       router.get('/*', function(req, res){
333         var keys = Object.keys(req.params).sort();
334         res.send(keys.map(function(k){ return [k, req.params[k]] }));
335       });
337       app.use('/user/id:(\\d+)/name:(\\w+)', router);
339       request(app)
340       .get('/user/id:10/name:tj/profile')
341       .expect(200, '[["0","10"],["1","tj"],["2","profile"]]', done);
342     })
344     it('should merge numeric indices req.params when parent has same number', function(done){
345       var app = express();
346       var router = new express.Router({ mergeParams: true });
348       router.get('/name:(\\w+)', function(req, res){
349         var keys = Object.keys(req.params).sort();
350         res.send(keys.map(function(k){ return [k, req.params[k]] }));
351       });
353       app.use('/user/id:(\\d+)', router);
355       request(app)
356       .get('/user/id:10/name:tj')
357       .expect(200, '[["0","10"],["1","tj"]]', done);
358     })
360     it('should ignore invalid incoming req.params', function(done){
361       var app = express();
362       var router = new express.Router({ mergeParams: true });
364       router.get('/:name', function(req, res){
365         var keys = Object.keys(req.params).sort();
366         res.send(keys.map(function(k){ return [k, req.params[k]] }));
367       });
369       app.use('/user/', function (req, res, next) {
370         req.params = 3; // wat?
371         router(req, res, next);
372       });
374       request(app)
375       .get('/user/tj')
376       .expect(200, '[["name","tj"]]', done);
377     })
379     it('should restore req.params', function(done){
380       var app = express();
381       var router = new express.Router({ mergeParams: true });
383       router.get('/user:(\\w+)/*', function (req, res, next) {
384         next();
385       });
387       app.use('/user/id:(\\d+)', function (req, res, next) {
388         router(req, res, function (err) {
389           var keys = Object.keys(req.params).sort();
390           res.send(keys.map(function(k){ return [k, req.params[k]] }));
391         });
392       });
394       request(app)
395       .get('/user/id:42/user:tj/profile')
396       .expect(200, '[["0","42"]]', done);
397     })
398   })
400   describe('trailing slashes', function(){
401     it('should be optional by default', function(done){
402       var app = express();
404       app.get('/user', function(req, res){
405         res.end('tj');
406       });
408       request(app)
409       .get('/user/')
410       .expect('tj', done);
411     })
413     describe('when "strict routing" is enabled', function(){
414       it('should match trailing slashes', function(done){
415         var app = express();
417         app.enable('strict routing');
419         app.get('/user/', function(req, res){
420           res.end('tj');
421         });
423         request(app)
424         .get('/user/')
425         .expect('tj', done);
426       })
428       it('should pass-though middleware', function(done){
429         var app = express();
431         app.enable('strict routing');
433         app.use(function (req, res, next) {
434           res.setHeader('x-middleware', 'true');
435           next();
436         });
438         app.get('/user/', function(req, res){
439           res.end('tj');
440         });
442         request(app)
443         .get('/user/')
444         .expect('x-middleware', 'true')
445         .expect(200, 'tj', done);
446       })
448       it('should pass-though mounted middleware', function(done){
449         var app = express();
451         app.enable('strict routing');
453         app.use('/user/', function (req, res, next) {
454           res.setHeader('x-middleware', 'true');
455           next();
456         });
458         app.get('/user/test/', function(req, res){
459           res.end('tj');
460         });
462         request(app)
463         .get('/user/test/')
464         .expect('x-middleware', 'true')
465         .expect(200, 'tj', done);
466       })
468       it('should match no slashes', function(done){
469         var app = express();
471         app.enable('strict routing');
473         app.get('/user', function(req, res){
474           res.end('tj');
475         });
477         request(app)
478         .get('/user')
479         .expect('tj', done);
480       })
482       it('should match middleware when omitting the trailing slash', function(done){
483         var app = express();
485         app.enable('strict routing');
487         app.use('/user/', function(req, res){
488           res.end('tj');
489         });
491         request(app)
492         .get('/user')
493         .expect(200, 'tj', done);
494       })
496       it('should match middleware', function(done){
497         var app = express();
499         app.enable('strict routing');
501         app.use('/user', function(req, res){
502           res.end('tj');
503         });
505         request(app)
506         .get('/user')
507         .expect(200, 'tj', done);
508       })
510       it('should match middleware when adding the trailing slash', function(done){
511         var app = express();
513         app.enable('strict routing');
515         app.use('/user', function(req, res){
516           res.end('tj');
517         });
519         request(app)
520         .get('/user/')
521         .expect(200, 'tj', done);
522       })
524       it('should fail when omitting the trailing slash', function(done){
525         var app = express();
527         app.enable('strict routing');
529         app.get('/user/', function(req, res){
530           res.end('tj');
531         });
533         request(app)
534         .get('/user')
535         .expect(404, done);
536       })
538       it('should fail when adding the trailing slash', function(done){
539         var app = express();
541         app.enable('strict routing');
543         app.get('/user', function(req, res){
544           res.end('tj');
545         });
547         request(app)
548         .get('/user/')
549         .expect(404, done);
550       })
551     })
552   })
554   it('should allow escaped regexp', function(done){
555     var app = express();
557     app.get('/user/\\d+', function(req, res){
558       res.end('woot');
559     });
561     request(app)
562     .get('/user/10')
563     .expect(200, function (err) {
564       if (err) return done(err)
565       request(app)
566       .get('/user/tj')
567       .expect(404, done);
568     });
569   })
571   it('should allow literal "."', function(done){
572     var app = express();
574     app.get('/api/users/:from..:to', function(req, res){
575       var from = req.params.from
576         , to = req.params.to;
578       res.end('users from ' + from + ' to ' + to);
579     });
581     request(app)
582     .get('/api/users/1..50')
583     .expect('users from 1 to 50', done);
584   })
586   describe('*', function(){
587     it('should capture everything', function (done) {
588       var app = express()
590       app.get('*', function (req, res) {
591         res.end(req.params[0])
592       })
594       request(app)
595       .get('/user/tobi.json')
596       .expect('/user/tobi.json', done)
597     })
599     it('should decode the capture', function (done) {
600       var app = express()
602       app.get('*', function (req, res) {
603         res.end(req.params[0])
604       })
606       request(app)
607       .get('/user/tobi%20and%20loki.json')
608       .expect('/user/tobi and loki.json', done)
609     })
611     it('should denote a greedy capture group', function(done){
612       var app = express();
614       app.get('/user/*.json', function(req, res){
615         res.end(req.params[0]);
616       });
618       request(app)
619       .get('/user/tj.json')
620       .expect('tj', done);
621     })
623     it('should work with several', function(done){
624       var app = express();
626       app.get('/api/*.*', function(req, res){
627         var resource = req.params[0]
628           , format = req.params[1];
629         res.end(resource + ' as ' + format);
630       });
632       request(app)
633       .get('/api/users/foo.bar.json')
634       .expect('users/foo.bar as json', done);
635     })
637     it('should work cross-segment', function(done){
638       var app = express();
639       var cb = after(2, done)
641       app.get('/api*', function(req, res){
642         res.send(req.params[0]);
643       });
645       request(app)
646         .get('/api')
647         .expect(200, '', cb)
649       request(app)
650         .get('/api/hey')
651         .expect(200, '/hey', cb)
652     })
654     it('should allow naming', function(done){
655       var app = express();
657       app.get('/api/:resource(*)', function(req, res){
658         var resource = req.params.resource;
659         res.end(resource);
660       });
662       request(app)
663       .get('/api/users/0.json')
664       .expect('users/0.json', done);
665     })
667     it('should not be greedy immediately after param', function(done){
668       var app = express();
670       app.get('/user/:user*', function(req, res){
671         res.end(req.params.user);
672       });
674       request(app)
675       .get('/user/122')
676       .expect('122', done);
677     })
679     it('should eat everything after /', function(done){
680       var app = express();
682       app.get('/user/:user*', function(req, res){
683         res.end(req.params.user);
684       });
686       request(app)
687       .get('/user/122/aaa')
688       .expect('122', done);
689     })
691     it('should span multiple segments', function(done){
692       var app = express();
694       app.get('/file/*', function(req, res){
695         res.end(req.params[0]);
696       });
698       request(app)
699       .get('/file/javascripts/jquery.js')
700       .expect('javascripts/jquery.js', done);
701     })
703     it('should be optional', function(done){
704       var app = express();
706       app.get('/file/*', function(req, res){
707         res.end(req.params[0]);
708       });
710       request(app)
711       .get('/file/')
712       .expect('', done);
713     })
715     it('should require a preceding /', function(done){
716       var app = express();
718       app.get('/file/*', function(req, res){
719         res.end(req.params[0]);
720       });
722       request(app)
723       .get('/file')
724       .expect(404, done);
725     })
727     it('should keep correct parameter indexes', function(done){
728       var app = express();
730       app.get('/*/user/:id', function (req, res) {
731         res.send(req.params);
732       });
734       request(app)
735       .get('/1/user/2')
736       .expect(200, '{"0":"1","id":"2"}', done);
737     })
739     it('should work within arrays', function(done){
740       var app = express();
742       app.get(['/user/:id', '/foo/*', '/:bar'], function (req, res) {
743         res.send(req.params.bar);
744       });
746       request(app)
747       .get('/test')
748       .expect(200, 'test', done);
749     })
750   })
752   describe(':name', function(){
753     it('should denote a capture group', function(done){
754       var app = express();
756       app.get('/user/:user', function(req, res){
757         res.end(req.params.user);
758       });
760       request(app)
761       .get('/user/tj')
762       .expect('tj', done);
763     })
765     it('should match a single segment only', function(done){
766       var app = express();
768       app.get('/user/:user', function(req, res){
769         res.end(req.params.user);
770       });
772       request(app)
773       .get('/user/tj/edit')
774       .expect(404, done);
775     })
777     it('should allow several capture groups', function(done){
778       var app = express();
780       app.get('/user/:user/:op', function(req, res){
781         res.end(req.params.op + 'ing ' + req.params.user);
782       });
784       request(app)
785       .get('/user/tj/edit')
786       .expect('editing tj', done);
787     })
789     it('should work following a partial capture group', function(done){
790       var app = express();
791       var cb = after(2, done);
793       app.get('/user(s)?/:user/:op', function(req, res){
794         res.end(req.params.op + 'ing ' + req.params.user + (req.params[0] ? ' (old)' : ''));
795       });
797       request(app)
798       .get('/user/tj/edit')
799       .expect('editing tj', cb);
801       request(app)
802       .get('/users/tj/edit')
803       .expect('editing tj (old)', cb);
804     })
806     it('should work inside literal parenthesis', function(done){
807       var app = express();
809       app.get('/:user\\(:op\\)', function(req, res){
810         res.end(req.params.op + 'ing ' + req.params.user);
811       });
813       request(app)
814       .get('/tj(edit)')
815       .expect('editing tj', done);
816     })
818     it('should work in array of paths', function(done){
819       var app = express();
820       var cb = after(2, done);
822       app.get(['/user/:user/poke', '/user/:user/pokes'], function(req, res){
823         res.end('poking ' + req.params.user);
824       });
826       request(app)
827       .get('/user/tj/poke')
828       .expect('poking tj', cb);
830       request(app)
831       .get('/user/tj/pokes')
832       .expect('poking tj', cb);
833     })
834   })
836   describe(':name?', function(){
837     it('should denote an optional capture group', function(done){
838       var app = express();
840       app.get('/user/:user/:op?', function(req, res){
841         var op = req.params.op || 'view';
842         res.end(op + 'ing ' + req.params.user);
843       });
845       request(app)
846       .get('/user/tj')
847       .expect('viewing tj', done);
848     })
850     it('should populate the capture group', function(done){
851       var app = express();
853       app.get('/user/:user/:op?', function(req, res){
854         var op = req.params.op || 'view';
855         res.end(op + 'ing ' + req.params.user);
856       });
858       request(app)
859       .get('/user/tj/edit')
860       .expect('editing tj', done);
861     })
862   })
864   describe('.:name', function(){
865     it('should denote a format', function(done){
866       var app = express();
867       var cb = after(2, done)
869       app.get('/:name.:format', function(req, res){
870         res.end(req.params.name + ' as ' + req.params.format);
871       });
873       request(app)
874         .get('/foo.json')
875         .expect(200, 'foo as json', cb)
877       request(app)
878         .get('/foo')
879         .expect(404, cb)
880     })
881   })
883   describe('.:name?', function(){
884     it('should denote an optional format', function(done){
885       var app = express();
886       var cb = after(2, done)
888       app.get('/:name.:format?', function(req, res){
889         res.end(req.params.name + ' as ' + (req.params.format || 'html'));
890       });
892       request(app)
893         .get('/foo')
894         .expect(200, 'foo as html', cb)
896       request(app)
897         .get('/foo.json')
898         .expect(200, 'foo as json', done)
899     })
900   })
902   describe('when next() is called', function(){
903     it('should continue lookup', function(done){
904       var app = express()
905         , calls = [];
907       app.get('/foo/:bar?', function(req, res, next){
908         calls.push('/foo/:bar?');
909         next();
910       });
912       app.get('/bar', function(req, res){
913         assert(0);
914       });
916       app.get('/foo', function(req, res, next){
917         calls.push('/foo');
918         next();
919       });
921       app.get('/foo', function(req, res, next){
922         calls.push('/foo 2');
923         res.json(calls)
924       });
926       request(app)
927       .get('/foo')
928       .expect(200, ['/foo/:bar?', '/foo', '/foo 2'], done)
929     })
930   })
932   describe('when next("route") is called', function(){
933     it('should jump to next route', function(done){
934       var app = express()
936       function fn(req, res, next){
937         res.set('X-Hit', '1')
938         next('route')
939       }
941       app.get('/foo', fn, function(req, res, next){
942         res.end('failure')
943       });
945       app.get('/foo', function(req, res){
946         res.end('success')
947       })
949       request(app)
950       .get('/foo')
951       .expect('X-Hit', '1')
952       .expect(200, 'success', done)
953     })
954   })
956   describe('when next("router") is called', function () {
957     it('should jump out of router', function (done) {
958       var app = express()
959       var router = express.Router()
961       function fn (req, res, next) {
962         res.set('X-Hit', '1')
963         next('router')
964       }
966       router.get('/foo', fn, function (req, res, next) {
967         res.end('failure')
968       })
970       router.get('/foo', function (req, res, next) {
971         res.end('failure')
972       })
974       app.use(router)
976       app.get('/foo', function (req, res) {
977         res.end('success')
978       })
980       request(app)
981       .get('/foo')
982       .expect('X-Hit', '1')
983       .expect(200, 'success', done)
984     })
985   })
987   describe('when next(err) is called', function(){
988     it('should break out of app.router', function(done){
989       var app = express()
990         , calls = [];
992       app.get('/foo/:bar?', function(req, res, next){
993         calls.push('/foo/:bar?');
994         next();
995       });
997       app.get('/bar', function(req, res){
998         assert(0);
999       });
1001       app.get('/foo', function(req, res, next){
1002         calls.push('/foo');
1003         next(new Error('fail'));
1004       });
1006       app.get('/foo', function(req, res, next){
1007         assert(0);
1008       });
1010       app.use(function(err, req, res, next){
1011         res.json({
1012           calls: calls,
1013           error: err.message
1014         })
1015       })
1017       request(app)
1018       .get('/foo')
1019       .expect(200, { calls: ['/foo/:bar?', '/foo'], error: 'fail' }, done)
1020     })
1022     it('should call handler in same route, if exists', function(done){
1023       var app = express();
1025       function fn1(req, res, next) {
1026         next(new Error('boom!'));
1027       }
1029       function fn2(req, res, next) {
1030         res.send('foo here');
1031       }
1033       function fn3(err, req, res, next) {
1034         res.send('route go ' + err.message);
1035       }
1037       app.get('/foo', fn1, fn2, fn3);
1039       app.use(function (err, req, res, next) {
1040         res.end('error!');
1041       })
1043       request(app)
1044       .get('/foo')
1045       .expect('route go boom!', done)
1046     })
1047   })
1049   it('should allow rewriting of the url', function(done){
1050     var app = express();
1052     app.get('/account/edit', function(req, res, next){
1053       req.user = { id: 12 }; // faux authenticated user
1054       req.url = '/user/' + req.user.id + '/edit';
1055       next();
1056     });
1058     app.get('/user/:id/edit', function(req, res){
1059       res.send('editing user ' + req.params.id);
1060     });
1062     request(app)
1063     .get('/account/edit')
1064     .expect('editing user 12', done);
1065   })
1067   it('should run in order added', function(done){
1068     var app = express();
1069     var path = [];
1071     app.get('*', function(req, res, next){
1072       path.push(0);
1073       next();
1074     });
1076     app.get('/user/:id', function(req, res, next){
1077       path.push(1);
1078       next();
1079     });
1081     app.use(function(req, res, next){
1082       path.push(2);
1083       next();
1084     });
1086     app.all('/user/:id', function(req, res, next){
1087       path.push(3);
1088       next();
1089     });
1091     app.get('*', function(req, res, next){
1092       path.push(4);
1093       next();
1094     });
1096     app.use(function(req, res, next){
1097       path.push(5);
1098       res.end(path.join(','))
1099     });
1101     request(app)
1102     .get('/user/1')
1103     .expect(200, '0,1,2,3,4,5', done);
1104   })
1106   it('should be chainable', function(){
1107     var app = express();
1108     assert.strictEqual(app.get('/', function () {}), app)
1109   })