使用Jest测试Express+TS应用时Multer报undefined错误
问题场景
我开发了基于TypeScript的Express应用,用Multer处理文件上传,应用本身运行正常,但用Jest测试时触发错误:TypeError: Cannot read properties of undefined (reading 'diskStorage'),错误出在调用multer.diskStorage()的Multer配置模块中。
相关代码如下:
Multer配置模块
import multer from "multer"; const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "images/"); }, filename: function (req, file, cb) { const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9); cb( null, ( file.fieldname + "-" + uniqueSuffix + "-" + file.originalname ).replace(/ /g, "_") ); }, }); function filter(req: object, file: Express.Multer.File, cb: Function) { cb(null, file.mimetype === "image/jpg" || file.mimetype === "image/jpeg"); } const postStorage = multer({ storage: storage, fileFilter: filter, limits: { fileSize: 1024 * 1024, // max size in bytes }, }); export default postStorage;
路由使用代码
const router = express.Router(); router.get("/", getAll); router.post( "/", postStorage.fields([ { name: "main_image", maxCount: 1 }, { name: "additional_images", maxCount: 5 }, ]), RequestValidator(PostSchema, "body"), insert ); export default router;
Jest测试代码
describe("do ", () => { describe("dodo", () => { it("dododo", async () => { await supertest(app).get("/").expect(200); return true; }); }); });
解决方案
这个错误的核心是Jest测试环境中Multer模块的导入或解析出现问题,以下是几种可行的解决方法:
1. 修正Multer导入方式
将默认导入改为命名导入,避免Jest对ES模块默认导入的解析异常:
// 替换原import语句 import * as multer from "multer";
这种方式能确保获取完整的Multer模块对象,不会出现模块为undefined的情况。
2. 配置Jest兼容ES模块
如果项目使用ES模块,在jest.config.js或jest.config.ts中添加以下配置:
module.exports = { // 其他已有配置... transform: { "^.+\\.tsx?$": "ts-jest", }, moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], // 让Jest不忽略Multer模块的转换 transformIgnorePatterns: ["<rootDir>/node_modules/(?!multer)/"], };
transformIgnorePatterns设置会确保Multer被ts-jest正确转换,避免因模块格式不兼容导致的错误。
3. 模拟Multer模块(适用于无需测试文件上传逻辑的场景)
如果测试仅验证路由基础响应(比如示例中的GET请求),可以直接在测试中模拟Multer,跳过真实的文件上传逻辑:
在测试文件顶部添加:
jest.mock("multer", () => ({ diskStorage: jest.fn(), __esModule: true, default: jest.fn(() => ({ fields: jest.fn(() => (req, res, next) => next()), })), }));
这个模拟会让Multer返回一个空中间件,不会触发真实的diskStorage调用,从而绕过错误。
4. 检查TypeScript配置
确保tsconfig.json的模块设置与Jest兼容:
{ "compilerOptions": { "module": "CommonJS", // 若用ESNext需对应调整Jest配置 "target": "ES6", "esModuleInterop": true, "allowSyntheticDefaultImports": true } }
esModuleInterop和allowSyntheticDefaultImports能帮助TypeScript正确处理CommonJS模块的默认导入,避免导入后模块为undefined。
内容的提问来源于stack exchange,提问作者Muhib Al Hasan

