I am new to mocha sinon unit test. This is what i tried to get the expected result. But it's throwing the following error.
AssertionError: expected stub to have been called with arguments 201
Can somebody help me with this or any suggestion if i am doing something wrong.
async createUser(req: Request, res: Response, next: NextFunction) {
const { name, email, password } = req.body;
const user = new User({ name, email, password });
try {
const userCreated = await userService.createUserService(user);
res.status(201).json({ status: 201, data: userCreated });
} catch (err) {
next(httpErrors(500, err.message));
}
}
unit test for the above:
import sinon from "sinon";
import { Request, Response } from "express";
import userController from "./user.controller";
import UserService from "../services/user.service";
import User from "../models/user.model";
describe("UserController", () => {
let userService;
beforeEach(() => {
userService = new UserService();
});
it("should create user", async () => {
const mReq = {
body: {
name: "mockName",
email: "mockEmail",
password: "mockPassword#123"
}
} as Request;
const mRes = {
status: sinon.stub().returnsThis(),
json: sinon.stub()
} as any;
const mNext = sinon.stub();
const stubValue = {
name: "Deepesh"
};
const createUserServiceStub = sinon
.stub(userService, "createUserService")
.resolves(stubValue);
await userController.createUser(mReq, mRes, mNext);
sinon.assert.calledWithExactly(
createUserServiceStub,
new User({
name: "mockName",
email: "mockEmail",
password: "mockPassword#123"
})
);
sinon.assert.calledWithExactly(mRes.status, 201);
sinon.assert.calledWithExactly(mRes.json, {
status: 201,
data: { name: "StubName" }
});
});
});
user.service.ts
import User, { IUser } from "../models/user.model";
import HashPassword from "../utils/password";
class UserService {
private user;
constructor() {
this.user = User;
}
/**
* Function to check existence of user if not then create new user in db
* @param user
*/
public async createUserService(user: IUser): Promise<any> {
try {
// Check for existence of user in db
const userRecord = await this.user.findOne({ email: user.email });
if (userRecord) {
throw new Error("RECORD ALREADY EXISTS");
}
const encPwd = await HashPassword.encryptPassword(user.password); // Encrypt user entered password
user.password = encPwd;
user.role = "user";
const createdUser = await this.user.create(user); // create user
return createdUser;
} catch (error) {
throw error;
}
}
}
export default UserService;
Any help would be really appreciated..
Thanks in advance.
Here is the unit test solution:
controller.ts
:
import { NextFunction, Response, Request } from 'express';
import userService from './service';
import User from './model';
const userController = {
async createUser(req: Request, res: Response, next: NextFunction) {
const { name, email, password } = req.body;
const user = new User({ name, email, password });
try {
const userCreated = await userService.createUserService(user);
res.status(201).json({ status: 201, data: userCreated });
} catch (err) {
next(err);
}
},
};
export default userController;
service.ts
:
import User from './model';
const userService = {
async createUserService(user: User) {
return {};
},
};
export default userService;
model.ts
:
export default class User {
constructor(data) {}
}
controller.test.ts
:
import userController from './controller';
import { Request } from 'express';
import userService from './service';
import sinon from 'sinon';
import User from './model';
describe('userController', () => {
it('should create user', async () => {
const mReq = { body: { name: 'mockName', email: 'mockEmail', password: 'mockPassword#123' } } as Request;
const mRes = { status: sinon.stub().returnsThis(), json: sinon.stub() } as any;
const mNext = sinon.stub();
const stubValue = {
name: 'StubName',
};
const createUserServiceStub = sinon.stub(userService, 'createUserService').resolves(stubValue);
await userController.createUser(mReq, mRes, mNext);
sinon.assert.calledWithExactly(
createUserServiceStub,
new User({
name: 'mockName',
email: 'mockEmail',
password: 'mockPassword#123',
}),
);
sinon.assert.calledWithExactly(mRes.status, 201);
sinon.assert.calledWithExactly(mRes.json, { status: 201, data: { name: 'StubName' } });
});
});
unit test results with coverage report:
userController
✓ should create user
1 passing (25ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 85.71 | 100 | 66.67 | 85.71 |
controller.ts | 90 | 100 | 100 | 90 | 14
model.ts | 100 | 100 | 100 | 100 |
service.ts | 66.67 | 100 | 0 | 66.67 | 5
---------------|---------|----------|---------|---------|-------------------