'Jest: await mssql.connect not working (timeout)

I want to test some functionality that should not rely on mocked sql query results but that should actually write to the database in a nextjs Typescript project.

Here's a minimal example of what is going wrong:

/* @/lib/db.ts */
import sql, { ConnectionPool } from "mssql";

const sqlConfig: sql.config = {
  user: process.env.DB_USER,
  password: process.env.DB_PWD,
  database: process.env.DB_NAME,
  server: process.env.DB_HOST!,
  pool: {
    max: parseInt(process.env.MAX_DB_CONNECTIONS || "10"),
    min: 0,
    idleTimeoutMillis: 30000
  },
  options: {
    encrypt: true, // for azure
    trustServerCertificate: true // change to true for local dev / self-signed certs
  }
};

if (!global.db) {
  global.db = { pool: null };
}

export async function connectToDatabase(): Promise<ConnectionPool> {
  if (!global.db.pool) {
    console.log("No pool available, creating new pool."); // this output shows up in the console
    const pool = await sql.connect(sqlConfig);
    global.db.pool = pool;
    console.log("Created new pool."); // this is never reached
    
  }
  return global.db.pool!;
}
/* db.test.ts */

import { connectToDatabase } from "@/lib/db";
// as you can see I already tried a high timeout. The db connection never takes this long in development
jest.setTimeout(30000);

describe("Database", ()=>{
  it("can connect", async()=>{
    const pool = await connectToDatabase();
    expect(1).toBe(1);
  });
});

export {};

The test above fails because the connectToDatabase() Promise never fulfills (it doesn't reject either, which it should do when the credentials are wrong)

I have copied the .env.local file, which contains the DB credentials, and named it .env.test. I have also verified that the env data are in fact getting read correctly by outputting sqlConfig

The db.ts functions work perfectly in development.

Is there anything I overlooked why this shouldn't work in jest out of the box?



Solution 1:[1]

Ok I found it:

After taking a deeper look at the error log, I saw that I only read the lower half (ignore the different file name from the question):

  ControllingTableLock
    ? works (30016 ms)

  ? ControllingTableLock › works

    ReferenceError: setImmediate is not defined

      at node_modules/mssql/lib/base/connection-pool.js:402:9
          at Array.forEach (<anonymous>)
      at node_modules/mssql/lib/base/connection-pool.js:401:26

  ? ControllingTableLock › works

    thrown: "Exceeded timeout of 30000 ms for a test.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

       5 |
       6 | describe("ControllingTableLock", ()=>{
    >  7 |   it("works", async()=>{
         |   ^
       8 |     const pool = await connectToDatabase();
       9 |     expect(1).toBe(1);
      10 |     return;

After some research I found out that

setImmediate is not defined

is an error that stems from jest using the jsdom environment instead of node.

The fix was very simple: I added

/*
* @jest-environment node
*/

above the imports in the test file.

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 Taxel