chore: update marked 17.0.5, add global error handler tests (TDD)
This commit is contained in:
parent
eea9489efc
commit
ab89085a0b
3 changed files with 130 additions and 5 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -12,7 +12,7 @@
|
|||
"express": "^5.1.0",
|
||||
"express-rate-limit": "^8.3.1",
|
||||
"helmet": "^8.1.0",
|
||||
"marked": "^17.0.4",
|
||||
"marked": "^17.0.5",
|
||||
"nanoid": "^5.1.6",
|
||||
"nodemailer": "^8.0.2",
|
||||
"pg": "^8.20.0",
|
||||
|
|
@ -3464,9 +3464,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "17.0.4",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz",
|
||||
"integrity": "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==",
|
||||
"version": "17.0.5",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-17.0.5.tgz",
|
||||
"integrity": "sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"express": "^5.1.0",
|
||||
"express-rate-limit": "^8.3.1",
|
||||
"helmet": "^8.1.0",
|
||||
"marked": "^17.0.4",
|
||||
"marked": "^17.0.5",
|
||||
"nanoid": "^5.1.6",
|
||||
"nodemailer": "^8.0.2",
|
||||
"pg": "^8.20.0",
|
||||
|
|
|
|||
125
src/__tests__/global-error-handler.test.ts
Normal file
125
src/__tests__/global-error-handler.test.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import express from "express";
|
||||
import request from "supertest";
|
||||
|
||||
let app: express.Express;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
|
||||
// Create a minimal test app that mimics the structure of the main app
|
||||
app = express();
|
||||
|
||||
// Add request ID middleware (used by error handler)
|
||||
app.use((req, _res, next) => {
|
||||
req.requestId = "test-request-id";
|
||||
next();
|
||||
});
|
||||
|
||||
// Add JSON parsing middleware
|
||||
app.use(express.json({ limit: "500kb" }));
|
||||
|
||||
// Add test routes that can throw errors
|
||||
app.post("/v1/convert/html", (_req, _res, next) => {
|
||||
const err = new Error("Test API error");
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get("/v1/test-error", (_req, _res, next) => {
|
||||
const err = new Error("Test V1 error");
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get("/health/test-error", (_req, _res, next) => {
|
||||
const err = new Error("Test health error");
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get("/non-api/test-error", (_req, _res, next) => {
|
||||
const err = new Error("Test non-API error");
|
||||
next(err);
|
||||
});
|
||||
|
||||
// Import and add the global error handler from index.ts
|
||||
// We need to copy the exact error handler logic
|
||||
app.use((err: unknown, req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
||||
const reqId = req.requestId || "unknown";
|
||||
|
||||
// Check if this is a JSON parse error from express.json()
|
||||
if (err instanceof SyntaxError && 'status' in err && (err as Record<string, unknown>).status === 400 && 'body' in err) {
|
||||
if (!res.headersSent) {
|
||||
res.status(400).json({ error: "Invalid JSON in request body" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.headersSent) {
|
||||
const isApi = req.path.startsWith("/v1/") || req.path.startsWith("/health");
|
||||
if (isApi) {
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
} else {
|
||||
res.status(500).send("Internal server error");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("global error handler", () => {
|
||||
it("returns 400 JSON response for invalid JSON body", async () => {
|
||||
const response = await request(app)
|
||||
.post("/v1/convert/html")
|
||||
.set("Content-Type", "application/json")
|
||||
.send("{ invalid json content")
|
||||
.expect(400);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
error: "Invalid JSON in request body"
|
||||
});
|
||||
expect(response.headers["content-type"]).toMatch(/application\/json/);
|
||||
});
|
||||
|
||||
it("returns 500 JSON response for errors on /v1/* API paths", async () => {
|
||||
const response = await request(app)
|
||||
.get("/v1/test-error")
|
||||
.expect(500);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
error: "Internal server error"
|
||||
});
|
||||
expect(response.headers["content-type"]).toMatch(/application\/json/);
|
||||
});
|
||||
|
||||
it("returns 500 JSON response for errors on /health API paths", async () => {
|
||||
const response = await request(app)
|
||||
.get("/health/test-error")
|
||||
.expect(500);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
error: "Internal server error"
|
||||
});
|
||||
expect(response.headers["content-type"]).toMatch(/application\/json/);
|
||||
});
|
||||
|
||||
it("returns 500 plain text response for errors on non-API paths", async () => {
|
||||
const response = await request(app)
|
||||
.get("/non-api/test-error")
|
||||
.expect(500);
|
||||
|
||||
expect(response.text).toBe("Internal server error");
|
||||
expect(response.headers["content-type"]).toMatch(/text\/html/);
|
||||
});
|
||||
|
||||
it("handles POST requests with valid JSON but route throws error (API path)", async () => {
|
||||
const response = await request(app)
|
||||
.post("/v1/convert/html")
|
||||
.set("Content-Type", "application/json")
|
||||
.send({ html: "<h1>Test</h1>" })
|
||||
.expect(500);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
error: "Internal server error"
|
||||
});
|
||||
expect(response.headers["content-type"]).toMatch(/application\/json/);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue