test/Router.js JAVASCRIPT 637 lines View on github.com → Search inside
1'use strict'23var after = require('after');4var express = require('../')5  , Router = express.Router6  , methods = require('../lib/utils').methods7  , assert = require('node:assert');89describe('Router', function () {10  it('should return a function with router methods', function () {11    var router = new Router();12    assert(typeof router === 'function')1314    assert(typeof router.get === 'function')15    assert(typeof router.handle === 'function')16    assert(typeof router.use === 'function')17  });1819  it('should support .use of other routers', function (done) {20    var router = new Router();21    var another = new Router();2223    another.get('/bar', function (req, res) {24      res.end();25    });26    router.use('/foo', another);2728    router.handle({ url: '/foo/bar', method: 'GET' }, { end: done }, function () { });29  });3031  it('should support dynamic routes', function (done) {32    var router = new Router();33    var another = new Router();3435    another.get('/:bar', function (req, res) {36      assert.strictEqual(req.params.bar, 'route')37      res.end();38    });39    router.use('/:foo', another);4041    router.handle({ url: '/test/route', method: 'GET' }, { end: done }, function () { });42  });4344  it('should handle blank URL', function (done) {45    var router = new Router();4647    router.use(function (req, res) {48      throw new Error('should not be called')49    });5051    router.handle({ url: '', method: 'GET' }, {}, done);52  });5354  it('should handle missing URL', function (done) {55    var router = new Router()5657    router.use(function (req, res) {58      throw new Error('should not be called')59    })6061    router.handle({ method: 'GET' }, {}, done)62  })6364  it('handle missing method', function (done) {65    var all = false66    var router = new Router()67    var route = router.route('/foo')68    var use = false6970    route.post(function (req, res, next) { next(new Error('should not run')) })71    route.all(function (req, res, next) {72      all = true73      next()74    })75    route.get(function (req, res, next) { next(new Error('should not run')) })7677    router.get('/foo', function (req, res, next) { next(new Error('should not run')) })78    router.use(function (req, res, next) {79      use = true80      next()81    })8283    router.handle({ url: '/foo' }, {}, function (err) {84      if (err) return done(err)85      assert.ok(all)86      assert.ok(use)87      done()88    })89  })9091  it('should not stack overflow with many registered routes', function (done) {92    this.timeout(5000) // long-running test9394    var handler = function (req, res) { res.end(new Error('wrong handler')) };95    var router = new Router();9697    for (var i = 0; i < 6000; i++) {98      router.get('/thing' + i, handler)99    }100101    router.get('/', function (req, res) {102      res.end();103    });104105    router.handle({ url: '/', method: 'GET' }, { end: done }, function () { });106  });107108  it('should not stack overflow with a large sync route stack', function (done) {109    this.timeout(5000) // long-running test110111    var router = new Router()112113    router.get('/foo', function (req, res, next) {114      req.counter = 0115      next()116    })117118    for (var i = 0; i < 6000; i++) {119      router.get('/foo', function (req, res, next) {120        req.counter++121        next()122      })123    }124125    router.get('/foo', function (req, res) {126      assert.strictEqual(req.counter, 6000)127      res.end()128    })129130    router.handle({ url: '/foo', method: 'GET' }, { end: done }, function (err) {131      assert(!err, err);132    });133  })134135  it('should not stack overflow with a large sync middleware stack', function (done) {136    this.timeout(5000) // long-running test137138    var router = new Router()139140    router.use(function (req, res, next) {141      req.counter = 0142      next()143    })144145    for (var i = 0; i < 6000; i++) {146      router.use(function (req, res, next) {147        req.counter++148        next()149      })150    }151152    router.use(function (req, res) {153      assert.strictEqual(req.counter, 6000)154      res.end()155    })156157    router.handle({ url: '/', method: 'GET' }, { end: done }, function (err) {158      assert(!err, err);159    })160  })161162  describe('.handle', function () {163    it('should dispatch', function (done) {164      var router = new Router();165166      router.route('/foo').get(function (req, res) {167        res.send('foo');168      });169170      var res = {171        send: function (val) {172          assert.strictEqual(val, 'foo')173          done();174        }175      }176      router.handle({ url: '/foo', method: 'GET' }, res, function () { });177    })178  })179180  describe('.multiple callbacks', function () {181    it('should throw if a callback is null', function () {182      assert.throws(function () {183        var router = new Router();184        router.route('/foo').all(null);185      })186    })187188    it('should throw if a callback is undefined', function () {189      assert.throws(function () {190        var router = new Router();191        router.route('/foo').all(undefined);192      })193    })194195    it('should throw if a callback is not a function', function () {196      assert.throws(function () {197        var router = new Router();198        router.route('/foo').all('not a function');199      })200    })201202    it('should not throw if all callbacks are functions', function () {203      var router = new Router();204      router.route('/foo').all(function () { }).all(function () { });205    })206  })207208  describe('error', function () {209    it('should skip non error middleware', function (done) {210      var router = new Router();211212      router.get('/foo', function (req, res, next) {213        next(new Error('foo'));214      });215216      router.get('/bar', function (req, res, next) {217        next(new Error('bar'));218      });219220      router.use(function (req, res, next) {221        assert(false);222      });223224      router.use(function (err, req, res, next) {225        assert.equal(err.message, 'foo');226        done();227      });228229      router.handle({ url: '/foo', method: 'GET' }, {}, done);230    });231232    it('should handle throwing inside routes with params', function (done) {233      var router = new Router();234235      router.get('/foo/:id', function () {236        throw new Error('foo');237      });238239      router.use(function (req, res, next) {240        assert(false);241      });242243      router.use(function (err, req, res, next) {244        assert.equal(err.message, 'foo');245        done();246      });247248      router.handle({ url: '/foo/2', method: 'GET' }, {}, function () { });249    });250251    it('should handle throwing in handler after async param', function (done) {252      var router = new Router();253254      router.param('user', function (req, res, next, val) {255        process.nextTick(function () {256          req.user = val;257          next();258        });259      });260261      router.use('/:user', function (req, res, next) {262        throw new Error('oh no!');263      });264265      router.use(function (err, req, res, next) {266        assert.equal(err.message, 'oh no!');267        done();268      });269270      router.handle({ url: '/bob', method: 'GET' }, {}, function () { });271    });272273    it('should handle throwing inside error handlers', function (done) {274      var router = new Router();275276      router.use(function (req, res, next) {277        throw new Error('boom!');278      });279280      router.use(function (err, req, res, next) {281        throw new Error('oops');282      });283284      router.use(function (err, req, res, next) {285        assert.equal(err.message, 'oops');286        done();287      });288289      router.handle({ url: '/', method: 'GET' }, {}, done);290    });291  })292293  describe('FQDN', function () {294    it('should not obscure FQDNs', function (done) {295      var request = { hit: 0, url: 'http://example.com/foo', method: 'GET' };296      var router = new Router();297298      router.use(function (req, res, next) {299        assert.equal(req.hit++, 0);300        assert.equal(req.url, 'http://example.com/foo');301        next();302      });303304      router.handle(request, {}, function (err) {305        if (err) return done(err);306        assert.equal(request.hit, 1);307        done();308      });309    });310311    it('should ignore FQDN in search', function (done) {312      var request = { hit: 0, url: '/proxy?url=http://example.com/blog/post/1', method: 'GET' };313      var router = new Router();314315      router.use('/proxy', function (req, res, next) {316        assert.equal(req.hit++, 0);317        assert.equal(req.url, '/?url=http://example.com/blog/post/1');318        next();319      });320321      router.handle(request, {}, function (err) {322        if (err) return done(err);323        assert.equal(request.hit, 1);324        done();325      });326    });327328    it('should ignore FQDN in path', function (done) {329      var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' };330      var router = new Router();331332      router.use('/proxy', function (req, res, next) {333        assert.equal(req.hit++, 0);334        assert.equal(req.url, '/http://example.com/blog/post/1');335        next();336      });337338      router.handle(request, {}, function (err) {339        if (err) return done(err);340        assert.equal(request.hit, 1);341        done();342      });343    });344345    it('should adjust FQDN req.url', function (done) {346      var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };347      var router = new Router();348349      router.use('/blog', function (req, res, next) {350        assert.equal(req.hit++, 0);351        assert.equal(req.url, 'http://example.com/post/1');352        next();353      });354355      router.handle(request, {}, function (err) {356        if (err) return done(err);357        assert.equal(request.hit, 1);358        done();359      });360    });361362    it('should adjust FQDN req.url with multiple handlers', function (done) {363      var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };364      var router = new Router();365366      router.use(function (req, res, next) {367        assert.equal(req.hit++, 0);368        assert.equal(req.url, 'http://example.com/blog/post/1');369        next();370      });371372      router.use('/blog', function (req, res, next) {373        assert.equal(req.hit++, 1);374        assert.equal(req.url, 'http://example.com/post/1');375        next();376      });377378      router.handle(request, {}, function (err) {379        if (err) return done(err);380        assert.equal(request.hit, 2);381        done();382      });383    });384385    it('should adjust FQDN req.url with multiple routed handlers', function (done) {386      var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };387      var router = new Router();388389      router.use('/blog', function (req, res, next) {390        assert.equal(req.hit++, 0);391        assert.equal(req.url, 'http://example.com/post/1');392        next();393      });394395      router.use('/blog', function (req, res, next) {396        assert.equal(req.hit++, 1);397        assert.equal(req.url, 'http://example.com/post/1');398        next();399      });400401      router.use(function (req, res, next) {402        assert.equal(req.hit++, 2);403        assert.equal(req.url, 'http://example.com/blog/post/1');404        next();405      });406407      router.handle(request, {}, function (err) {408        if (err) return done(err);409        assert.equal(request.hit, 3);410        done();411      });412    });413  })414415  describe('.all', function () {416    it('should support using .all to capture all http verbs', function (done) {417      var router = new Router();418419      var count = 0;420      router.all('/foo', function () { count++; });421422      var url = '/foo?bar=baz';423424      methods.forEach(function testMethod(method) {425        router.handle({ url: url, method: method }, {}, function () { });426      });427428      assert.equal(count, methods.length);429      done();430    })431  })432433  describe('.use', function () {434    it('should require middleware', function () {435      var router = new Router()436      assert.throws(function () { router.use('/') }, /argument handler is required/)437    })438439    it('should reject string as middleware', function () {440      var router = new Router()441      assert.throws(function () { router.use('/', 'foo') }, /argument handler must be a function/)442    })443444    it('should reject number as middleware', function () {445      var router = new Router()446      assert.throws(function () { router.use('/', 42) }, /argument handler must be a function/)447    })448449    it('should reject null as middleware', function () {450      var router = new Router()451      assert.throws(function () { router.use('/', null) }, /argument handler must be a function/)452    })453454    it('should reject Date as middleware', function () {455      var router = new Router()456      assert.throws(function () { router.use('/', new Date()) }, /argument handler must be a function/)457    })458459    it('should be called for any URL', function (done) {460      var cb = after(4, done)461      var router = new Router()462463      function no() {464        throw new Error('should not be called')465      }466467      router.use(function (req, res) {468        res.end()469      })470471      router.handle({ url: '/', method: 'GET' }, { end: cb }, no)472      router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no)473      router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no)474      router.handle({ url: '*', method: 'GET' }, { end: cb }, no)475    })476477    it('should accept array of middleware', function (done) {478      var count = 0;479      var router = new Router();480481      function fn1(req, res, next) {482        assert.equal(++count, 1);483        next();484      }485486      function fn2(req, res, next) {487        assert.equal(++count, 2);488        next();489      }490491      router.use([fn1, fn2], function (req, res) {492        assert.equal(++count, 3);493        done();494      });495496      router.handle({ url: '/foo', method: 'GET' }, {}, function () { });497    })498  })499500  describe('.param', function () {501    it('should require function', function () {502      var router = new Router();503      assert.throws(router.param.bind(router, 'id'), /argument fn is required/);504    });505506    it('should reject non-function', function () {507      var router = new Router();508      assert.throws(router.param.bind(router, 'id', 42), /argument fn must be a function/);509    });510511    it('should call param function when routing VERBS', function (done) {512      var router = new Router();513514      router.param('id', function (req, res, next, id) {515        assert.equal(id, '123');516        next();517      });518519      router.get('/foo/:id/bar', function (req, res, next) {520        assert.equal(req.params.id, '123');521        next();522      });523524      router.handle({ url: '/foo/123/bar', method: 'get' }, {}, done);525    });526527    it('should call param function when routing middleware', function (done) {528      var router = new Router();529530      router.param('id', function (req, res, next, id) {531        assert.equal(id, '123');532        next();533      });534535      router.use('/foo/:id/bar', function (req, res, next) {536        assert.equal(req.params.id, '123');537        assert.equal(req.url, '/baz');538        next();539      });540541      router.handle({ url: '/foo/123/bar/baz', method: 'get' }, {}, done);542    });543544    it('should only call once per request', function (done) {545      var count = 0;546      var req = { url: '/foo/bob/bar', method: 'get' };547      var router = new Router();548      var sub = new Router();549550      sub.get('/bar', function (req, res, next) {551        next();552      });553554      router.param('user', function (req, res, next, user) {555        count++;556        req.user = user;557        next();558      });559560      router.use('/foo/:user/', new Router());561      router.use('/foo/:user/', sub);562563      router.handle(req, {}, function (err) {564        if (err) return done(err);565        assert.equal(count, 1);566        assert.equal(req.user, 'bob');567        done();568      });569    });570571    it('should call when values differ', function (done) {572      var count = 0;573      var req = { url: '/foo/bob/bar', method: 'get' };574      var router = new Router();575      var sub = new Router();576577      sub.get('/bar', function (req, res, next) {578        next();579      });580581      router.param('user', function (req, res, next, user) {582        count++;583        req.user = user;584        next();585      });586587      router.use('/foo/:user/', new Router());588      router.use('/:user/bob/', sub);589590      router.handle(req, {}, function (err) {591        if (err) return done(err);592        assert.equal(count, 2);593        assert.equal(req.user, 'foo');594        done();595      });596    });597  });598599  describe('parallel requests', function () {600    it('should not mix requests', function (done) {601      var req1 = { url: '/foo/50/bar', method: 'get' };602      var req2 = { url: '/foo/10/bar', method: 'get' };603      var router = new Router();604      var sub = new Router();605      var cb = after(2, done)606607608      sub.get('/bar', function (req, res, next) {609        next();610      });611612      router.param('ms', function (req, res, next, ms) {613        ms = parseInt(ms, 10);614        req.ms = ms;615        setTimeout(next, ms);616      });617618      router.use('/foo/:ms/', new Router());619      router.use('/foo/:ms/', sub);620621      router.handle(req1, {}, function (err) {622        assert.ifError(err);623        assert.equal(req1.ms, 50);624        assert.equal(req1.originalUrl, '/foo/50/bar');625        cb()626      });627628      router.handle(req2, {}, function (err) {629        assert.ifError(err);630        assert.equal(req2.ms, 10);631        assert.equal(req2.originalUrl, '/foo/10/bar');632        cb()633      });634    });635  });636})

Code quality findings 83

Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var after = require('after');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var express = require('../')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
assert(typeof router === 'function')
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
assert(typeof router === 'function')
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
assert(typeof router.get === 'function')
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
assert(typeof router.get === 'function')
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
assert(typeof router.handle === 'function')
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
assert(typeof router.handle === 'function')
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
assert(typeof router.use === 'function')
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
assert(typeof router.use === 'function')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var another = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var another = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var all = false
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var route = router.route('/foo')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var use = false
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var handler = function (req, res) { res.end(new Error('wrong handler')) };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < 6000; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < 6000; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < 6000; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < 6000; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < 6000; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < 6000; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var res = {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: 'http://example.com/foo', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: '/proxy?url=http://example.com/blog/post/1', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var count = 0;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var url = '/foo?bar=baz';
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var cb = after(4, done)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router()
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var count = 0;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var count = 0;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = { url: '/foo/bob/bar', method: 'get' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var sub = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var count = 0;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = { url: '/foo/bob/bar', method: 'get' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var sub = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req1 = { url: '/foo/50/bar', method: 'get' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req2 = { url: '/foo/10/bar', method: 'get' };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var router = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var sub = new Router();
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var cb = after(2, done)
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
setTimeout(next, ms);

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.