sequelize-auto
sequelize-auto copied to clipboard
Mocking auto generated model functions
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
I don't know how Sequelize attaches the findAll
function to the models. Let me know if you figure this one out.
@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
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.
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 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.