Jest: ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

Created on 6 May 2020  ·  10Comments  ·  Source: facebook/jest

🐛 Bug Report

ReferenceError: You are trying to 'import' a file after the Jest environment has been torn down. when trying to test Express API with Jest and Supertest.

Log:

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

      at BufferList.Readable (node_modules/readable-stream/lib/_stream_readable.js:179:22)
      at BufferList.Duplex (node_modules/readable-stream/lib/_stream_duplex.js:67:12)
      at new BufferList (node_modules/bl/bl.js:33:16)
      at new MessageStream (node_modules/mongodb/lib/cmap/message_stream.js:35:21)
      at new Connection (node_modules/mongodb/lib/cmap/connection.js:49:28)
C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111
  var isDuplex = stream instanceof Duplex;
                        ^

TypeError: Right-hand side of 'instanceof' is not callable
    at new ReadableState (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111:25)
    at BufferList.Readable (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:183:25)
    at BufferList.Duplex (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_duplex.js:67:12)
    at new BufferList (C:\Users\ichok\Desktop\...\Server\node_modules\bl\bl.js:33:16)
    at new MessageStream (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\message_stream.js:35:21)
    at new Connection (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\connection.js:49:28)
    at C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:35:29
    at callback (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:264:5)
    at TLSSocket.connectHandler (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:309:5)
    at Object.onceWrapper (events.js:416:28)
npm ERR! Test failed.  See above for more details.

To Reproduce

app.ts:

import Express from 'express';
import BodyParser from 'body-parser';
import Controller from './controller';
import jwt from 'jsonwebtoken';
import cookieParser from 'cookie-parser';
/** few other imports */

const app = Express();
const jwtSecret = process.env.TOKEN_SIGNING_SECRET;

