How to use bcrypt in JEST Unit Testing for a FindAll() Method

Viewed 16

I have a NestJS App that has GET routes. One of them, for instance, is the FindAll() which simply gets all the users from Prisma. The FindAll() method looks like this:

  findAll(): Promise<Users[]> {
    return prisma.users.findMany();
  }

And in my service.spec.ts I have this:

const usersMany = [
  {
    username: 'user1',
    name: 'User One',
    password: '123',
    email: 'user1@test.com',
    tasks: [],
  },
  {
    username: 'user2',
    name: 'User Two',
    password: '456',
    email: 'user2@test.com',
    tasks: [],
  },
]

  describe('findAll', () => {
    it('should return all users', async () => {
      const usersAll = service.findAll();
      expect(usersAll).resolves.toEqual(usersMany);
    });
  });

How would I go about running this test case if I am also encrypting the passwords using bcrypt? In a running application, this would result in me getting all the users currently made with their passwords hashed instead of plain string.

1 Answers

I would make sure to never return the password, hashed or not. With a hashed password, you can still run bcrypt.compare() with a plain string and the hash and if you're lucky eventually determine the password. If you really do plan on keeping this approach, you can use Jest's .arrayContaining matcher with a regex for the password like

expect(usersAll).toEqual(
  expect.arrayContaining(
    usersMany.map((user) => ({
      ...user,
      password: expect.stringMatching(/\$2a\$<SALT_VALUE_HERE>\$.+/)
    })
  )
)

This will allow the password to be hashed in the responses to match a regex rather than a strict value, as bcrypt does not hash the same value to the same hash twice. Make sure to replace the <SALT_VALUE_HERE> (the default value is 10)

Your other option would be mocking the bcrypt module to return some sort of expected string.

Your best option in my opinion would be to make sure your API never returns the password to the client.

Related