Search code examples
javascriptnode.jsunit-testingsequelize.jssupertest

Mock sequelize with Jest and sequelize-mock


I'm building a new project and I'm trying to use TDD as my default methodology and trying to apply it with integration test.

The thing is easy I want to retrieve all the users from my DB.

//controller.js
const UserService = require('../services/user');

module.exports = {
  // corresponds to /users
  getAllUsers: async (req, res, next) => {
    const users = await UserService.fetchAllUsers();
    res.send(users);
  },
};
const models = require('../database/models/index'); // I tried also with destructuring

module.exports = {
  fetchAllUsers: async () => models.user.findAll(),
};

and my actual test file looks like

const request = require('supertest');

const SequelizeMock = require('sequelize-mock');
const app = require('..');

const dbMock = new SequelizeMock();
const models = require('../src/database/models/index');

jest.mock('../src/database/models/index', () => ({
  user: jest.fn(),
}));

models.user.mockImplementation(() => {
  const UserMock = dbMock.define('user', {});
  UserMock.$queueResult(UserMock.build({
    username: 'username',
    mail: '[email protected]',
  }));
  return UserMock;
});

describe('Demo test', () => {
  it('should respond to users route', (done) => {
    request(app)
      .get('/users')
      .end((err, res) => {
        expect(err).toBeNull();
        expect(res.status).toBe(200);
        expect(res.json).toBe('object');
        done();
      });
  });
});


All of this is actually working but when I'm trying to mock the user I TypeError: models.user.findAll is not a function

I need to replace the model.user with the UserMock's value.

Is there anyway to do this? or I should just mock findAll like

jest.mock('../src/database/models/index', () => ({
  user: () => ({ findAll: jest.fn() }),
}));

``

Solution

  • In this case, I was not mocking what I wanted to.

    If you wish to mock the models all you need to do is use SpyOn like

    const { sequelize, Report, User } = require('../../database/models/index');
    
    
    describe("my test", () => {
        it("should just mock", () => {
            jest.SpyOn(Report, "count").mockResolvedOnce(6);
        })
    })
    
    

    In the case that you need to mock like your service

    first create jest functions to allow the access from outside the scope of your mock and then mock it with "double class call"

    const BaseService = require('../BaseService');
    const mockFecthOne = jest.fn();
    
    
    jest.mock('../BaseService',
      () => jest.fn().mockImplementation(
        () => ({
          fetchOne: mockFetchOne,
        }),
      ));
    
    // inside your test just
    
    BaseService().fetchOne.mockResolvedOnce({....})
    

    and thats it hope it works.