vendredi 24 juillet 2020

jest testing nodejs controller

I have the following controller

import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { UserModel, isPasswordAllowed } from '../../models/User';

const saltRounds = 10;

function userController() {
  function add(req, res) {
    try {
      if (req.body.administrator) {
        res.status(400).json({
          error: {
            message: 'Bad Request',
          },
        });
        return;
      }

      if (!isPasswordAllowed(req.body.password)) {
        res.status(400).json({
          error: {
            message: 'La contraseña no cumple con los requisitos minimos',
          },
        });
        return;
      }

      bcrypt.hash(req.body.password, saltRounds, async (err, hash) => {
        if (err) {
          res.status(500).json({ error: { code: '500', message: err.errmsg } });
          return;
        }
        const user = new UserModel();
        user.email = req.body.email.toLowerCase();
        user.password = hash;

        await user
          .save()
          .then(() => {
            const token = jwt.sign(
              {
                username: user.email,
                userId: user.id,
              },
              process.env.JWT_KEY,
              {
                expiresIn: '7d',
              },
            );

            res.status(200).json({
              message: 'Usuario Creado',
              token,
              email: user.email,
            });
          })
          .catch((error) => {
            if (error.code === 11000) {
              res.status(400).json({
                error: { code: '500', message: 'El correo ya existe' },
              });
            } else {
              console.log(error);
              res.status(500).json({ error: { code: '500', message: error.message } });
            }
          });
      });
    } catch (error) {
      res.status(503).json({ error });
    }
  }
  return {
    add,
  };
}

export default userController();

As you can expect this controller works great, the user is created in the database, but I have the following test:

import UserController from './UserController';
import { connect, closeDatabase, clearDatabase } from '../../__test__/db-handler';

describe('test UserController', () => {
  const res = {};
  beforeEach(async () => {
    await connect();
    res.send = jest.fn().mockReturnValue(res);
    res.status = jest.fn().mockReturnValue(res);
    res.json = jest.fn().mockReturnValue(res);
  });

  afterEach(async () => {
    await clearDatabase();
  });

  afterAll(async () => {
    await closeDatabase();
  });

  test('should return the expect api method', () => {
    const userControllerApi = {
      add: expect.any(Function),
    };

    expect(UserController).toMatchObject(userControllerApi);
  });

  test('should return 400 error bad request is body contains administrator: true', async () => {
    const req = {
      body: {
        administrator: true,
      },
    };

    await UserController.add(req, res);
    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledTimes(1);
    expect(res.json).toHaveBeenCalledWith({
      error: {
        message: 'Bad Request',
      },
    });
  });

  test('should return 400 error bad request is password is not allow', async () => {
    const req = {
      body: {
        password: '123456',
      },
    };
    await UserController.add(req, res);

    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledTimes(1);
    expect(res.json).toHaveBeenCalledWith({
      error: {
        message: 'La contraseña no cumple con los requisitos minimos',
      },
    });
  });
  
  // this test is not passing
  test('should create an user and return a token', async () => {

    const req = {
      body: {
        email: 'test@test.com',
        password: 'Abc123456',
      },
    };

    const expectObject = {
      message: 'Usuario Creado',
      email: 'test@test.com',
    };

    await UserController.add(req, res);

    jest.useFakeTimers();

    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.json).toHaveBeenCalledTimes(1);
    expect(res.json).toMatchObject(expectObject);
  });
});

but the last test 'should create an user and return a token' never pass and I get the following:

  ● test UserController › should create an user and return a token

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: 200

    Number of calls: 0

      78 |     jest.useFakeTimers();
      79 | 
    > 80 |     expect(res.status).toHaveBeenCalledWith(200);
         |                        ^
      81 |     expect(res.json).toHaveBeenCalledTimes(1);
      82 |     expect(res.json).toMatchObject(expectObject);
      83 |   });

I also debbug this code in testing mode and as you can see in the following image, the code is enter in the res.status(200).json({ .... }), so I don't understand what it is happening here.

Aucun commentaire:

Enregistrer un commentaire