UNPKG

cloudflare-worker-router-typescript

Version:

Cloudflare Worker Router Typescript is a lightweight Express-like router library for Cloudflare Workers including service workers, modules, and Durable Objects

186 lines (157 loc) 6.47 kB
import * as testing from 'start-testing' import { chaiAssert } from 'start-testing/dist/extra/testUtils.js' import { bodyParser } from './middleware/bodyParser.js' import { queryParser } from './middleware/queryParser.js' import { Route, Router } from './router.js' import { RouterHandler, RouterRequest, RouterResponse } from './types.js' type TestResponse = { pathname: string method: string body: any } type HandlerRegister = (url: string, ...handlers: RouterHandler[]) => void type HandlerRegisterFactory = (router: Router) => HandlerRegister export async function testHttpMethodHandlers(t: testing.Context) { const tests: { method: keyof Router, register: HandlerRegisterFactory, body?: any }[] = [ // { method: 'connect', register: r => r.connect }, { method: 'delete', register: r => r.delete }, { method: 'get', register: r => r.get }, { method: 'head', register: r => r.head }, { method: 'options', register: r => r.options }, // { method: 'patch', register: r => r.patch }, { method: 'post', register: r => r.post }, { method: 'put', register: r => r.put }, // { method: 'trace', register: r => r.trace }, // { method: 'any', register: r => r.any } ] await Promise.all(tests.map(async test => { t.run(test.method, async (t) => { const assert = chaiAssert(t) const router = new Router() const register: HandlerRegister = test.register(router).bind(router) register(`/${test.method}`, async (req: RouterRequest, res: RouterResponse) => { const { pathname } = new URL(req.request.url) const method = req.method.toLowerCase() res.status = 200 res.body = { pathname, method, } }) const req = new Request(`http://127.0.0.1/${test.method}`, { method: test.method.toUpperCase(), }) const res = await router.handle(req) assert.equal(res.status, 200) const body = await res.json<TestResponse>() assert.equal(body.pathname, `/${test.method}`) assert.equal(body.method, test.method) if (test.body) { assert.deepEqual(body.body, test.body) } }) })) } export async function testMiddlewareBodyParser(t: testing.Context) { const assert = chaiAssert(t) const router = new Router() router.use(bodyParser) router.post('/middleware', async (req, res) => { assert.deepEqual(req.body, { foo: 'bar' }) res.status = 200 }) const req = new Request(`http://127.0.0.1/middleware`, { method: 'post', headers: new Headers({ 'Content-Type': 'application/json' }), body: JSON.stringify({ foo: 'bar' }) }) const res = await router.handle(req) assert.equal(res.status, 200) } export async function testMiddlewareQueryParser(t: testing.Context) { const assert = chaiAssert(t) const router = new Router() router.use(queryParser) router.post('/middleware', async (req, res) => { assert.equal(req.query.foo, 'bar') res.status = 200 }) const req = new Request(`http://127.0.0.1/middleware?foo=bar`, { method: 'post' }) const res = await router.handle(req) assert.equal(res.status, 200) } export async function testCustomMiddleware(t: testing.Context) { const tests = [ { name: 'fail', headers: null, expectedCode: 403 }, { name: 'pass', headers: { 'X-Auth-Token': 'secret' }, expectedCode: 200 } ] await Promise.all(tests.map((test) => { return t.run(test.name, async t => { const assert = chaiAssert(t) const router = new Router() router.use(async (req, res, next) => { const token = req.headers.get('X-Auth-Token') if (token !== "secret") { res.status = 403 res.body = 'no token' return } await next() }) router.get('/secrets', (req, res) => { res.body = { foo: 'bar' } res.status = 200 }) const req = new Request(`http://127.0.0.1/secrets`, { method: 'get', headers: new Headers(test.headers || {}) }) const res = await router.handle(req) assert.equal(res.status, test.expectedCode) }) })) } export async function testRouteMatch(t: testing.Context) { const tests = [ { method: 'delete', route: '/foo/:id', path: '/foo/bar', pass: true, params: { id: 'bar' } }, { method: 'get', route: '/foo/:id', path: '/foo/bar', pass: true, params: { id: 'bar' } }, { method: 'head', route: '/foo/:id', path: '/foo/bar', pass: true, params: { id: 'bar' } }, { method: 'options', route: '/foo/:id', path: '/foo/bar', pass: true, params: { id: 'bar' } }, { method: 'post', route: '/foo/:id', path: '/foo/bar', pass: true, params: { id: 'bar' } }, { method: 'get', route: '/foo/:id', path: '/foo/bar/baz', pass: false, params: {} }, ] await Promise.all(tests.map(async test => { const name = `${test.method} ${test.path}` return t.run(name, async t => { const assert = chaiAssert(t) const route = new Route(test.method, test.route, []) try { const params = route.match({ request: new Request(`http://127.0.0.1:8787${test.path}`, { method: test.method }), method: test.method, params: {}, query: {}, headers: new Headers({}), body: null }) as any assert.deepEqual(params, test.params) } catch(e) { if (test.pass) { t.error('should not be in catch block') t.log(e) return } else if (e instanceof Error) { assert.include(e.message, 'url pattern doesn\'t match') return } throw e } }) })) }