Testing the Express API with MongoDB on a local machine is successful but encounters a timeout issue on CircleCI

I am facing an issue with testing a RESTful API (built with Express in TypeScript) using Jest. The test passes successfully on my local Windows machine but times out on CircleCI.

.circleci/config.ylm

version: 2.1
jobs:
  build:
    docker:
      - image: circleci/node:16.3.0
    working_directory: ~/Mealplanr-api/api
    steps:
      - checkout:
          path: ~/Mealplanr-api
      - run:
          name: Install dependencies
          command: |
            yarn install
      - run:
          name: Run tests
          command: |
            yarn test:ci
      - store_test_results:
          path: test-results
      - store_artifacts:
          path: test-results

package.json

...

"scripts": {
    "start": "nodemon --config nodemon.json src/server.ts",
    "test": "jest --watchAll",
    "test:ci": "jest"
  },

...

jest.config.js

module.exports = {
    roots: ['<rootDir>/src'],
    testMatch: [
        '**/__tests__/**/*.+(ts|tsx|js)',
        '**/?(*.)+(spec|test).+(ts|tsx|js)',
    ],
    transform: {
        '^.+\\.(ts|tsx)$': 'ts-jest',
    },
};

The test description is as follows

users.spec.ts

import request from 'supertest';
import app from '../app';

import { connectDB, closeDB } from '../connect';

describe('POST /users', () => {
    beforeAll(async () => {
        await connectDB();
    });

    afterAll(async () => {
        await closeDB();
    });

    it('Should create a new user', async () => {
        const res = await request(app).post('/users').send({
            email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2d59485e596d59485e590359485e59">[email protected]</a>',
            password: '123456',
            passwordconfirmation: '123456',
        });

        const body = res.body;
        expect(body?.hasOwnProperty('_id')).toBe(true);
        expect(body?.hasOwnProperty('email')).toBe(true);
        expect(body?.hasOwnProperty('createdAt')).toBe(true);
        expect(body?.hasOwnProperty('updatedAt')).toBe(true);
    });
});

The functions used for connection are described here

connect.ts

import { connect, disconnect } from 'mongoose';
import log from './logger';
const mongoose = require('mongoose');
import { Mockgoose } from 'mockgoose';
const mockgoose = new Mockgoose(mongoose);

const dbUri = process.env.DB_URI as string;

export async function connectDB() {
    if ((process.env.NODE_ENV as string) === 'test') {
        // In the test environment, we don't want to connect to the real DB.
        await mockgoose.prepareStorage();
        await connect(dbUri, {
            useNewUrlParser: true,
            useCreateIndex: true,
            useUnifiedTopology: true,
        }).catch((error) => {
            log.error('Error in connecting', error);
        });
        log.info('Mock connection success');
    } else {
        // If not in the test environment, connect to the database
        await connect(dbUri, {
            useNewUrlParser: true,
            useCreateIndex: true,
            useUnifiedTopology: true,
        }).catch((error) => {
            log.error('Error in connecting', error);
        });
        log.info('Connection success');
    }
}

export async function closeDB() {
    await mockgoose.shutdown();
    await disconnect();
}

Output from CircleCI:

#!/bin/bash -eo pipefail
yarn test:ci

