Search code examples
node.jsunit-testingjestjssequelize.js

TypeError: User.findOne is not a function when mocking sequelize model in vitest


I'm trying to run some Jest tests for the auth.service.js module, which uses Sequelize ORM. However, when I run the tests, I'm getting the following error:

FAIL  tests/modules/auth/auth.service.test.js > AuthService > login > should login user and return token
TypeError: User.findOne is not a function

Here is the code for AuthService

const User = require('../../db/models/User');
 const AuthService =  {
  doLogin: async (requestBody) => {
    const { email, password } = requestBody;
    const user = await User.findOne({ where: { email } });
    // rest of the code
  }
}


module.exports = AuthService;

And here is the test code,

import { describe, it, expect, vi, afterEach } from 'vitest';
import bcrypt from 'bcryptjs';
import SequelizeMock from 'sequelize-mock';

const { faker } = require('@faker-js/faker');

const AuthService = require('../../../src/modules/auth/auth.service');
const JwtService = require('../../../src/modules/auth/jwt.service');

vi.mock('../../../src/db/models/User', async () => {
  const dbMock = new SequelizeMock();
  const fakeUser = {
    id: 1,
    phone: faker.phone.phoneNumber('##########'),
    password: faker.internet.password(8),
  };
  const UserMock = dbMock.define('User', fakeUser);
  return UserMock;
});

describe('AuthService', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  describe('login', () => {
    it('should login user and return token', async () => {
      // Arrange
      const requestBody = {
        phone: faker.phone.phoneNumber('##########'),
        password: faker.internet.password(8),
      };
      const fakeUser = {
        id: faker.datatype.uuid(),
        role: faker.datatype.string(4),
      };
      const fakeAccessToken = 'fake-access-token';
      vi.spyOn(bcrypt, 'compareSync').mockImplementation(() => true);
      vi.spyOn(JwtService, 'generateJWT').mockResolvedValue(fakeAccessToken);

      const expected = {
        ...fakeUser,
        accessToken: fakeAccessToken,
      };

      // Act
      const result = await AuthService.doLogin(requestBody);

      // Assert
      expect(result).toEqual(expected);
    });
  });
});

I also tried the below answers, but none of them work:

Sequelize Model Mocking findAll and findOne using sequelize-mock and jest

Mock sequelize with Jest and sequelize-mock


Solution

  • vitest was not giving me proper errors. Inside vi.mock() we can't access outside scoped variables.

    I got this error when I changed it to jest. Now, I have changed my test runner from vitest to jest, and it's working. I also removed sequelize-mock dependency as I don't need this for my use case as of now.

    const bcrypt = require('bcryptjs');
    
    const { faker } = require('@faker-js/faker');
    
    const AuthService = require('../../../src/modules/auth/auth.service');
    const JwtService = require('../../../src/modules/auth/jwt.service');
    
    jest.mock('../../../src/db/models/User', () => {
      const fakeUser = {
        id: 'fake-id',
        role: 'fake-role'
      };
      const User = {
       findOne: jest.fn().mockResolvedValue(fakeUser)
      };
      return User;
    });
    
    describe('AuthService', () => {
      describe('login', () => {
        it('should login user and return token', async () => {
          // Arrange
          const requestBody = {
            phone: faker.phone.phoneNumber('##########'),
            password: faker.internet.password(8),
          };
          const resolvedFakeUser = {
            userId: 'fake-id',
            role: 'fake-role',
          };
          const fakeAccessToken = 'fake-access-token';
          jest.spyOn(bcrypt, 'compareSync').mockImplementation(() => true);
          jest.spyOn(JwtService, 'generateJWT').mockResolvedValue(fakeAccessToken);
    
          const expected = {
            ...fakeUser,
            accessToken: fakeAccessToken,
          };
    
          // Act
          const result = await AuthService.doLogin(requestBody);
    
          // Assert
          expect(result).toEqual(expected);
        });
      });
    });