Search code examples
node.jsunit-testingexpressmocha.jssinon

AssertionError: expected stub to have been called with arguments 201


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.


Solution

  • 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                 
    ---------------|---------|----------|---------|---------|-------------------