import assert from "node:assert/strict";
import http from "node:http";
import { runTests } from "../runner.mjs";
import { assocIn } from "../../src/utils.mjs";
import {
normalizeSegments,
pathToSegments,
hasPathParams,
addRoute,
findStaticHandler,
firstParamMatch,
findDynamicHandler,
findHandler,
extractQueryParams,
handleRequest,
makeRequestListener,
interceptorsFn,
interceptors,
chainInterceptors,
wrapHandler,
buildRoutes,
promisifyServer,
buildServer,
} from "../../src/hero.mjs";
const test_normalizeSegments = t => {
t.start("normalizeSegments()");
t.test("unchanged when already normalized", () => {
assert.deepEqual(normalizeSegments([""]), [""]);
});
t.test("empty terminator added when missing", () => {
assert.deepEqual(normalizeSegments([]), [""]);
assert.deepEqual(normalizeSegments([" "]), [" ", ""]);
assert.deepEqual(normalizeSegments(["_"]), ["_", ""]);
assert.deepEqual(normalizeSegments(["a"]), ["a", ""]);
assert.deepEqual(normalizeSegments([":a"]), [":a", ""]);
assert.deepEqual(normalizeSegments(["path"]), ["path", ""]);
});
};
const test_pathToSegments = t => {
t.start("pathToSegments()");
t.test("simple paths", () => {
assert.deepEqual(pathToSegments("/"), [ "" ]);
assert.deepEqual(pathToSegments("/simple"), ["simple", ""]);
assert.deepEqual(pathToSegments("/simple/route"), ["simple", "route", ""]);
assert.deepEqual(pathToSegments("/api/user/:id"), ["api", "user", ":id", ""]);
assert.deepEqual(pathToSegments("/api/user/:id/info"), ["api", "user", ":id", "info", ""]);
});
t.test("extra separators", () => {
assert.deepEqual(pathToSegments("/api/health/"), ["api", "health", ""]);
assert.deepEqual(pathToSegments("/api///health"), ["api", "health", ""]);
assert.deepEqual(pathToSegments("//api///health//"), ["api", "health", ""]);
});
};
const test_hasPathParams = t => {
t.start("hasPathParam()");
t.test("has it", () => {
assert(hasPathParams(["some", ":path", ""]));
assert(hasPathParams(["path", ":params", ""]));
assert(hasPathParams(["api", "user", ":id", "info", ""]));
});
t.test("doesn't have it", () => {
assert(!hasPathParams([]));
assert(!hasPathParams([ "" ]));
assert(!hasPathParams(["some", "path", ""]));
assert(!hasPathParams(["s:o:m:e:", "p::ath:::"]));
assert(!hasPathParams([" :"]));
});
};
const test_addRoute = t => {
t.start("addRoute()");
const fn1 = () => {};
t.test("daily usage examples", () => {
assert.deepEqual(
addRoute({}, "GET", "/home", fn1),
{ static: { GET: { home: { "": fn1 }}}},
);
assert.deepEqual(
addRoute({}, ["PUT", "POST", "PATCH"], "/api/user", fn1),
{
static: {
PUT: { api: { user: { "": fn1 }}},
POST: { api: { user: { "": fn1 }}},
PATCH: { api: { user: { "": fn1 }}},
},
},
);
assert.deepEqual(
addRoute({}, "*", "/settings", fn1),
{
static: {
GET: { settings: { "": fn1 }},
HEAD: { settings: { "": fn1 }},
POST: { settings: { "": fn1 }},
PUT: { settings: { "": fn1 }},
PATCH: { settings: { "": fn1 }},
DELETE: { settings: { "": fn1 }},
OPTIONS: { settings: { "": fn1 }},
},
},
);
assert.deepEqual(
addRoute({}, "GET", "/", fn1),
{ static: { GET: { "": fn1 }}},
);
assert.deepEqual(
addRoute({}, "GET", "/api/user/:id", fn1),
{ dynamic: { GET: { api: { user: { ":id": { "": fn1 }}}}}},
);
assert.deepEqual(
addRoute({}, ["PUT", "PATCH"], "/api/org/:orgid/member/:memberid", fn1),
{
dynamic: {
PUT: { api: { org: { ":orgid": { member: { ":memberid": { "": fn1 }}}}}},
PATCH: { api: { org: { ":orgid": { member: { ":memberid": { "": fn1 }}}}}},
},
},
);
});
t.test("bad method", () => {
assert.throws(
() => addRoute({}, "VERB", "/path", fn1),
assert.AssertionError,
);
});
t.test("empty methods array", () => {
assert.deepEqual(addRoute({}, [], "", fn1), {});
});
t.test("subpaths", () => {
const fn1 = () => {};
const fn2 = () => {};
const t1 = addRoute({}, "GET", "/home", fn1);
const t2 = addRoute(t1, "GET", "/home/details", fn2);
assert.deepEqual(
t2,
{
static: {
GET: {
home: {
"": fn1,
details: {
"": fn2,
},
},
},
},
},
);
});
};
const test_findStaticHandler = t => {
t.start("findStaticHandler()");
t.test("multiple accesses to the same table", () => {
const fn1 = () => {};
const fn2 = () => {};
const fn3 = () => {};
const table = {
static: {
GET: {
api: {
home: { "": fn1 },
settings: { "": fn2 },
},
},
POST: {
api: {
settings: { "": fn3 },
},
},
},
};
assert.deepEqual(
findStaticHandler(table, "GET", [ "api", "home", "" ]),
{ handlerFn: fn1, params: {} },
);
assert.deepEqual(
findStaticHandler(table, "PUT", [ "api", "home", "" ]),
null,
);
assert.deepEqual(
findStaticHandler(table, "GET", [ "api", "settings", "" ]),
{ handlerFn: fn2, params: {} },
);
assert.deepEqual(
findStaticHandler(table, "POST", [ "api", "settings", "" ]),
{ handlerFn: fn3, params: {} },
);
assert.deepEqual(
findStaticHandler(table, "PUT", [ "api", "settings", "" ]),
null,
);
assert.deepEqual(
findStaticHandler(table, "GET", [ "api", "profile", "" ]),
null,
);
assert.deepEqual(
findStaticHandler({}, "GET", [ "api", "profile", "" ]),
null,
);
});
};
const test_firstParamMatch = t => {
t.start("firstParamMatch()");
const params = {};
const fn1 = () => {};
const fn2 = () => {};
t.test("we BACKTRACK when searching down routes", () => {
const segments = [ "path", "split", "match", "" ];
const tree = {
path: {
split: {
MISMATCH: {
"": fn1,
},
},
":param": {
match: {
"": fn2,
},
},
},
};
assert.deepEqual(
firstParamMatch(tree, segments, params),
{ handlerFn: fn2, params: { param: "split" }},
);
});
t.test("ambiguous route prefers params at the end", () => {
const segments = [ "path", "param1", "param2", "" ];
const tree1 = {
path: {
":shallower": {
param2: {
"": fn2,
},
},
},
};
const tree2 = assocIn(tree1, [ "path", "param1", ":deeper", "" ], fn1);
assert.deepEqual(
firstParamMatch(tree1, segments, params),
{ handlerFn: fn2, params: { shallower: "param1" }},
);
assert.deepEqual(
firstParamMatch(tree2, segments, params),
{ handlerFn: fn1, params: { deeper: "param2" }},
);
});
t.test("when 2 params are possible, we pick the first alphabetically", () => {
const segments = [ "user", "someId", "" ];
const tree1 = {
user: {
":bbb": {
"": fn2,
},
},
};
const tree2 = assocIn(tree1, ["user", ":aaa", ""], fn1);
assert.deepEqual(
firstParamMatch(tree1, segments, params),
{ handlerFn: fn2, params: { bbb: "someId" }},
);
assert.deepEqual(
firstParamMatch(tree2, segments, params),
{ 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 => {
t.start("findDynamicHandler()");
t.test("daily usage cases", () => {
const fn1 = () => {};
const fn2 = () => {};
const table = {
dynamic: {
GET: {
users: {
"by-id": {
":id": { "": fn1 },
},
},
},
PUT: {
user: {
":user-id": {
info: { "": fn2 },
},
},
},
},
};
assert.deepEqual(
findDynamicHandler(table, "GET", [ "users", "by-id", "123", "" ]),
{ handlerFn: fn1, params: { "id": "123" }},
);
assert.deepEqual(
findDynamicHandler({}, "GET", [ "users", "by-id", "123", "" ]),
null,
);
assert.deepEqual(
findDynamicHandler({ dynamic: { GET: { "": fn1 }}}, "GET", [ "users", "by-id", "123", "" ]),
null,
);
assert.deepEqual(
findDynamicHandler(table, "PUT", [ "user", "deadbeef", "info", "" ]),
{ handlerFn: fn2, params: { "user-id": "deadbeef" }},
);
});
};
const test_findHandler = t => {
t.start("findHandler()");
t.test("mix of static and dynamic routes", () => {
const static1 = () => {};
const static2 = () => {};
const static3 = () => {};
const dynamic1 = () => {};
const dynamic2 = () => {};
const dynamic3 = () => {};
const dynamic4 = () => {};
const table = {
static: {
GET: {
user: {
"": static1,
},
pages: {
"": static2,
home: {
"": static3,
},
},
},
},
dynamic: {
GET: {
user: {
":id": {
"": dynamic1,
},
},
},
PUT: {
user: {
":id": {
"": dynamic2,
"info": {
"": dynamic3,
},
"preferences": {
"": dynamic4,
},
},
},
},
},
};
assert.deepEqual(
findHandler(table, "GET", "/"),
null,
);
assert.deepEqual(
findHandler(table, "GET", "/user/"),
{ handlerFn: static1, params: {} },
);
assert.deepEqual(
findHandler(table, "GET", "/pages"),
{ handlerFn: static2, params: {} },
);
assert.deepEqual(
findHandler(table, "GET", "/pages/home/"),
{ handlerFn: static3, params: {} },
);
assert.deepEqual(
findHandler(table, "GET", "/user/some-id"),
{ handlerFn: dynamic1, params: { id: "some-id" }},
);
assert.deepEqual(
findHandler(table, "GET", "/user/other-id/info"),
null,
);
assert.deepEqual(
findHandler(table, "PUT", "/user/other-id/info"),
{ handlerFn: dynamic3, params: { id: "other-id" }},
);
assert.deepEqual(
findHandler(table, "PUT", "/user/another-id/preferences"),
{ handlerFn: dynamic4, params: { id: "another-id" }},
);
assert.deepEqual(
findHandler(table, "POST", "/user/another-id/preferences"),
null,
);
});
};
const test_extractQueryParams = t => {
t.start("extractQueryParams()");
t.test("empty values", () => {
assert.deepEqual(extractQueryParams(), {});
assert.deepEqual(extractQueryParams(null), {});
assert.deepEqual(extractQueryParams(undefined), {});
});
t.test("we get a flat key-value strings", () => {
assert.deepEqual(
extractQueryParams("a[]=1&b=text&c=___"),
{
"a[]": "1",
b: "text",
c: "___",
},
);
});
t.test("duplicate values are suppressed, deterministically", () => {
assert.deepEqual(extractQueryParams("a=1&a=2&a=3"), { a: "3" });
assert.deepEqual(extractQueryParams("a=1&b=2&a=3"), { a: "3", b: "2" });
});
};
const test_handleRequest = t => {
t.start("handleRequest()");
const fn = req => req;
t.test("request without params", async () => {
const table = {
static: {
GET: {
"": fn,
},
},
};
assert.deepEqual(
await handleRequest(table, "GET", "/?q=1"),
{
params: {
path: {},
query: {
q: "1",
},
},
method: "GET",
path: "/",
handler: fn,
},
);
});
t.test("request with params", async () => {
const table = {
dynamic: {
PUT: {
api: {
user: {
":userId": {
"": fn,
},
},
},
},
},
};
assert.deepEqual(
await handleRequest(table, "PUT", "/api/user/2222"),
{
params: {
path: {
userId: "2222",
},
query: {},
},
method: "PUT",
path: "/api/user/2222",
handler: fn,
},
);
});
t.test("missing route", async () => {
assert.deepEqual(
await handleRequest({}, "GET", "/"),
{
status: 404,
body: "Not Found",
},
);
});
};
const test_makeRequestListener = t => {
t.start("makeRequestListener()");
t.test("straightforward body execution", async () => {
const fn = _ => ({
status: "test status",
body: "test body",
headers: "test headers",
});
const routes = [[ "GET", "/route1", fn ]];
const requestListener = makeRequestListener(buildRoutes(routes));
const req = {
method: "GET",
url: "/route1",
};
const heads = [];
const bodies = [];
const res = {
writeHead: (status, headers) => heads.push({ status, headers }),
end: body => bodies.push(body),
};
await requestListener(req, res);
assert.deepEqual(
heads,
[{
status: "test status",
headers: "test headers",
}],
);
assert.deepEqual(
bodies,
[ "test body" ],
);
});
t.test("we break if handleRequest() throws an error", async () => {
const fn = _ => { throw new Error("handler error"); };
const routes = [[ "GET", "/route2", fn ]];
const requestListener = makeRequestListener(buildRoutes(routes));
const req = {
method: "GET",
url: "/route2",
};
const heads = [];
const bodies = [];
const res = {
writeHead: (status, headers) => heads.push({ status, headers }),
end: body => bodies.push(body),
};
await assert.rejects(
async () => await requestListener(req, res),
{ message: "handler error" },
);
assert.deepEqual(heads, []);
assert.deepEqual(bodies, []);
});
};
const test_interceptorsFn = t => {
const next = x => x;
{
t.start("interceptorsFn().requestId()");
let i = 0;
const uuidFn = () => `${i++}`;
t.test("we add an id to whatever we receive", () => {
assert.deepEqual(
interceptorsFn({uuidFn}).requestId({}, next),
{
id: "0",
},
);
assert.deepEqual(
interceptorsFn({uuidFn}).requestId({ a: "existing data" }, next),
{
a: "existing data",
id: "1",
},
);
});
t.test(`we overwrite the "id" if it already exists`, async () => {
assert.deepEqual(
interceptorsFn({uuidFn}).requestId({ id: "before" }, next),
{
id: "2",
},
);
});
}
{
t.start("interceptorsFn().logged()");
t.test("we log before and after next()", async () => {
const contents = [];
const logger = x => contents.push(x);
const status = 201;
const req = {
id: "an ID",
url: "a URL",
method: "a method",
};
assert.deepEqual(
await interceptorsFn({logger}).logged(req, _ => ({ status })),
{ status },
);
assert.deepEqual(
contents,
[
{ ...req, type: "in-request" },
{ id: req.id, status, type: "in-response" },
],
);
});
}
{
t.start("interceptorsFn().contentType()");
t.test("empty values", async () => {
assert.deepEqual(
await interceptorsFn().contentType({}, next),
{
body: "",
headers: {
"Content-Type": "application/json",
"Content-Length": 0,
},
},
);
assert.deepEqual(
await interceptorsFn().contentType({ body: "" }, next),
{
body: "",
headers: {
"Content-Type": "text/html",
"Content-Length": 0,
},
},
);
});
t.test("body values", async () => {
assert.deepEqual(
await interceptorsFn().contentType({ body: { a: 1 }}, next),
{
body: `{"a":1}`,
headers: {
"Content-Type": "application/json",
"Content-Length": 7,
},
},
);
assert.deepEqual(
await interceptorsFn().contentType({ body: "
" }, next),
{
body: "
",
headers: {
"Content-Type": "text/html",
"Content-Length": 6,
},
},
);
});
t.test("header values preference", async () => {
assert.deepEqual(
await interceptorsFn().contentType({
body: "",
headers: {
"Content-Type": "we have preference",
"Content-Length": "and so do we",
},
}, next),
{
body: "",
headers: {
"Content-Type": "we have preference",
"Content-Length": "and so do we",
},
}
);
});
t.test("headers get propagated", async () => {
assert.deepEqual(
await interceptorsFn().contentType({
body: "",
headers: {
"My": "Header",
},
}, next),
{
body: "",
headers: {
"My": "Header",
"Content-Type": "text/html",
"Content-Length": 0,
},
},
);
});
}
{
t.start("interceptorsFn().serverError()");
t.test("no-op when no error occurs", async () => {
assert.deepEqual(
await interceptorsFn().serverError({ status: 1 }, next),
{ status: 1 },
);
});
t.test(`an error is thrown if "status" is missing`, async () => {
const contents = [];
const logger = x => contents.push(x);
assert.deepEqual(
await interceptorsFn({ logger }).serverError({ id: 123 }, next),
{
status: 500,
body: "Internal Server Error",
},
);
assert.deepEqual(
contents,
[{
id: 123,
type: "server-error-interceptor",
message: `Missing "status"`,
}],
);
});
t.test("we turn a handler error into a 500 response", async () => {
const contents = [];
const logger = x => contents.push(x);
assert.deepEqual(
await interceptorsFn({ logger }).serverError(
{ id: "some ID" },
_ => { throw new Error("My test error message"); },
),
{
status: 500,
body: "Internal Server Error",
},
);
assert.deepEqual(
contents,
[{
id: "some ID",
type: "server-error-interceptor",
message: "My test error message",
}],
);
});
}
};
const test_chainInterceptors = t => {
t.start("chainInterceptors()");
t.test("empty values", () => {
assert.equal(chainInterceptors([])("req"), "req");
});
t.test("the order of interceptors matter", () => {
const a = [];
const i1 = (req, next) => {
a.push("i1");
return next(req);
};
const i2 = (req, next) => {
a.push("i2");
return next(req);
};
assert.equal(chainInterceptors([i1, i2])("req"), "req");
assert.deepEqual(a, ["i1", "i2"]);
assert.equal(chainInterceptors([i2, i1])("req"), "req");
assert.deepEqual(a, ["i1", "i2", "i2", "i1"]);
});
t.test("with ordering, interceptors implicitly depend on each other", () => {
const i1 = (req, next) => next({ ...req, id: 1 });
const i2 = (req, next) => next({ ...req, id: req.id + 1 });
assert.deepEqual(
chainInterceptors([i1, i2])({}),
{ id: 2 },
);
assert.deepEqual(
chainInterceptors([i2])({}),
{ id: NaN },
);
assert.deepEqual(
chainInterceptors([i2, i1])({}),
{ id: 1 },
);
});
t.test("we can chain async interceptors", async () => {
const i1 = async (req, next) => await next({ ...req, i1: true });
const i2 = async (req, next) => await next({ ...req, i2: true });
assert.deepEqual(
await chainInterceptors([i1, i2])({}),
{
i1: true,
i2: true,
},
);
});
};
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++}`;
const contents = [];
const logger = x => contents.push(x);
const interceptors = interceptorsFn({uuidFn, logger});
const fn = async _ => await { status: 1, body: { a: 1 }};
const wrappedFn = wrapHandler(fn, [
interceptors.requestId,
interceptors.logged,
interceptors.contentType,
]);
const req = {
url: "URL",
method: "METHOD",
};
assert.deepEqual(
await fn(req),
{ status: 1, body: { a: 1 }},
);
assert.deepEqual(contents, []);
assert.deepEqual(
await wrappedFn(req),
{
status: 1,
body: `{"a":1}`,
headers: {
"Content-Type": "application/json",
"Content-Length": 7,
},
},
);
assert.deepEqual(
contents,
[
{
id: "0",
url: "URL",
method: "METHOD",
type: "in-request",
},
{
id: "0",
status: 1,
type: "in-response",
},
],
);
});
};
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_findStaticHandler,
test_firstParamMatch,
test_findDynamicHandler,
test_findHandler,
test_extractQueryParams,
test_handleRequest,
test_makeRequestListener,
test_interceptorsFn,
test_chainInterceptors,
test_wrapHandler,
test_buildRoutes,
test_promisifyServer,
test_buildServer,
]);