2 var after = require('after');
3 var express = require('../')
4 , Router = express.Router
5 , methods = require('methods')
6 , assert = require('assert');
8 describe('Router', function(){
9 it('should return a function with router methods', function() {
10 var router = Router();
11 assert(typeof router == 'function');
13 var router = new Router();
14 assert(typeof router == 'function');
16 assert(typeof router.get == 'function');
17 assert(typeof router.handle == 'function');
18 assert(typeof router.use == 'function');
21 it('should support .use of other routers', function(done){
22 var router = new Router();
23 var another = new Router();
25 another.get('/bar', function(req, res){
28 router.use('/foo', another);
30 router.handle({ url: '/foo/bar', method: 'GET' }, { end: done });
33 it('should support dynamic routes', function(done){
34 var router = new Router();
35 var another = new Router();
37 another.get('/:bar', function(req, res){
38 req.params.bar.should.equal('route');
41 router.use('/:foo', another);
43 router.handle({ url: '/test/route', method: 'GET' }, { end: done });
46 it('should handle blank URL', function(done){
47 var router = new Router();
49 router.use(function (req, res) {
50 false.should.be.true()
53 router.handle({ url: '', method: 'GET' }, {}, done);
56 it('should handle missing URL', function (done) {
57 var router = new Router()
59 router.use(function (req, res) {
60 throw new Error('should not be called')
63 router.handle({ method: 'GET' }, {}, done)
66 it('should not stack overflow with many registered routes', function(done){
67 var handler = function(req, res){ res.end(new Error('wrong handler')) };
68 var router = new Router();
70 for (var i = 0; i < 6000; i++) {
71 router.get('/thing' + i, handler)
74 router.get('/', function (req, res) {
78 router.handle({ url: '/', method: 'GET' }, { end: done });
81 describe('.handle', function(){
82 it('should dispatch', function(done){
83 var router = new Router();
85 router.route('/foo').get(function(req, res){
91 val.should.equal('foo');
95 router.handle({ url: '/foo', method: 'GET' }, res);
99 describe('.multiple callbacks', function(){
100 it('should throw if a callback is null', function(){
101 assert.throws(function () {
102 var router = new Router();
103 router.route('/foo').all(null);
107 it('should throw if a callback is undefined', function(){
108 assert.throws(function () {
109 var router = new Router();
110 router.route('/foo').all(undefined);
114 it('should throw if a callback is not a function', function(){
115 assert.throws(function () {
116 var router = new Router();
117 router.route('/foo').all('not a function');
121 it('should not throw if all callbacks are functions', function(){
122 var router = new Router();
123 router.route('/foo').all(function(){}).all(function(){});
127 describe('error', function(){
128 it('should skip non error middleware', function(done){
129 var router = new Router();
131 router.get('/foo', function(req, res, next){
132 next(new Error('foo'));
135 router.get('/bar', function(req, res, next){
136 next(new Error('bar'));
139 router.use(function(req, res, next){
143 router.use(function(err, req, res, next){
144 assert.equal(err.message, 'foo');
148 router.handle({ url: '/foo', method: 'GET' }, {}, done);
151 it('should handle throwing inside routes with params', function(done) {
152 var router = new Router();
154 router.get('/foo/:id', function(req, res, next){
155 throw new Error('foo');
158 router.use(function(req, res, next){
162 router.use(function(err, req, res, next){
163 assert.equal(err.message, 'foo');
167 router.handle({ url: '/foo/2', method: 'GET' }, {}, function() {});
170 it('should handle throwing in handler after async param', function(done) {
171 var router = new Router();
173 router.param('user', function(req, res, next, val){
174 process.nextTick(function(){
180 router.use('/:user', function(req, res, next){
181 throw new Error('oh no!');
184 router.use(function(err, req, res, next){
185 assert.equal(err.message, 'oh no!');
189 router.handle({ url: '/bob', method: 'GET' }, {}, function() {});
192 it('should handle throwing inside error handlers', function(done) {
193 var router = new Router();
195 router.use(function(req, res, next){
196 throw new Error('boom!');
199 router.use(function(err, req, res, next){
200 throw new Error('oops');
203 router.use(function(err, req, res, next){
204 assert.equal(err.message, 'oops');
208 router.handle({ url: '/', method: 'GET' }, {}, done);
212 describe('FQDN', function () {
213 it('should not obscure FQDNs', function (done) {
214 var request = { hit: 0, url: 'http://example.com/foo', method: 'GET' };
215 var router = new Router();
217 router.use(function (req, res, next) {
218 assert.equal(req.hit++, 0);
219 assert.equal(req.url, 'http://example.com/foo');
223 router.handle(request, {}, function (err) {
224 if (err) return done(err);
225 assert.equal(request.hit, 1);
230 it('should ignore FQDN in search', function (done) {
231 var request = { hit: 0, url: '/proxy?url=http://example.com/blog/post/1', method: 'GET' };
232 var router = new Router();
234 router.use('/proxy', function (req, res, next) {
235 assert.equal(req.hit++, 0);
236 assert.equal(req.url, '/?url=http://example.com/blog/post/1');
240 router.handle(request, {}, function (err) {
241 if (err) return done(err);
242 assert.equal(request.hit, 1);
247 it('should ignore FQDN in path', function (done) {
248 var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' };
249 var router = new Router();
251 router.use('/proxy', function (req, res, next) {
252 assert.equal(req.hit++, 0);
253 assert.equal(req.url, '/http://example.com/blog/post/1');
257 router.handle(request, {}, function (err) {
258 if (err) return done(err);
259 assert.equal(request.hit, 1);
264 it('should adjust FQDN req.url', function (done) {
265 var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
266 var router = new Router();
268 router.use('/blog', function (req, res, next) {
269 assert.equal(req.hit++, 0);
270 assert.equal(req.url, 'http://example.com/post/1');
274 router.handle(request, {}, function (err) {
275 if (err) return done(err);
276 assert.equal(request.hit, 1);
281 it('should adjust FQDN req.url with multiple handlers', function (done) {
282 var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
283 var router = new Router();
285 router.use(function (req, res, next) {
286 assert.equal(req.hit++, 0);
287 assert.equal(req.url, 'http://example.com/blog/post/1');
291 router.use('/blog', function (req, res, next) {
292 assert.equal(req.hit++, 1);
293 assert.equal(req.url, 'http://example.com/post/1');
297 router.handle(request, {}, function (err) {
298 if (err) return done(err);
299 assert.equal(request.hit, 2);
304 it('should adjust FQDN req.url with multiple routed handlers', function (done) {
305 var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
306 var router = new Router();
308 router.use('/blog', function (req, res, next) {
309 assert.equal(req.hit++, 0);
310 assert.equal(req.url, 'http://example.com/post/1');
314 router.use('/blog', function (req, res, next) {
315 assert.equal(req.hit++, 1);
316 assert.equal(req.url, 'http://example.com/post/1');
320 router.use(function (req, res, next) {
321 assert.equal(req.hit++, 2);
322 assert.equal(req.url, 'http://example.com/blog/post/1');
326 router.handle(request, {}, function (err) {
327 if (err) return done(err);
328 assert.equal(request.hit, 3);
334 describe('.all', function() {
335 it('should support using .all to capture all http verbs', function(done){
336 var router = new Router();
339 router.all('/foo', function(){ count++; });
341 var url = '/foo?bar=baz';
343 methods.forEach(function testMethod(method) {
344 router.handle({ url: url, method: method }, {}, function() {});
347 assert.equal(count, methods.length);
351 it('should be called for any URL when "*"', function (done) {
352 var cb = after(4, done)
353 var router = new Router()
356 throw new Error('should not be called')
359 router.all('*', function (req, res) {
363 router.handle({ url: '/', method: 'GET' }, { end: cb }, no)
364 router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no)
365 router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no)
366 router.handle({ url: '*', method: 'GET' }, { end: cb }, no)
370 describe('.use', function() {
371 it('should require middleware', function () {
372 var router = new Router()
373 assert.throws(function () { router.use('/') }, /requires a middleware function/)
376 it('should reject string as middleware', function () {
377 var router = new Router()
378 assert.throws(function () { router.use('/', 'foo') }, /requires a middleware function but got a string/)
381 it('should reject number as middleware', function () {
382 var router = new Router()
383 assert.throws(function () { router.use('/', 42) }, /requires a middleware function but got a number/)
386 it('should reject null as middleware', function () {
387 var router = new Router()
388 assert.throws(function () { router.use('/', null) }, /requires a middleware function but got a Null/)
391 it('should reject Date as middleware', function () {
392 var router = new Router()
393 assert.throws(function () { router.use('/', new Date()) }, /requires a middleware function but got a Date/)
396 it('should be called for any URL', function (done) {
397 var cb = after(4, done)
398 var router = new Router()
401 throw new Error('should not be called')
404 router.use(function (req, res) {
408 router.handle({ url: '/', method: 'GET' }, { end: cb }, no)
409 router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no)
410 router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no)
411 router.handle({ url: '*', method: 'GET' }, { end: cb }, no)
414 it('should accept array of middleware', function(done){
416 var router = new Router();
418 function fn1(req, res, next){
419 assert.equal(++count, 1);
423 function fn2(req, res, next){
424 assert.equal(++count, 2);
428 router.use([fn1, fn2], function(req, res){
429 assert.equal(++count, 3);
433 router.handle({ url: '/foo', method: 'GET' }, {}, function(){});
437 describe('.param', function() {
438 it('should call param function when routing VERBS', function(done) {
439 var router = new Router();
441 router.param('id', function(req, res, next, id) {
442 assert.equal(id, '123');
446 router.get('/foo/:id/bar', function(req, res, next) {
447 assert.equal(req.params.id, '123');
451 router.handle({ url: '/foo/123/bar', method: 'get' }, {}, done);
454 it('should call param function when routing middleware', function(done) {
455 var router = new Router();
457 router.param('id', function(req, res, next, id) {
458 assert.equal(id, '123');
462 router.use('/foo/:id/bar', function(req, res, next) {
463 assert.equal(req.params.id, '123');
464 assert.equal(req.url, '/baz');
468 router.handle({ url: '/foo/123/bar/baz', method: 'get' }, {}, done);
471 it('should only call once per request', function(done) {
473 var req = { url: '/foo/bob/bar', method: 'get' };
474 var router = new Router();
475 var sub = new Router();
477 sub.get('/bar', function(req, res, next) {
481 router.param('user', function(req, res, next, user) {
487 router.use('/foo/:user/', new Router());
488 router.use('/foo/:user/', sub);
490 router.handle(req, {}, function(err) {
491 if (err) return done(err);
492 assert.equal(count, 1);
493 assert.equal(req.user, 'bob');
498 it('should call when values differ', function(done) {
500 var req = { url: '/foo/bob/bar', method: 'get' };
501 var router = new Router();
502 var sub = new Router();
504 sub.get('/bar', function(req, res, next) {
508 router.param('user', function(req, res, next, user) {
514 router.use('/foo/:user/', new Router());
515 router.use('/:user/bob/', sub);
517 router.handle(req, {}, function(err) {
518 if (err) return done(err);
519 assert.equal(count, 2);
520 assert.equal(req.user, 'foo');
526 describe('parallel requests', function() {
527 it('should not mix requests', function(done) {
528 var req1 = { url: '/foo/50/bar', method: 'get' };
529 var req2 = { url: '/foo/10/bar', method: 'get' };
530 var router = new Router();
531 var sub = new Router();
533 done = after(2, done);
535 sub.get('/bar', function(req, res, next) {
539 router.param('ms', function(req, res, next, ms) {
540 ms = parseInt(ms, 10);
542 setTimeout(next, ms);
545 router.use('/foo/:ms/', new Router());
546 router.use('/foo/:ms/', sub);
548 router.handle(req1, {}, function(err) {
550 assert.equal(req1.ms, 50);
551 assert.equal(req1.originalUrl, '/foo/50/bar');
555 router.handle(req2, {}, function(err) {
557 assert.equal(req2.ms, 10);
558 assert.equal(req2.originalUrl, '/foo/10/bar');