yarn run v1.22.5
$ jest
Completed: 100 % (80.8mb / 80.8mbb FAIL  src/routes/users.spec.ts (30.653 s)
  ● POST /users › Should create a new user

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

       5 |
       6 | describe('POST /users', () => {
    >  7 |  beforeAll(async () => {
         |  ^
       8 |      await connectDB();
       9 |  });
      10 |

      at src/routes/users.spec.ts:7:2
      at Object.<anonymous> (src/routes/users.spec.ts:6:1)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:387:19)
      ...

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        30.842 s
Ran all test suites.
Jest did not exit one second after the test run has completed.

This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Exited with code exit status 1

Answer №1

It appears that the issue lies in the deprecation of mockgoose, causing it to malfunction when executed on CircleCI. To resolve this issue, one alternative is to utilize mongodb-memory-server.

Caution: The use of this package is no longer recommended! Consider switching to mongodb-memory-server instead.

This serves as a partial solution. Currently, I have only managed to make it function by including the following configuration in my package.json file:

"config": {
    "mongodbMemoryServer": {
      "version": "4.2.3"
    }
  }

Answer №2

Lately, I came across this issue while using the package

"mongodb-memory-server": "^8.13.0"
. To resolve it, I switched to the node: bullseye image (which is based on Debian 11) on CircleCI and surprisingly, it worked seamlessly without any additional configurations needed.

You can check out a sample repository where everything is in working order here: https://github.com/duluca/document-ts

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

Alerting Users Before Navigating Away from an Angular Page

I am looking to implement a feature in my app that will display a warning message when attempting to close the tab, exit the page, or reload it. However, I am facing an issue where the warning message is displayed but the page still exits before I can resp ...

Why am I unable to apply the keyof operator from one type to another type, even though both types have identical keys defined but different value types?

Consider this code snippet. I am encountering a TypeScript error specifically on the last compat[k] line with the following error message: Type 'keyof T' cannot be used to index type 'Partial<CompatType>' export type KeysOfType ...

Error: The method cloudinaryStorage does not exist as a function

I am encountering a TypeError while attempting to integrate Cloudinary into my code. Below is the snippet of code I am working with: const express = require('express') const bodyParser = require('body-parser') const multer = require(&a ...

The 'required' validator in Mongoose seems to be malfunctioning

I've been attempting to validate the request body against a Mongoose model that has 'required' validators, but I haven't been successful in achieving the desired outcome so far. My setup involves using Next.js API routes connected to Mo ...

"Enhance user experience with Angular Material: Popup Windows that preserve functionality in the original window while staying vibrant and accessible

Exploring Angular Material Dialog and other Popup Window Components for a project. Making progress but facing some challenges. Here are the requirements: a) The original screen should not be grayed out, b) Users should be able to interact with the windo ...

react-mock-store: Error - the middleware function is not defined

In my current setup, I am utilizing jest for testing with React and Typescript. import configureStore from "redux-mock-store"; import thunk from "redux-thunk"; const mockStore = configureStore([thunk]); it("should handle fetchCha ...

Session Redirect Error in Express.js

Encountering an error consistently when running my code with the pseudocode provided below (Just to clarify, my code is built on the react-redux-universal-hot-example) Error: Can't set headers after they are sent. [2] at ServerResponse.OutgoingMe ...

Guide to displaying loading progress during server response delay in React with TypeScript

I need to find a way to update the loading state to false once the server responds. The challenge is that the response occurs in one component, while the progress bar is located in another. To illustrate the scenario: const Form: React.FC = () => { ...

Tips on modifying the selected type key name through Pick?

I currently have this structure: type Product = { name: string } and I am looking to extract the name property and use it in a different type declaration like so: type NewProduct = Pick<Product, 'name'> Now, I want to rename name as new ...

Unusual behavior when importing in Angular 2 using TypeScript

While working on a demo for another question on Stack Overflow, I initially used angular-cli and then switched to Plunker. I noticed a peculiar difference in behavior with the import statement between the two setups. The issue arises with the second impo ...

The comparison between exposing and creating objects in a Nodejs router file

Recently, I began using expressjs 4.0.0 and was impressed by the express.Router() object. However, a dilemma arose when I moved all my routes to another file - how do I expose an object to the routes file? In my server.js file: ... var passport = ...

Maximizing performance with Mongodb by splitting a single collection into multiple ones

I am managing a Rails app with multiple collections in MongoDB. One of the collections contains approximately 800,000 entries. I am considering splitting this collection into four separate collections based on the year it is related to (2018, 2019, 2020, ...

What is the best way to compare List<DateTimie> using ElemMatch in C#?

Struggling with the {Document} is not supported. exception in C# - any advice? Looking to convert this MongoDB query into C# code: db.Data.find({ "searchData": "Abc", "modifyDates": { $elemMatch:{ ...

Is Drizzle ORM able to handle decimal values in MySQL as strings?

The data structure: export const myTable = mysqlTable( "MyTable", { id: varchar("id", { length: 191 }).notNull(), value: decimal("value", { precision: 7, scale: 4 }).notNull(), createdAt: datetime("created ...

NodeJS Express session data not retained following jQuery POST request

After struggling with this issue for quite some time, I have not found a solution that works for me. On my simple login page, the user's credentials are passed to the server for authentication and then stored in the session object: Here is an excerpt ...

Creating dynamic queries in Nodejs using MongoDB aggregation with both AND and OR conditions

I am facing an issue with MongoDB aggregation in my nodejs code. const query = { '$expr':{ '$and':[ {'$eq': ['$appId', req.user.appId]}, ] } } A filter object is coming from the frontend: { shops ...

Angular 6: Harnessing the Power of RouterLinks

Can you navigate to a different section of another page using the defined ID without having to reload the entire page? ...

Transferring pictures through Mandrill

Dealing with sending QR codes via email using Mandrill. Here's the progress so far: db.get(id, function (err, doc) { if (err) { fail('Couch', [err, doc]) } db.attachment.get(id, 'qr-code.png', function (error, image) { // ...

Leverage interceptors in Axios to utilize the Express request object

I have a dilemma with my express route. When I send a header from the front end, I execute a GET request using axios in this specific route. I've set up an interceptor with axios, but what I really need is to access the req object from the activated r ...

Using TypeScript with Redux for Form Validation in FieldArray

My first time implementing a FieldArray from redux-form has been quite a learning experience. The UI functions properly, but there seems to be some performance issues that I need to investigate further. Basically, the concept is to click an ADD button to i ...