refactor: migrate from node:http to Express with Express.js tests
All checks were successful
/ checks (push) Successful in 9s
/ deploy (push) Successful in 7s

This commit is contained in:
Noah Holt 2026-08-10 23:03:21 -05:00
parent 6dd9c6e6ee
commit 1365bd7644
6 changed files with 2391 additions and 38 deletions

2323
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,8 +6,8 @@
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"test": "npm run build && node --test dist/index.test.js",
"start": "node dist/bin/server.js",
"test": "vitest run",
"lint": "eslint . && tsc --noEmit",
"format": "prettier --write .",
"format:check": "prettier --check ."
@ -15,13 +15,20 @@
"engines": {
"node": ">=22"
},
"dependencies": {
"express": "^5.2.0"
},
"devDependencies": {
"typescript": "^5.6.0",
"@types/node": "^22.0.0",
"eslint": "^9.13.0",
"typescript-eslint": "^8.15.0",
"prettier": "^3.3.3",
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0"
"@commitlint/config-conventional": "^19.5.0",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"@types/supertest": "^7.2.1",
"eslint": "^9.13.0",
"prettier": "^3.3.3",
"supertest": "^7.2.2",
"typescript": "^5.6.0",
"typescript-eslint": "^8.15.0",
"vitest": "^4.1.10"
}
}

5
src/bin/server.ts Normal file
View file

@ -0,0 +1,5 @@
import { app, port } from "../index.js";
app.listen(port, () => {
console.log(`demo-app listening on :${port}`);
});

View file

@ -1,7 +1,33 @@
import test from "node:test";
import assert from "node:assert/strict";
import { describe, it, expect } from "vitest";
import request from "supertest";
import { app } from "./index.js";
import { greeting } from "./greeting.js";
test("greeting mentions the homelab", () => {
assert.match(greeting(), /homelab/);
describe("greeting", () => {
it("mentions the homelab", () => {
expect(greeting()).toMatch(/homelab/);
});
});
describe("GET /healthz", () => {
it("returns 200 ok", async () => {
const res = await request(app).get("/healthz");
expect(res.status).toBe(200);
expect(res.text).toBe("ok");
expect(res.type).toBe("text/plain");
});
});
describe("GET /", () => {
it("returns service info", async () => {
const res = await request(app).get("/");
expect(res.status).toBe(200);
expect(res.body).toMatchObject({
service: "demo-app",
message: "Hello from the homelab pipeline!",
sha: expect.any(String),
pod: expect.any(String),
time: expect.any(String),
});
});
});

View file

@ -1,32 +1,23 @@
import { createServer } from "node:http";
import express from "express";
import { hostname } from "node:os";
import { greeting } from "./greeting.js";
const app = express();
const port = Number(process.env.PORT ?? 3000);
const sha = process.env.GIT_SHA ?? "dev";
const server = createServer((req, res) => {
if (req.url === "/healthz") {
res.writeHead(200, { "content-type": "text/plain" });
res.end("ok");
return;
}
res.writeHead(200, { "content-type": "application/json" });
res.end(
JSON.stringify(
{
service: "demo-app",
message: greeting(),
sha,
pod: hostname(),
time: new Date().toISOString(),
},
null,
2,
) + "\n",
);
app.get("/healthz", (_req, res) => {
res.type("text/plain").send("ok");
});
server.listen(port, () => {
console.log(`demo-app ${sha} listening on :${port}`);
app.get("/", (_req, res) => {
res.json({
service: "demo-app",
message: greeting(),
sha,
pod: hostname(),
time: new Date().toISOString(),
});
});
export { app, port };

7
vitest.config.ts Normal file
View file

@ -0,0 +1,7 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["src/**/*.test.ts"],
},
});