diff options
author | EuAndreh <eu@euandre.org> | 2024-02-23 14:40:24 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-02-23 14:40:24 -0300 |
commit | 21be0bfc48d73beb9860a47d28b5b16b9c2a29b8 (patch) | |
tree | 17eccfccb7c5d54d65f6c133cd3585f983175c95 /tests/js/hero.mjs | |
parent | Implement accretion.runMigrations() and wrappings of node-sqlite3 (diff) | |
download | papod-21be0bfc48d73beb9860a47d28b5b16b9c2a29b8.tar.gz papod-21be0bfc48d73beb9860a47d28b5b16b9c2a29b8.tar.xz |
src/hero.mjs: Add buildServer()
Diffstat (limited to 'tests/js/hero.mjs')
-rw-r--r-- | tests/js/hero.mjs | 346 |
1 files changed, 249 insertions, 97 deletions
diff --git a/tests/js/hero.mjs b/tests/js/hero.mjs index 09e6e54..7b8a5cc 100644 --- a/tests/js/hero.mjs +++ b/tests/js/hero.mjs @@ -1,4 +1,6 @@ import assert from "node:assert/strict"; +import http from "node:http"; + import { runTests } from "../runner.mjs"; import { assocIn } from "../../src/utils.mjs"; import { @@ -6,7 +8,6 @@ import { pathToSegments, hasPathParams, addRoute, - buildRoutes, findStaticHandler, firstParamMatch, findDynamicHandler, @@ -15,8 +16,12 @@ import { handleRequest, makeRequestListener, interceptorsFn, + interceptors, chainInterceptors, wrapHandler, + buildRoutes, + promisifyServer, + buildServer, } from "../../src/hero.mjs"; @@ -167,101 +172,6 @@ const test_addRoute = t => { }); }; -const test_buildRoutes = t => { - t.start("buildRoutes()"); - - t.test("empty values", () => { - assert.deepEqual(buildRoutes([]), {}); - }); - - t.test("overwrites", () => { - const fn1 = () => {}; - const fn2 = () => {}; - - const r1 = [ [ "GET", "/", fn1 ] ]; - const r2 = [ [ "GET", "/", fn2 ] ]; - - assert.deepEqual( - buildRoutes(r1), - { - static: { - GET: { - "": fn1, - }, - }, - }, - ); - - assert.deepEqual( - buildRoutes(r2), - { - static: { - GET: { - "": fn2, - }, - }, - }, - ); - - assert.deepEqual( - buildRoutes(r1.concat(r2)), - buildRoutes(r2), - ); - - assert.deepEqual( - buildRoutes(r2.concat(r1)), - buildRoutes(r1), - ); - }); - - t.test("multiple routes built", () => { - const fn1 = () => {}; - const fn2 = () => {}; - const fn3 = () => {}; - const fn4 = () => {}; - const fn5 = () => {}; - - const routes = [ - [ "GET", "/", fn1 ], - [ "GET", "/home", fn2 ], - [ "GET", "/user", fn3 ], - [ "POST", "/user", fn4 ], - [ "GET", "/user/:id", fn5 ], - ]; - - assert.deepEqual( - buildRoutes(routes), - { - static: { - GET: { - "": fn1, - home: { - "": fn2, - }, - user: { - "": fn3, - }, - }, - POST: { - user: { - "": fn4, - }, - }, - }, - dynamic: { - GET: { - user: { - ":id": { - "": fn5, - } - } - } - }, - }, - ); - }); -}; - const test_findStaticHandler = t => { t.start("findStaticHandler()"); @@ -400,6 +310,22 @@ const test_firstParamMatch = t => { { handlerFn: fn1, params: { aaa: "someId" }}, ); }); + + t.test(`we deal with segments that start with ":"`, () => { + const segments = [ "path", ":param", "" ]; + const tree = { + path: { + ":arg": { + "": fn1, + }, + }, + }; + + assert.deepEqual( + firstParamMatch(tree, segments, params), + { handlerFn: fn1, params: { arg: ":param" }}, + ); + }); }; const test_findDynamicHandler = t => { @@ -973,6 +899,15 @@ const test_chainInterceptors = t => { const test_wrapHandler = t => { t.start("wrapHandler()"); + t.test("noop when arr is empty", () => { + const fn = () => {}; + const wrappedFn1 = wrapHandler(fn, []); + assert.deepEqual(fn, wrappedFn1); + + const wrappedFn2 = wrapHandler(fn, [ interceptors.requestId ]); + assert.notDeepEqual(fn, wrappedFn2); + }); + t.test("a handler with chained interceptors change its behaviour", async () => { let i = 0; const uuidFn = () => `${i++}`; @@ -1030,13 +965,227 @@ const test_wrapHandler = t => { }); }; +const test_buildRoutes = t => { + t.start("buildRoutes()"); + + t.test("empty values", () => { + assert.deepEqual(buildRoutes([]), {}); + }); + + t.test("overwrites", () => { + const fn1 = () => {}; + const fn2 = () => {}; + + const r1 = [ [ "GET", "/", fn1 ] ]; + const r2 = [ [ "GET", "/", fn2 ] ]; + + assert.deepEqual( + buildRoutes(r1), + { + static: { + GET: { + "": fn1, + }, + }, + }, + ); + + assert.deepEqual( + buildRoutes(r2), + { + static: { + GET: { + "": fn2, + }, + }, + }, + ); + + assert.deepEqual( + buildRoutes(r1.concat(r2)), + buildRoutes(r2), + ); + + assert.deepEqual( + buildRoutes(r2.concat(r1)), + buildRoutes(r1), + ); + }); + + t.test("wrapped handler functions", async () => { + const handler = req => ({ ...req, handled: true }); + const interceptor = (req, next) => next({ ...req, intercepted: true }); + + const routes = [ + [ "GET", "/without", handler ], + [ "GET", "/with", handler, [ interceptor ] ], + ]; + + const table = buildRoutes(routes); + + { + const { handled, intercepted } = + await handleRequest(table, "GET", "/without"); + assert.deepEqual( + { handled, intercepted }, + { handled: true, intercepted: undefined }, + ); + } + { + const { handled, intercepted } = + await handleRequest(table, "GET", "/with"); + assert.deepEqual( + { handled, intercepted }, + { handled: true, intercepted: true }, + ); + } + }); + + t.test("interceptors are combined", async () => { + const handler = req => ({ ...req, handled: true }); + const interceptor1 = (req, next) => next({ ...req, interceptor1: true }); + const interceptor2 = (req, next) => next({ ...req, interceptor2: true }); + + const routes = [ + [ "GET", "/global-only", handler ], + [ "GET", "/global-and-local", handler, [ interceptor2 ] ], + ]; + + const table = buildRoutes(routes, [ interceptor1 ]); + + { + const { handled, interceptor1, interceptor2 } = + await handleRequest(table, "GET", "/global-only"); + assert.deepEqual( + { handled, interceptor1, interceptor2 }, + { handled: true, interceptor1: true, interceptor2: undefined }, + ); + } + { + const { handled, interceptor1, interceptor2 } = + await handleRequest(table, "GET", "/global-and-local"); + assert.deepEqual( + { handled, interceptor1, interceptor2 }, + { handled: true, interceptor1: true, interceptor2: true }, + ); + } + }); + + t.test("multiple routes built", () => { + const fn1 = () => {}; + const fn2 = () => {}; + const fn3 = () => {}; + const fn4 = () => {}; + const fn5 = () => {}; + + const routes = [ + [ "GET", "/", fn1 ], + [ "GET", "/home", fn2 ], + [ "GET", "/user", fn3 ], + [ "POST", "/user", fn4 ], + [ "GET", "/user/:id", fn5 ], + ]; + + assert.deepEqual( + buildRoutes(routes), + { + static: { + GET: { + "": fn1, + home: { + "": fn2, + }, + user: { + "": fn3, + }, + }, + POST: { + user: { + "": fn4, + }, + }, + }, + dynamic: { + GET: { + user: { + ":id": { + "": fn5, + } + } + } + }, + }, + ); + }); +}; + +const test_promisifyServer = t => { + t.start("promisifyServer()"); + + t.test("we can access the underlying server ref", () => { + const server = promisifyServer(http.createServer(() => {})); + assert.ok(server.ref instanceof http.Server); + }); +}; + +const test_buildServer = t => { + t.start("buildServer()"); + + const socketRequest = (socketPath, path) => + new Promise((resolve, reject) => { + const callback = res => { + let body = ""; + res.on("data", chunk => body += chunk); + res.on("error", reject); + res.on("end", () => resolve({ + body, + status: res.statusCode, + })); + }; + const request = http.request({ + socketPath, + path, + }, callback); + request.end(); + }); + + t.test("empty values", async () => { + const socketPath = "./tests/hero-0.sock"; + const server = buildServer([]); + + await server.listen(socketPath); + const response = await socketRequest(socketPath, "/anything"); + await server.close(); + + assert.deepEqual(response, { status: 404, body: "Not Found" }); + }); + + t.test("integrated application server", async () => { + const socketPath = "./tests/hero-1.sock"; + const pathHandler = req => ({ status: 200, body: "OK" }); + const globalInterceptors = [ + interceptors.serverError, + interceptors.contentType, + interceptors.requestId, + interceptors.logged, + ]; + const routes = [ [ "GET", "/path", pathHandler ] ]; + const server = buildServer(routes, globalInterceptors); + + await server.listen(socketPath); + const response = await socketRequest(socketPath, "/path"); + await server.close(); + + assert.deepEqual(response, { status: 200, body: "OK" }); + }); +}; + await runTests([ test_normalizeSegments, test_pathToSegments, test_hasPathParams, test_addRoute, - test_buildRoutes, test_findStaticHandler, test_firstParamMatch, test_findDynamicHandler, @@ -1047,4 +1196,7 @@ await runTests([ test_interceptorsFn, test_chainInterceptors, test_wrapHandler, + test_buildRoutes, + test_promisifyServer, + test_buildServer, ]); |