Problem
While trying to run some Jest testing on my Express application, I encounter this error:
FAIL models/tests/user.model.test.js ● Test suite failed to run
TypeError: Sequelize is not a constructor
2 | const path = require('path');
3 |
> 4 | const sequelize = new Sequelize({
| ^
5 | dialect: 'sqlite',
6 | storage: path.join(__dirname, 'database.sqlite'),
7 | logging: console.log // Output logs to the console
at Object.<anonymous> (models/connection.js:4:19)
at Object.require (models/user.model.js:2:19)
at Object.require (models/__tests__/user.model.test.js:3:64)
Code
This is the actual code for my Sequelize connection:
const Sequelize = require('sequelize'); // also tried const { Sequelize }
const path = require('path');
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: path.join(__dirname, 'database.sqlite'),
logging: console.log // Output logs to the console
});
sequelize.authenticate()
.then(() => {
console.log('Database connection established successfully');
})
.catch((error) => {
console.error('Error connecting to the database: ', error);
});
module.exports = sequelize;
Then this is the code for my actual tests im running on user.model.js:
const { DataTypes } = require('sequelize');
const bcrypt = require('bcrypt');
const { User, createUser, findUserById, findUserByUsername } =
require('../user.model.js');
jest.mock('sequelize', () => ({
define: jest.fn(),
sync: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
query: jest.fn(),
}));
jest.mock('bcrypt', () => ({
hash: jest.fn(),
}));
describe('User Model', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('Should define User model', () => {
expect(sequelize.define).toHaveBeenCalledTimes(1);
expect(sequelize.define).toHaveBeenCalledWith('users', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
});
});
test('Should create user and hash password', async () => {
bcrypt.hash.mockResolvedValue('hashedPassword');
const username = 'testuser';
const password = 'testpassword';
const expectedUser = {
id: 1,
username,
password: 'hashedPassword',
};
User.create.mockResolvedValue(expectedUser);
const user = await createUser(username, password);
expect(User.create).toHaveBeenCalledTimes(1);
expect(User.create).toHaveBeenCalledWith({
username,
password: 'hashedPassword',
});
expect(user).toEqual(expectedUser);
expect(bcrypt.hash).toHaveBeenCalledWith(password, 10);
});
});
Inside my user.model.js file that im running tests on, I import the connection module with const sequelize = require('./connection.js');
. I only run into the problem when I try and run my test, if I start the server it will start no problem and I can interact with the database.
What I've Tried
I've asked chatGPT it said to make sure that I have the right dependencies, and to make sure I import sequelize properly in the connection module. I've tried multiple different ways of importing sequelize, but same issue. I know the right dependencies are installed because my other tests work.
Sequelize
is a class exported by sequelize
module. So you need to mock the class like this: jest.fn(() => instance)
.
After mocking, the Sequelize
class will become jest.fn(() => instance)
,
new Sequelize(/**/)
will return the instance
.
You should use Mocking Partials, which means we just want to mock the Sequelize
class and keep using the original implementation of other things.
import Sequelize, { DataTypes } from 'sequelize';
jest.mock('sequelize', () => {
return {
...jest.requireActual('sequelize'),
default: jest.fn(() => ({
define: jest.fn(),
sync: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
query: jest.fn(),
})),
__esModule: true,
};
});
describe('76657256', () => {
test('should pass', () => {
expect(jest.isMockFunction(Sequelize)).toBeTruthy();
expect(DataTypes.INTEGER).toBeDefined();
});
});