I have a Node.js/Express.js API and I want to test the routes using Jest and Supertest. The app itself works without issues but when I run the test, I keep getting the same error:
● 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)
Do I have to mock also Express and the express Router?
Code for the express app is in a file named 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;
The auth route I'm trying to test looks like this:
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);
}
});
This is my test:
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);
}
});
});