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.
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();
});
});
});
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.
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
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.
Most helpful comment
@IanChok you connect to a mongo db as a side effect of importing the
controllerfile. 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.