From 13a634dcdb167a673a0f2f192d6682dab5ea9fa0 Mon Sep 17 00:00:00 2001 From: Malcolm Date: Mon, 4 Jul 2022 18:29:16 +1200 Subject: [PATCH] Support symbols as route names (#143) * Test symbols as route names and related error handling * Better support for symbols as route names, and add error handling for router.redirect --- lib/router.js | 15 ++++++++--- test/lib/router.js | 63 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/lib/router.js b/lib/router.js index e84f6a7..d9e3a33 100644 --- a/lib/router.js +++ b/lib/router.js @@ -540,10 +540,19 @@ Router.prototype.all = function (name, path, middleware) { Router.prototype.redirect = function (source, destination, code) { // lookup source route by name - if (source[0] !== '/') source = this.url(source); + if (typeof source === 'symbol' || source[0] !== '/') { + source = this.url(source); + if (source instanceof Error) throw source; + } // lookup destination route by name - if (destination[0] !== '/' && !destination.includes('://')) destination = this.url(destination); + if ( + typeof destination === 'symbol' || + destination[0] !== '/' && !destination.includes('://') + ) { + destination = this.url(destination); + if (destination instanceof Error) throw destination; + } return this.all(source, ctx => { ctx.redirect(destination); @@ -662,7 +671,7 @@ Router.prototype.url = function (name, params) { return route.url.apply(route, args); } - return new Error(`No route found for name: ${name}`); + return new Error(`No route found for name: ${String(name)}`); }; /** diff --git a/test/lib/router.js b/test/lib/router.js index f21c0ea..cb17b57 100644 --- a/test/lib/router.js +++ b/test/lib/router.js @@ -1331,6 +1331,33 @@ describe('Router', function () { }); }); + it('redirects using symbols as route names', function (done) { + const app = new Koa(); + const router = new Router(); + app.use(router.routes()); + const homeSymbol = Symbol('home'); + const signUpFormSymbol = Symbol('sign-up-form'); + router.get(homeSymbol, '/', function () { }); + router.get(signUpFormSymbol, '/sign-up-form', function () { }); + router.redirect(homeSymbol, signUpFormSymbol); + request(http.createServer(app.callback())) + .post('/') + .expect(301) + .end(function (err, res) { + if (err) return done(err); + res.header.should.have.property('location', '/sign-up-form'); + done(); + }); + }); + + it('throws an error if no route is found for name', function () { + const router = new Router(); + expect(() => router.redirect('missing', '/destination')).to.throwError(); + expect(() => router.redirect('/source', 'missing')).to.throwError(); + expect(() => router.redirect(Symbol('missing'), '/destination')).to.throwError(); + expect(() => router.redirect('/source', Symbol('missing'))).to.throwError(); + }); + it('redirects to external sites', function (done) { const app = new Koa(); const router = new Router(); @@ -1371,10 +1398,26 @@ describe('Router', function () { expect(router.route('child')).to.have.property('name', 'child'); }); - it('should return false if no name matches', function () { - const value = Router().route('Picard') - value.should.be.false() - }) + it('supports symbols as names', function () { + const childSymbol = Symbol('child'); + const subrouter = Router().get(childSymbol, '/hello', function (ctx) { + ctx.body = { hello: 'world' }; + }); + const router = Router().use(subrouter.routes()); + expect(router.route(childSymbol)).to.have.property('name', childSymbol); + }); + + it('returns false if no name matches', function () { + const router = new Router(); + router.get('books', '/books', function (ctx) { + ctx.status = 204; + }); + router.get(Symbol('Picard'), '/enterprise', function (ctx) { + ctx.status = 204; + }); + router.route('Picard').should.be.false(); + router.route(Symbol('books')).should.be.false(); + }); }); describe('Router#url()', function () { @@ -1510,17 +1553,19 @@ describe('Router', function () { done(); }) - it("should test Error flow if no route is found for name", function () { + it('returns an Error if no route is found for name', function () { const app = new Koa(); const router = new Router(); app.use(router.routes()); - router.get("books", "/:category/:title", function (ctx) { + router.get('books', '/books', function (ctx) { + ctx.status = 204; + }); + router.get(Symbol('Picard'), '/enterprise', function (ctx) { ctx.status = 204; }); - router - .url("Picard", "Enterprise") - .should.Error(); + router.url('Picard').should.be.Error(); + router.url(Symbol('books')).should.be.Error(); }); });