app.use(BodyParser.json()); // for parsing application/json
app.use(BodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(cookieParser());

// For testing
app.get("/", (req, res) => {
    res.status(200).send("Hello World!");
  });

module.exports = app;

app.test.ts:

const request = require("supertest");
const app = require("../app");

describe("Test the root path", () => {
  test("It should response the GET method", (done) => {
    request(app)
      .get("/")
      .then(response => {
        expect(response.statusCode).toBe(200);
        done();
      });
  });
});

Expected behavior

The test passes, but is getting the error still.


 PASS  src/tests/app.test.ts
  Test the root path
    √ It should response the GET method (17 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.87 s, estimated 2 s
Ran all test suites.

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

      at BufferList.Readable (node_modules/readable-stream/lib/_stream_readable.js:179:22)
      at BufferList.Duplex (node_modules/readable-stream/lib/_stream_duplex.js:67:12)
      at new BufferList (node_modules/bl/bl.js:33:16)
      at new MessageStream (node_modules/mongodb/lib/cmap/message_stream.js:35:21)
      at new Connection (node_modules/mongodb/lib/cmap/connection.js:49:28)
C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111
  var isDuplex = stream instanceof Duplex;
                        ^

TypeError: Right-hand side of 'instanceof' is not callable
    at new ReadableState (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111:25)
    at BufferList.Readable (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:183:25)
    at BufferList.Duplex (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_duplex.js:67:12)
    at new BufferList (C:\Users\ichok\Desktop\...\Server\node_modules\bl\bl.js:33:16)
    at new MessageStream (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\message_stream.js:35:21)
    at new Connection (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\connection.js:49:28)
    at C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:35:29
    at callback (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:264:5)
    at TLSSocket.connectHandler (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:309:5)
    at Object.onceWrapper (events.js:416:28)
npm ERR! Test failed.  See above for more details.

envinfo

npx: installed 1 in 1.101s

  System:
    OS: Windows 10 10.0.18363
    CPU: (2) x64 Intel(R) Core(TM) i7-8665U CPU @ 1.90GHz
  Binaries:
    Node: 12.16.2 - C:\Program Files\nodejs\node.EXE
    npm: 6.14.4 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    jest: ^26.0.0 => 26.0.0
Bug Report Needs Repro Needs Triage

Most helpful comment

@IanChok you connect to a mongo db as a side effect of importing the controller file. You need to wait for this promise, and after your test has completed you need to tear it down. Jest cannot know that you are doing async stuff without telling it.

See e.g. https://jestjs.io/docs/en/mongodb which closes down both the connection and db within the test. You don't need to use the preset at all, but you need to have the cleanup logic illustrated.

All 10 comments

Could you put together a full reproduction we can pull down and run to see the error?

@SimenB https://github.com/IanChok/jest-debug

The error seems to be coming from when I'm trying to connect to MongoDB. I'm not sure why though 🤔 Any help would be appreciated 🙇

Interestingly I get a similar error after upgrading from 25.4.0 to any newer version:

ReferenceError: You are trying to 'import' a file after the Jest environment has been torn down.

      at handleResolved (node_modules/promise/lib/core.js:113:3)
      at handle (node_modules/promise/lib/core.js:109:3)
      at finale (node_modules/promise/lib/core.js:175:5)
      at reject (node_modules/promise/lib/core.js:171:3)
      at node_modules/promise/lib/core.js:125:7

 RUNS  src/screens/app/home/overview/purchase-statistics.spec.ts
/Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:113
  require('asap/raw')(function () {
                     ^

TypeError: require(...) is not a function
    at handleResolved (/Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:113:22)
    at handle (/Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:109:3)
    at finale (/Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:175:5)
    at reject (/Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:171:3)
    at /Users/matthias/Documents/warrify/app/node_modules/promise/lib/core.js:125:7
    at flush (/Users/matthias/Documents/warrify/app/node_modules/asap/raw.js:50:25)
    at processTicksAndRejections (internal/process/task_queues.js:79:11)

this is in a react-native project.

u can try it when test environment.
MongoDB: useUnifiedTopology: false and remove schema.plugin();

thx @deot . useUnifiedTopology: false helped for me

Setting useUnifiedTopology: false gets rid of the ReferenceError, but it's going to be deprecated.

DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.

@IanChok you connect to a mongo db as a side effect of importing the controller file. You need to wait for this promise, and after your test has completed you need to tear it down. Jest cannot know that you are doing async stuff without telling it.

See e.g. https://jestjs.io/docs/en/mongodb which closes down both the connection and db within the test. You don't need to use the preset at all, but you need to have the cleanup logic illustrated.

@SimenB The issue still arises even after I configured the setup and teardown only when I specify { useUnifiedTopology: true} in the mongo client.

For E.g.,
Test file:

const Controller = require('../controller').getInstance();
describe('Controller Tests', () => {
    const dbName = '...';
    const collectionName = 'users';

    beforeAll(async () => {
        await Controller.connectToDb();
    });

    afterAll(async () => {
        await Controller.closeDbConnection();
    })

    it('should create new class with default constructor', async () => {
        expect(Controller.getDbname()).toBe(dbName)
        expect(Controller.getCollectionName()).toBe(collectionName);
    });

    it('should get db instance', async () => {
        const instance = Controller.getDbInstance();
        expect(instance.databaseName).toBe(dbName);

        const dbTest = 'dbTest';
        const instance2 = Controller.getDbInstance(dbTest);
        expect(instance2.databaseName).toBe(dbTest);
    });
});

In Controller, if const mongoClient = new MongoClient(url, { useUnifiedTopology: true});

//Controller
  public async connectToDb(currentAttempt = 1, maxAttempt = 3) {
        const mongoClient = new MongoClient(url, { useUnifiedTopology: true });
        log(`Attempting to connect to database ${this.dbName} as ${usernameDb}`);
        this.mongoClient = await mongoClient.connect();
        try {
            log(`Connected to ${this.dbName} as ${usernameDb}`)
            this.dbInstance = mongoClient.db(this.dbName);
            this.dbInfo = { dbInstance: this.dbInstance, dbName: this.dbName, collectionName: this.collectionName };
        }
        catch{
            (err) => {
                if (currentAttempt <= maxAttempt) {
                    log(`Failed to connect. Attempting to reconnect (#${currentAttempt} of ${maxAttempt})`);
                    this.connectToDb(currentAttempt + 1, maxAttempt);
                } else {
                    log(`Failed to connect to db after ${maxAttempt} attempts. Aborting.`);
                    console.error(err);
                    process.exit(1);
                }
            }
        };
    }

Result:


Test Suites: 2 passed, 2 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        2.757 s, estimated 3 s
Ran all test suites.

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

      at BufferList.Readable (node_modules/readable-stream/lib/_stream_readable.js:179:22)
      at BufferList.Duplex (node_modules/readable-stream/lib/_stream_duplex.js:67:12)
      at new BufferList (node_modules/bl/bl.js:33:16)
      at new MessageStream (node_modules/mongodb/lib/cmap/message_stream.js:35:21)
      at new Connection (node_modules/mongodb/lib/cmap/connection.js:49:28)
C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111
  var isDuplex = stream instanceof Duplex;
                        ^

TypeError: Right-hand side of 'instanceof' is not callable
    at new ReadableState (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:111:25)
    at BufferList.Readable (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_readable.js:183:25)
    at BufferList.Duplex (C:\Users\ichok\Desktop\...\Server\node_modules\readable-stream\lib\_stream_duplex.js:67:12)
    at new BufferList (C:\Users\ichok\Desktop\...\Server\node_modules\bl\bl.js:33:16)
    at new MessageStream (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\message_stream.js:35:21)
    at new Connection (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\cmap\connection.js:49:28)
    at C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:35:29
    at callback (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:264:5)
    at TLSSocket.connectHandler (C:\Users\ichok\Desktop\...\Server\node_modules\mongodb\lib\core\connection\connect.js:309:5)
    at Object.onceWrapper (events.js:416:28)
npm ERR! Test failed.  See above for more details.

With: const mongoClient = new MongoClient(url);

//Controller
  public async connectToDb(currentAttempt = 1, maxAttempt = 3) {
        const mongoClient = new MongoClient(url);
        log(`Attempting to connect to database ${this.dbName} as ${usernameDb}`);
        this.mongoClient = await mongoClient.connect();
        try {
            log(`Connected to ${this.dbName} as ${usernameDb}`)
            this.dbInstance = mongoClient.db(this.dbName);
            this.dbInfo = { dbInstance: this.dbInstance, dbName: this.dbName, collectionName: this.collectionName };
        }
        catch{
            (err) => {
                if (currentAttempt <= maxAttempt) {
                    log(`Failed to connect. Attempting to reconnect (#${currentAttempt} of ${maxAttempt})`);
                    this.connectToDb(currentAttempt + 1, maxAttempt);
                } else {
                    log(`Failed to connect to db after ${maxAttempt} attempts. Aborting.`);
                    console.error(err);
                    process.exit(1);
                }
            }
        };
    }

Result:

Test Suites: 2 passed, 2 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        3.265 s
Ran all test suites.
(node:5904) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.

  ●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "(5/10/2020, 12:48:01 PM) Connected to ... as dbAdmin".

      1 | export function log(message: string) {
    > 2 |     console.log(`(${new Date().toLocaleString()}) ${message}`);
        |             ^
      3 | }
      4 |
      5 | export function debug(message: any) {

      at BufferedConsole.log (node_modules/@jest/console/build/BufferedConsole.js:201:10)
      at log (src/errors.ts:2:13)
      at Controller.connectToDb (src/controller.ts:157:13)

So I'm still not sure if there's additional setup and teardown that's not documented / I'm missing, or if this is a MongoDB issue.

edit: I found jest --forceExit helps get rid of the error messages. 🤷‍♂️

After test, mongoDB should close. (Mongoose: db.disconnect())

--forceExit ignores the problem - your test is inherently flaky and depends on specific timing.

You want something like this

diff --git i/src/controller.ts w/src/controller.ts
index 404bcc1..24b5acf 100644
--- i/src/controller.ts
+++ w/src/controller.ts
@@ -5,6 +5,8 @@ const passwordDb = process.env.MONGODB_PASSWORD;
 const url = `mongodb+srv://${usernameDb}:${passwordDb}@cluster0-jlp3r.mongodb.net/test?retryWrites=true&w=majority`;

 class Controller {
+    private mongoClient: MongoClient = undefined;
+    private connectionPromise: Promise<void>;
     private dbInstance: Db = undefined;
     private dbName: string = undefined;
     private collectionName: string = undefined;
@@ -12,22 +14,30 @@ class Controller {
     constructor(dbName = '...', collectionName = '...') {
         this.dbName = dbName;
         this.collectionName = collectionName;
-        this.connectToDb(1, 3);
+        this.connectionPromise = this.connectToDb(1, 3);
     };

     public getdbName(){
         return this.dbName;
     }

+    public async waitForSetup() {
+        await this.connectionPromise;
+    }
+
+    public async teardown() {
+        await this.mongoClient.close()
+    }
+
     // This method is causing the error
     private connectToDb(currentAttempt: number, maxAttempt: number) {
-        const mongoClient = new MongoClient(url, { useUnifiedTopology: true });
-        mongoClient.connect().then(() => {
+        this.mongoClient = new MongoClient(url, { useUnifiedTopology: true });
+        return this.mongoClient.connect().then(() => {
             console.log(`Connected to ${this.dbName} as ${usernameDb}`)
-            this.dbInstance = mongoClient.db(this.dbName);
+            this.dbInstance = this.mongoClient.db(this.dbName);
         }).catch((err) => {
             if (currentAttempt <= maxAttempt) {
-                this.connectToDb(currentAttempt + 1, maxAttempt);
+                return this.connectToDb(currentAttempt + 1, maxAttempt);
             } else {
                 console.error(err);
                 process.exit(1);
diff --git i/src/tests/app.test.ts w/src/tests/app.test.ts
index ef4fb50..b0a5e63 100644
--- i/src/tests/app.test.ts
+++ w/src/tests/app.test.ts
@@ -1,13 +1,19 @@
+const Controller = require('../controller').default;
 const request = require("supertest");
 const app = require("../app");

 describe("Test the root path", () => {
-  test("It should response the GET method", (done) => {
-    request(app)
+  beforeAll(async () => {
+    await Controller.waitForSetup()
+  })
+  afterAll(async () => {
+    await Controller.teardown()
+  })
+  test("It should response the GET method", async () => {
+    await request(app)
       .get("/")
       .then(response => {
         expect(response.statusCode).toBe(200);
-        done();
       });
   });
 });
\ No newline at end of file

It never connects on my machine (times out) so you might need something more but that's the gist of it.


Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

Was this page helpful?
0 / 5 - 0 ratings