add middleware tests

This commit is contained in:
Alex Holliday committed 2026-06-11 10:42:15 -07:00
1 parent a43363ebfc
commit ac77216f07
2 files changed
+80

No files matched your search

@@ -0,0 +1,38 @@
import { describe, expect, it, jest } from "@jest/globals";
import type { NextFunction, Request, Response } from "express";
import { MulterError } from "multer";
import { handleErrors } from "../../../src/api/middleware/handleErrors.ts";
import { AppError } from "../../../src/utils/AppError.ts";
const makeRes = (): Response => {
const res = {} as Response;
res.status = jest.fn().mockReturnValue(res) as unknown as Response["status"];
res.json = jest.fn().mockReturnValue(res) as unknown as Response["json"];
return res;
};
describe("handleErrors", () => {
it("maps a multer file-size violation to 413 Payload Too Large", () => {
const res = makeRes();
handleErrors(new MulterError("LIMIT_FILE_SIZE", "profileImage"), {} as Request, res, (() => {}) as NextFunction);
expect(res.status).toHaveBeenCalledWith(413);
});
it("maps other multer errors to 400", () => {
const res = makeRes();
handleErrors(new MulterError("LIMIT_UNEXPECTED_FILE", "profileImage"), {} as Request, res, (() => {}) as NextFunction);
expect(res.status).toHaveBeenCalledWith(400);
});
it("preserves AppError status codes", () => {
const res = makeRes();
handleErrors(new AppError({ status: 415, message: "bad image" }), {} as Request, res, (() => {}) as NextFunction);
expect(res.status).toHaveBeenCalledWith(415);
});
it("falls back to 500 for unknown errors", () => {
const res = makeRes();
handleErrors(new Error("boom"), {} as Request, res, (() => {}) as NextFunction);
expect(res.status).toHaveBeenCalledWith(500);
});
});
@@ -0,0 +1,42 @@
import { describe, expect, it } from "@jest/globals";
import type { Request } from "express";
import { imageUpload } from "../../../src/api/middleware/upload.ts";
import { MAX_IMAGE_SIZE_BYTES } from "../../../src/types/upload.ts";
import { AppError } from "../../../src/utils/AppError.ts";
// Reaches into the multer instance config to exercise the fileFilter/limits in isolation.
// Guards against regressing GHSA-9xvg-x28f-m78m (pre-auth DoS via unbounded uploads).
const config = (imageUpload as unknown as { fileFilter: Function; limits: { fileSize: number; files: number } });
const makeFile = (mimetype: string): Express.Multer.File =>
({ fieldname: "profileImage", originalname: "x", mimetype }) as Express.Multer.File;
const runFilter = (mimetype: string): Promise<{ error: unknown; accepted: unknown }> =>
new Promise((resolve) => {
config.fileFilter({} as Request, makeFile(mimetype), (error: unknown, accepted: unknown) => resolve({ error, accepted }));
});
describe("imageUpload middleware", () => {
it("enforces a file size limit so large uploads cannot exhaust memory", () => {
expect(config.limits.fileSize).toBe(MAX_IMAGE_SIZE_BYTES);
expect(config.limits.fileSize).toBeLessThanOrEqual(3 * 1024 * 1024);
});
it("limits a request to a single file", () => {
expect(config.limits.files).toBe(1);
});
it("accepts allowed image mime types", async () => {
for (const mimetype of ["image/jpeg", "image/png", "image/jpg"]) {
const { error, accepted } = await runFilter(mimetype);
expect(error).toBeNull();
expect(accepted).toBe(true);
}
});
it("rejects non-image uploads with a 415 AppError", async () => {
const { error } = await runFilter("application/octet-stream");
expect(error).toBeInstanceOf(AppError);
expect((error as AppError).status).toBe(415);
});
});