Reputation: 755
Am pretty new to JS, but I am trying my best to learn. As it is, I am trying to mock express. Here is my base class (cut down, for testing purposes):
import compression from 'compression';
import express from 'express';
export default class Index{
constructor(){}
spawnServer(){
console.log(express());
let app = express();
app.use(STATIC_PATH, express.static('dist'));
app.use(STATIC_PATH, express.static('public'));
etc...
}
}
And here is the test I am trying to achieve, in a separate test file...:
test('should invoke express once', () =>{
index.spawnServer();
expect(mockExpressFuncs().use.mock.calls.length).toBe(3);
})
My question is - how do I make the test override the require of the class under test - is that even possible? I want to have my Index use a mocked version of express, one that includes express() and express.require.
I did read through the documentation, and attempted something like:
const mockFunction = function() {
return {
use: useFn,
listen: jest.fn()
};
};
beforeEach(() => {
jest.mock('express', () => {
return mockFunction;
})
express = require('express');
});
But that did not work - what am I doing wrong? :(
Thanks.
Upvotes: 13
Views: 15322
Reputation: 1687
Creating express server. file name : myExpress.ts
import {Request, Response} from 'express';
const express = require('express');
const PORT = 8088;
const onConnectRequest = (req: Request, res: Response) => {
const connectRequest = req.body;
console.log(`Got connect request: ${JSON.stringify(connectRequest)}`);
// DO the logic
res.status(200).send();
};
const onDisconnectRequest = (req: Request, res: Response) => {
console.log('Got disconnect request,');
// DO the logic
res.status(200).send('user disconnected');
};
export const createServer = () => {
const tackListenerServer = express();
tackListenerServer.use(express.json());
tackListenerServer.post('/users/connect', onConnectRequest);
tackListenerServer.post('/users/disconnect', onDisconnectRequest);
tackListenerServer
.listen(PORT)
.on('listening', () => console.log(`Express server started on port ${PORT}`))
.on('error', (errorMessage: string) => console.error(`Error occurred during express server startup on port ${PORT}: ${errorMessage}`));
};
Creating express mock with jest file name: express-mock.ts
export let expressMock: any;
jest.mock('express', () => {
let routes = new Map();
let actualPort: number;
const actualExpress = jest.requireActual('express');
const expressMockFn = jest.fn(() => ({
...actualExpress,
post: jest.fn((path, handler) => {
routes.set(path, handler);
}),
use: jest.fn((middleware) => {}),
listen: jest.fn((port: number) => {
actualPort = port;
const serverMock: any = {
on: jest.fn((event: any, callback: any) => {
if (event === 'listening') {
setImmediate(callback);
}
return serverMock;
}),
};
return serverMock;
}),
mockTriggerPost: (path: string, req: any, res: any) => {
let callback = routes.get(path);
if (callback) {
callback(req, res);
} else {
throw new Error(`No handler found for path: ${path}`);
}
},
getActualPort: () => {
return actualPort;
},
clearMock: () => {
routes.clear();
}
}));
//@ts-ignore
expressMockFn.json = jest.fn();
expressMock = expressMockFn;
return expressMockFn;
});
Creating test file name : express.test.ts
import {expressMock} from "./mocks/express-mock";// Adjust the path to your actual file
import * as myExpress from "../../src/app/services/myExpress";// Adjust the path to your actual file
describe('Express Server', () => {
beforeEach(() => {
jest.useFakeTimers();
});
let expressMockInstance = expressMock();
afterEach(() => {
jest.clearAllTimers();
expressMockInstance.clearMock();
});
it('verify listen on the correct port and post return OK', () => {
myExpress.createServer();
// @ts-ignore
expect(expressMockInstance.getActualPort()).toBe(8088);
let actualStatusCode;
const actualExpressResponse = {
status: jest.fn((statusCode: number) => {
actualStatusCode = statusCode;
return {send: jest.fn()}
})
};
expressMockInstance.mockTriggerPost('/users/connect', {
body: {
userId: "123"
}
}, actualExpressResponse);
expect(actualStatusCode).toBe(200);
});
});
Upvotes: 0
Reputation: 2371
Create the mock app object and make it be returned by express module.
Then you can check how many times app.use
have been called using either expect(app.use.mock.calls.length).toBe(3)
or better expect(app.use).toHaveBeenCalledTimes(1)
const app = {
use: jest.fn(),
listen: jest.fn()
}
jest.doMock('express', () => {
return () => {
return app
}
})
test('should invoke express once', () => {
expect(app.use).toHaveBeenCalledTimes(1)
})
Upvotes: 14