You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest/Supertest测试时express.Router()返回undefined的问题

问题描述

我用Node.js/Express.js开发了一个API,想用Jest和Supertest测试路由。应用本身运行正常,但执行测试时持续报错:

● Test suite failed to run

TypeError: Cannot read properties of undefined (reading 'Router')

  3 | import { requestAuth2 } from "../middleware/requestAuth2.js";
  4 | import { ListUsersCommandOutput } from "@aws-sdk/client-cognito-identity-provider";
> 5 | const router = express.Router();
    |                        ^
  6 |
  7 | router.get("/", requestAuth2, async function (req, res, next) {
  8 |   next();

  at Object.<anonymous> (routes/users.ts:5:24)
  at Object.<anonymous> (app.ts:5:1)
  at Object.<anonymous> (__tests__/routes/auth.test.ts:2:1)

请问我需要mock Express和express Router吗?


相关代码

app.ts

import express, { Request, Response, Express } from "express";
import cookieParser from "cookie-parser";
import cors from "cors";
import logger from "morgan";
import usersRouter from "./routes/users.js";
import authRouter from "./routes/auth.js";
import monitoringRouter from "./routes/monitoring.js";
import bucketRouter from "./routes/buckets.js";
import dynamoDBRouter from "./routes/dynamoDB.js";
import stepFunctionsRouter from "./routes/stepFunctions.js";
import queueRouter from "./routes/queue.js";

const app: Express = express();

app.use(function (_req, res, next) {
  res.header("Access-Control-Allow-Origin", "true");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept",
  );
  res.header("Access-Control-Expose-Headers", "Set-Cookie, Cookie");
  next();
});

app.use(logger("dev"));
app.use(
  cors({
    origin: true,
    credentials: true,
  }),
);
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(`${process.env.ROUTE}/auth`, authRouter);
app.use(`${process.env.ROUTE}/monitoring`, monitoringRouter);
app.use(`${process.env.ROUTE}/users`, usersRouter);
app.use(`${process.env.ROUTE}/bucket`, bucketRouter);
app.use(`${process.env.ROUTE}/dynamodb`, dynamoDBRouter);
app.use(`${process.env.ROUTE}/stepfunctions`, stepFunctionsRouter);
app.use(`${process.env.ROUTE}/queue`, queueRouter);

app.get("/", (_: Request, res: Response) => {
  res.redirect("/api/monitoring/status");
});

app.use(function (_: Request, res: Response) {
  res
    .status(404)
    .json({ message: "We couldn't find what you were looking for 😞" });
});

app.use(function (err: Error, _req: Request, res: Response) {
  console.error(err.stack);
  res.status(500).json(err);
});

export default app;

auth路由代码

import express, { Request, Response } from "express";
import {
  createUser,
} from "../controllers/AuthController.js";
const router = express.Router();

// REGISTER
router.post("/register", async (req: Request, res: Response) => {
  console.log("Req body", req.body);
  // Retrieve user data
  const email: string = req.body.email;
  const password: string = req.body.password;

  // Create new user in Cognito pool
  try {
    console.log("Attempting user creation.");
    const newUser = await createUser({
      email: email,
      password: password,
    });
    console.log("New user", newUser);
    res.status(201).json(newUser);
  } catch (error) {
    console.log("Error", error.message);
    res.status(400).send(error);
  }
});

测试代码

import request from 'supertest';
import app from "../../app";
import {createUser} from "../../controllers/AuthController";

jest.mock("../../middleware/requestAuth2", () => ({
  requestAuth2: jest.fn(),
}));

jest.mock("../../controllers/AuthController", () => ({
  createUser: jest.fn(),
}));

describe('POST /api/auth/register', () => {
  it("should create a user", async () => {
   const mockCreateUser = createUser as jest.Mock;

    try {
      mockCreateUser.mockResolvedValueOnce("user created");
      await request(app)
        .post("/api/auth/register")
        .send({ email: "xxx", password: "xxx" })
        .expect("Content-Type", /json/)
        .expect(201);

    } catch (error) {
      console.log(error);
    }
  });
});

解决方案

不需要mock Express和Router,这个错误的核心是users.ts中导入的express为undefined,导致调用express.Router()失败。按以下步骤排查修复:

  1. 检查TypeScript模块解析配置

    • 确保tsconfig.json中module设为NodeNext或ESNext,moduleResolution与之一致,保证ES模块导入正常工作。
    • 路由导入的.js后缀:如果是TypeScript项目,可尝试去掉导入路径的.js后缀(让TS自动解析),或确认编译后的文件路径匹配。
  2. 修复Jest对ES模块的支持

    • 若项目使用ES模块(package.json中"type": "module"),Jest默认不兼容,需配置jest.config.js:
      export default {
        preset: 'ts-jest',
        testEnvironment: 'node',
        extensionsToTreatAsEsm: ['.ts'],
        moduleNameMapper: {
          '^(\\.{1,2}/.*)\\.js$': '$1',
        },
        transform: {
          '^.+\\.tsx?$': ['ts-jest', { useESM: true }],
        },
      };
      

    该配置让Jest正确解析带.js后缀的TS导入,同时支持ES模块语法。

  3. 确认Express依赖正常

    • 执行npm install express重新安装依赖,或删除node_modules和锁文件后重新安装,避免依赖损坏。
  4. 检查users.ts的Express导入

    • 确保users.ts中的导入语句为默认导入:
      import express from 'express';
      
      而非命名导入(比如import { express } from 'express')。
  5. 临时简化测试依赖

    • 暂时注释app.ts中usersRouter的导入和使用,若测试正常运行,说明users.ts的导入逻辑存在问题,针对性修复即可。

总结:错误源于模块解析或Jest配置导致Express未被正确导入,而非需要mock Express本身。

内容的提问来源于stack exchange,提问作者arengit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:30:56