Skip to content

Instantly share code, notes, and snippets.

@RolandWarburton
Last active June 19, 2021 02:42
Show Gist options
  • Save RolandWarburton/287b325210b7774ff5e0017297c8c02e to your computer and use it in GitHub Desktop.
Save RolandWarburton/287b325210b7774ff5e0017297c8c02e to your computer and use it in GitHub Desktop.
testController.spec.ts
import { NextFunction, Request, Response } from "express";
class IndexController {
public index = (req: Request, res: Response, next: NextFunction): void => {
try {
res.status(200).json({ hello: "world" });
} catch (error) {
next(error);
}
};
}
// when we import the IndexController we need to tell it what method we want to use
// Example: const myController = new IndexController.index
export default IndexController;
import IndexController from "../controllers/index.controller";
import { Request, Response, NextFunction } from "express";
describe("test", () => {
// declare these partials outside of the test scope so they are available within the closure of the test at all times.
// A partial is a typescript feature that means the mocked object will be a subset of the object it is pretending to be
// Later on when we pass the mockRequest and mockResponse to the controller we coerce them into their
// type using the (mockRequest as Request), "as" keyword so the controller is happy with the types
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let nextFunction: Partial<NextFunction>;
// we also create these objects to store the result of the .status and .json that express gives to us when we mock
// the implementation of the .status and .json functions that exist inside the controller
let resultJson = {};
let resultStatus = {};
beforeEach(() => {
// reset the request and response objects before each test
mockRequest = {};
mockResponse = {};
// reset the objects that store results in them
resultJson = {};
resultStatus = {};
// The mockImplementation catches the .status function when it is called in express,
// then runs the below test code to "implement" what the function will do.
//
// To test express there is a special requirement, that is to return the "mockResponse" object every time,
// this mimics the "function chaining" behaviour of express where we call .status().json({}) in the controller
//
// the .mockImplementation((result) => {} "result" variable is given to us by express and represents
// what the controller and express passed to the .status and .json parts of the chain,
// essentiall we just steal that and keep it for our assertions later on in the test
mockResponse.status = jest.fn().mockImplementation((result) => {
resultStatus = result;
return mockResponse;
});
mockResponse.json = jest.fn().mockImplementation((result) => {
resultJson = result;
return mockResponse;
});
// TODO find out how to mock this one as well
nextFunction = jest.fn();
});
test("test", () => {
const controller = new IndexController().index;
// run the index controller with the req of {} and wait for the response
controller(mockRequest as Request, mockResponse as Response, nextFunction as NextFunction);
// when the res.status is called we expect it to be passed 200
expect(resultStatus).toBe(200);
// when the res.json is called we expect it to have the body json from the controller
expect(resultJson).toEqual({ hello: "world" });
// TODO check that the next function has been called
// expect(nextFunction).toHaveBeenCalledTimes(0);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment