Use let or const to avoid scope issues and hoisting
var after = require('after');
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})
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.