Home > OS >  How can I either wait or prevent jest from running my db connection in Sequelize, so as to stop the
How can I either wait or prevent jest from running my db connection in Sequelize, so as to stop the

Time:10-26

Im trying to add unit tests to my node express app. The app uses sequelize with sqlite as its orm/database. I am trying to unit test one of my simplest controllers directly (not even trying to test routes with supertest yet)

I was able to get one basic successful test, the issue I a having is that since my controller imports my sequelize User model, it also imports the instantiation of Sequelize. This results in sequelize trying to connect to the DB while the tests are performed. The test is executed before all the db stuff happens, and hence at the end my result is a lot of "Cannot log after tests are done" because Sequelize is still trying to connect and log things, some from the sequelize module itself and others from my code connecting and sync()ing the db.

If I remove the import and usage of the model in my controller, I no longer have those issues, so clearly importing the model is causing all those calls to initialize sequelize. How can i ask Jest to either wait until all async processes are done, or just prevent sequelize from initializing at all (I dont actually need a db connection, i will test them all with mocks)

So here is what the test looks like

describe('testing user registration',  () => {
    let mRes: Response<any, Record<string, any>>;
    let mNext;
    beforeAll(()=>{

         mRes = {
             status: jest.fn().mockReturnThis(),
             json: jest.fn()
         }
         mNext = jest.fn(err => err)
        jest.spyOn(UserModel, 'create').mockResolvedValue(createdUser)

    })

    afterAll(()=>{
        jest.resetAllMocks();
    })

    test('with invalid email', async () => {
        const result = await registerUser(mReqInvalidEmail, mRes, mNext);

        expect(mNext).toBeCalledWith(invalidBodyError)
    })
})

Here is what the Controller looks like:

const registerUser = async(req:Request,res:Response,next:NextFunction) : Promise<Promise<Response> | void> => {
    const {body} = req
    const {email, role} = body;
    if(!isValidEmail(email) || !isValidRole(role)){
        const error = createError(
            400,
            'Invalid body, please provide a valid email address a role of oneOf[\"user\",\"super\"]',
            {
                body: {
                    email: 'a valid email string',
                    role: 'string, oneOf [user, super]'
                }
            }
        );
        return next(error);
    }
    const password = generatePassword()
    const hash = hashPassword(password)

    const user = await User.create({email, role, password:hash}).catch((err: Error) : Error => {
        return createError(500, 'woopsie', err)
    })

    if(user instanceof Error){
        return next(user)
    }
    return res.status(200).json({
        email,
        role,
        password
    });
}

The model:

import {sqlzDB} from "../../database/db";
const User = sqlzDB.define('User',
    {
        ...myfields, not including to save space
    }, {
options
    })

And finally, where sequelize gets initialized (declaring sqlzDB). This is all the code that is running that I need to either wait for it to finish, or just prevent it from getting called at all!

const {Sequelize} = require('sequelize');

export const sqlzDB = new Sequelize({
    dialect: 'sqlite',
    storage: 'database/db.sqlite'
});

sqlzDB.authenticate()
    .then(():void => {
        console.log('Connection to database established successfully.');
    }).catch((err : Error): void => {
        console.log('Unable to connect to the database: ', err);
    })

sqlzDB.sync().then(()=>{
    console.log('Sequelize Synced')
})

My test passes just fine. Note that for the test i wrote i dont actually need the mocks yet, Since im just trying to get the setup to work correctly.

I have tried suggestions I have seen out here like calling await new Promise(setImmediate); after my test, or also closing the connection with sqlzDB.close() which causes some different issues (it closes the connection but still tries to log)

So i dont know how to approach this at this point! Sorry for th elong question and thanks to whoever took their time to read this!

CodePudding user response:

You can try a trick to avoid this issue: Close the connection in afterAll

    afterEach(() => { // reset mock should be in afterEach
        jest.resetAllMocks();
    });

    afterAll(async ()=>{
        await sqlzDB.close();
        await new Promise(res => setTimeout(res, 500)); // avoid jest open handle error
    });
  • Related