sequelize-auto icon indicating copy to clipboard operation
sequelize-auto copied to clipboard

Mocking auto generated model functions

Open cmgchess opened this issue 3 years ago • 5 comments

More of a question than an issue

I have created my models using sequelize-auto and used them in my controllers

const sequelize = require('../database/db');
var models = require("../models/init-models").initModels(sequelize);

var User = models.User;

const controllerMethod = async (req,res,next) => {
    //calls User.findAll() and returns the results
}

I have called the findAll function of User model in one of my controller methods

I want to test my controller method and want to mock the findAll function to return an empty object. I have imported my models in the test file and mocked the findAll function as follows,

//test case
            models.User.findAll = jest.fn().mockImplementation(() => {
                return {}
            });
            const spy = jest.spyOn(models.User, "findAll")
            await controllerMethod(req, res,next);

My question is when I run the test case it runs the actual findAll() function inside the controller instead of the mocked findAll()

Any help would be greatly appreciated Thanks in advance

cmgchess avatar Oct 06 '21 14:10 cmgchess

I don't know how Sequelize attaches the findAll function to the models. Let me know if you figure this one out.

steveschmitt avatar Oct 10 '21 21:10 steveschmitt

@steveschmitt Thanks for the reply!

I couldn't figure out a proper way of doing this 😕

I created a seperate models.js file and exported all my Models via that. Imported Models to my Controllers from the models.js file instead of const sequelize = require('../database/db'); var models = require("../models/init-models").initModels(sequelize);

Fixed my issue for now until I come across a better solution.

models.js

const sequelize = require('../database/db');
var models = require("./init-models").initModels(sequelize);

module.exports.User= models.User;
module.exports.Instrument = models.Instrument;

module.exports.sequelize = sequelize;  //exported this too since I have used sequelize.fn in some of my controllers

userController.js

//const sequelize = require('../database/db');
//var models = require("../models/init-models").initModels(sequelize);

//var User = models.User;
const {User,sequelize} = require('../service/models');  //imported models this way

const controllerMethod = async (req,res,next) => {
    //calls await User.findAll() and returns the results
}

userController.test.js

const {controllerMethod} = require('../../../controllers/user');
const {User,sequelize} = require('../../../service/models');

//inside test case
           jest.spyOn(User, "findAll").mockImplementation(() => {return Promise.resolve([])});
           await controllerMethod(req, res,next);

in this way findAll mocks the way I wanted and returns the expected []

Would like to know if there is a better way

cmgchess avatar Oct 13 '21 09:10 cmgchess

I don't know why separating it to a different file would make a difference. You must be doing something different in the new code, or in a different order. I'm glad you got it working.

steveschmitt avatar Oct 13 '21 17:10 steveschmitt

I finally figured this one out for my jest unit tests that needed to conditionally mock the resolve values for sequelize auto generated model functions:

import { models } from '../data-store';

const mockAccountFindOne = jest.fn();
const mockItemCreate = jest.fn();
jest.mock('../data-store', () => ({
  models: {
    Account: {
      findOne: jest.fn(() => mockAccountFindOne()),
    },
    Item: {
      create: jest.fn(() => mockItemFindAll()),
    },
  },
}));

mia-pelino avatar Jan 25 '23 18:01 mia-pelino

I finally figured this one out for my jest unit tests that needed to conditionally mock the resolve values for sequelize auto generated model functions:

import { models } from '../data-store';

const mockAccountFindOne = jest.fn();
const mockItemCreate = jest.fn();
jest.mock('../data-store', () => ({
  models: {
    Account: {
      findOne: jest.fn(() => mockAccountFindOne()),
    },
    Item: {
      create: jest.fn(() => mockItemFindAll()),
    },
  },
}));

I am doing the same as below:

import { vi } from 'vitest';
const models = require('../../../src/db/models');
vi.mock('../../../src/db/models', () => ({
  User: {
    findOne: vi.fn(),
  },
}));

But it still tries to make the connection in the actual code where User.findOne({..} is used.

sujeet-agrahari avatar May 13 '23 18:05 sujeet-agrahari