mongoose memory leak attributed to jest

UPDATED 2020-09-14

I've encountered an issue with a test case I wrote. While the testcase passes, it raises a complaint about improper teardown and an open connection. Can anyone help identify the problem:

Approach to Solving the Issue - Memory Leak

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection> = async MONGO_DB_NAME => {
  if (conn == null) {
    conn = await createConnection(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      bufferCommands: false,
      bufferMaxEntries: 0,
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async done => {
    db = await getConnection(MONGO_DB_NAME);
    done();
  });
  afterAll(async done => {
    if (conn) {
      await db.dropDatabase();
      await conn.close();
    }
    done();
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

Error:

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --runInBand --detectOpenHandles to find leaks.

Simplifying the code doesn't solve the issue:

Another Attempt - Memory Leak

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection> = async MONGO_DB_NAME => {
  if (conn == null) {
    conn = await createConnection(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      bufferCommands: false,
      bufferMaxEntries: 0,
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

The problem persists even when trying it another way:

Alternative Approach - Memory Leak

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection | null> = MONGO_DB_NAME =>
  new Promise(resolve => {
    if (conn == null) {
      conn = createConnection(__MONGO_URI__, {
        dbName: MONGO_DB_NAME,
        bufferCommands: false,
        bufferMaxEntries: 0,
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true
      });
      conn.on('connected', () => {
        console.log('connection established');
        resolve(conn);
      });
    }
    resolve(conn);
  });

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

This new approach also presents the same issue:

Finding a Solution - Memory Leak

import mongoose from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: typeof mongoose;

const getConnection: (MONGO_DB_NAME: string) => Promise<typeof mongoose> = async MONGO_DB_NAME => {
  if (!conn) {
    conn = await mongoose.connect(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      // bufferCommands: false,
      // bufferMaxEntries: 0,
      // useNewUrlParser: true,
      // useUnifiedTopology: true,
      // useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: typeof mongoose;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

Answer №1

the final solution - credit goes to @EstusFlask

establishMongoConnection.ts

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const fetchConnection: (MONGO_DB_NAME: string) => Promise<Connection | null> = MONGO_DB_NAME =>
  new Promise(resolve => {
    if (conn == null) {
      conn = createConnection(__MONGO_URI__, {
        dbName: MONGO_DB_NAME,
        bufferCommands: false,
        bufferMaxEntries: 0,
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true
      });
      conn.on('connected', () => {
        resolve(conn);
      });
    }
    resolve(conn);
  });

export default fetchConnection;

mytest.test.ts

import { Connection } from 'mongoose';
import fetchConnection from './establishMongoConnection';

let db: Connection | null;

const MONGO_DB_NAME = 'mongo-test';
const collectionName = 'users';

describe('mongodb - testing connection setup and teardown', () => {
  beforeAll(async () => {
    db = await fetchConnection(MONGO_DB_NAME);
  });
  afterAll(async () => {
    if (db) {
      await db.dropDatabase();
      await db.close();
    }
  });
  it('should insert a document into the collection', async () => {
    if (db) {
      const users = db.collection(collectionName);

      const mockUser = { _id: 'some-user-id', name: 'John' };
      await users.insertOne(mockUser);

      const insertedUser = await users.findOne({ _id: 'some-user-id' });
      expect(insertedUser).toEqual(mockUser);
    }
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

how to send both the useState setter and object as props to a child component in React using TypeScript

Having an issue with passing useState setter and object (both together) to the child component. Successfully passed the object by spreading it like this {...object}, but unsure of the syntax to pass the setter along as well. Here's a code example: < ...

Can a map key value be converted into a param object?

I have a map containing key-value pairs as shown below: for (let controller of this.attributiFormArray.controls) { attributiAttivitaMap.set(controller.get('id').value, { value: controller.get('valoreDefault').value, mandatory ...

What could be the reason for the exclusion of 'null' from the return type of Document.getElementById in VS Code?

Versions of VS Code: Experimenting with 'Type Narrowing' Code in VS Code has brought to my attention a discrepancy between the information provided by VS Code and TypeScript Playground: In VS Code, it shows that the return type of Document.getE ...

Implementing a dynamic star rating system in Angular

I am working with an array of ratings that looks like this: "rating": [ { "sno": 1, "question": 13, }, { "sno": 2, ...

TypeScript Generic Functions and Type Literals

Everything seems to be running smoothly: type fun = (uid: string) => string const abc: fun = value => value const efg = (callback:fun, value:string) =>callback(value) console.log(efg(abc, "123")) However, when we try to make it generic, we e ...

Testing components in React Native using asynchronous Jest methods

I have a component that triggers a fetch request when it mounts and then displays the results. I've been struggling to create a test snapshot of this component after the request is completed. I've searched on various forums like SO but haven&apo ...

Is it possible to indicate the base type for a generic function?

Is it possible to define the generic type T as an Object rather than a primitive type like number or string? For example, this clone function should only accept Objects as input. It will destructure the input object o, set its prototype back to that of th ...

I can't figure out why the option value is being displayed as "2: Object" when printing it. Can someone please clarify

Hey there! Currently, I have a UI built using Angular 5 and TypeScript. In one of my components, I have a reactive form with a select box form control in the view. What I'm trying to achieve is that whenever a different option is selected from the sel ...

Using conditional statements to render content based on a certain condition within a

One of my requirements is to dynamically render a React component in the following manner: parent.ts ... <Parent> <Child/> <Parent> ... child.ts ... return (someBoolean && <Component/>) ... While ...

Exploring the concepts of type intersection in TypeScript

I attempted to create a type definition for recurrent intersection, in order to achieve this specific behavior: type merged = Merged<[{a: string}, {b: string}, ...]> to end up with {a: string} & {b: string} & ... I came up with some type u ...

reinstate dummy of external class method in ts-jest

Problem I am encountering an issue while trying to mock a function that is imported from another class and called within the main class. Although I can successfully mock the function and return the specified values, I am unable to revert the mocked functi ...

Issue with Typescript in react: JSX element lacks construct or call signatures

After upgrading TypeScript, I encountered the error mentioned above in one of my components. In that component's render method, I have the following code: render() { const Tag = props.link ? 'a' : 'div'; return ( < ...

Change a nullable string property within an interface to a non-nullable string property

Looking at two interfaces, one with a nullable vin and the other without: interface IVehicle { vin: string | null; model: string; } interface IVehicleNonNullVin { vin: string; model: string; } The goal is to convert a model from IVehicle ...

TypeError: Unable to find TextEncoder in mongoose and jest when using TypeScript

Currently, I am working on a project using Node 14 along with Express v4.16.3 and Typescript (v4.7.4). Recently, I added Mongoose (v6.5.2) to the project, and while the logic code seems fine, most of the tests executed by Jest (v26.4.2) are failing with th ...

The program was expecting an array to start, but instead encountered an object. Any suggestions on how to convert

{ "workingHours": [ { "date":"2023-02-01", "amount":3, "freigegeben":false } ] } Whenever I include this in my re ...

Challenges encountered when using promises for handling mysql query results

I've been working on creating a function that will return the value of a mysql query using promises. Here's what I have so far: query(query: string): string { var response = "No response..."; var sendRequest = (query:string): Prom ...

How to compare and filter items from two arrays using TypeScript

I am looking to filter out certain elements from an array in TypeScript Original Array: [ {"Id":"3","DisplayName":"Fax"}, {"Id":"1","DisplayName":"Home"}, {"Id":&quo ...

Efficiently process and handle the responses from Promise.all for every API call, then save the retrieved data

Currently, I am passing three API calls to Promise.all. Each API call requires a separate error handler and data storage in its own corresponding object. If I pass test4 to Promise.all, how can I automatically generate its own error and store the data in ...

Tips for obtaining response headers

Currently, I am utilizing Angular version 15.0 and retrieving a list of items from the backend (ASP.NET Core 5) with an additional item attached to the header. The GET method in the client-side service is as follows: /** GET Paged commodities from the s ...

Do you think this is a clever way to circumvent using ENUM for a parameter?

As I continue to explore different coding styles in Typescript and Angular, I recently encountered a method without any comments attached to it. It seems like this method is enforcing that the value passed in must be one of the defined options, but strang ...