'Mocking auto generated model functions created using sequelize-auto package
I have created my models using the sequelize-auto package 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 using Jest 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,
//inside 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()
i.e. findAll()
returns actual data instead of {}
Any help would be greatly appreciated
Thanks in advance
Solution 1:[1]
Welcome to Stack Overflow. I think the issue with your code is some confusion on how spyOn
works. Please see the documentation here specifically the following:
Note: By default, jest.spyOn also calls the spied method. This is different behavior from most other test libraries. If you want to overwrite the original function, you can use jest.spyOn(object, methodName).mockImplementation(() => customImplementation) or object[methodName] = jest.fn(() => customImplementation);
What this is telling you is that spyOn
actual calls the original method, not the mock implementation.
The way I would do this (and assuming you do not need to assert on how findAll
is called) is not use spyOn
at all but create a dummy models
that is returned from initModels
, which has your dummy findAll
method on it. Something like the following:
const mockModels = {
User: {
findAll: jest.fn(() => {})
}
};
// And then in your test - be careful as jest.mock is "hoisted" so you need to make sure mockModels has already been declared and assigned
test('blah', () => {
jest.mock("../models/init-models", () => ({
initModels: jest.fn(() => mockModels,
});
await controllerMethod(req, res, next) // ...etc
Solution 2:[2]
Managed to fix my issue until I come across a better solution.
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);
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 []
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Marcus |
Solution 2 | cmgchess |