Jest 在使用 Express 完成测试运行后一秒钟都没有退出

我正在使用 JEST 对我的快速路线进行单元测试。

在运行 yarn test时,我的所有测试用例都通过了,但是我得到了一个错误

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.

我使用 asyncdone,但它仍然抛出上述错误。

下面是我的规格代码。请帮助

路线,规划

const request = require('supertest');
describe('Test the root path', () => {
const app = require('./index');


test('GET /gql/gql-communication-portal/release-notes', async (done) => {
const response = await request(app).get('/gql/gql-communication-portal/release-notes');
expect(response.status).toBe(200);
done();
});
});
87632 次浏览

我遇到了同样的问题,但是在 package.json 文件中,我添加了 "test": "jest --detectOpenHandles"并运行了 npm test --detectOpenHandles。这次我没有收到错误消息。也许你可以试试。

我的问题通过这个代码得到了解决:

beforeAll(done => {
done()
})


afterAll(done => {
// Closing the DB connection allows Jest to exit successfully.
mongoose.connection.close()
done()
})

对我来说,使用 supertest 来测试路由本身是一个不同的问题,所以我必须关闭到服务器本身的连接。

afterAll(done => {
server.close();
done();
});

你可以启动 server in before All block,然后关闭:

beforeAll(() => {
server = app.listen(someRandomNumberHere); // Random number is needed to avoid using same port in different tests if you run in parallel
})


afterAll(() => {
server.close()
})


如果这不是你的情况下,这个问题可能有你的东西

在我这边,我只是将 app.listen()从我的应用程序中分离出来。 因此,使用 Express,您的应用程序以导出结束。

// index.js
module.exports = app;

然后创建另一个文件来监听端口。

// server.js
const app = require('./index')
app.listen(...)

如果您只导入测试中的索引(应用程序 index.js) ,那么它应该不需要额外的配置就可以工作。 当然,您需要调整您的快递应用程序的开始。它现在应该使用 server.js

这招对我很管用

const mongoose = require('mongoose');
afterAll(async(done) => {
// Closing the DB connection allows Jest to exit successfully.
try {
await mongoose.connection.close();
done()
} catch (error) {
console.log(error);
done()
}
// done()
})

对于 Firebase,我必须调用 clean up ()

import {
assertFails,
assertSucceeds,
initializeTestEnvironment,
RulesTestEnvironment,
} from "@firebase/rules-unit-testing";
import { doc, setDoc } from "firebase/firestore";


it('creates a new user document in firebase', async () => {
const testEnv = await initializeTestEnvironment({
projectId: "appname-test",
firestore: {
host: 'localhost',
port: 8088
}
});


const alice = testEnv.authenticatedContext("alice");


await assertSucceeds(setDoc(doc(alice.firestore(), "users", "alice"), {
fname: "Alice",
lname: "Wonderland",
dob: "18/01/1999",
email: "alice@example.com"
}));


return await testEnv.cleanup();
});

添加

jest.useFakeTimers();

在测试套件开始的时候为我修好了它。

可能来自渲染组件部分中定义的计时器(如节流按钮、模拟等)。

我已经将这一行添加到 package.json

这招对我很管用

jest --runInBand --detectOpenHandles --forceExit

你可以试试这个

“ test”: “ jest —— runInBand —— force-exit”

我遇到了同样的问题,但是,我正在使用我的 NodeJSExpress 应用程序的 pg模块。我想为那些使用这个堆栈的人也张贴这个,如果它能帮助他们。

从本质上讲,supertest创建了一个服务器连接,有些人可能会得到 TCPSERVERWRAP 错误,因为它没有关闭,无论我使用的是异步/等待还是 jest done回调。每次测试后都要关闭。最重要的是,数据库连接仍然是打开的,所以我对它进行了模拟。

关闭服务器连接和模拟 pg一起为我解决了这个错误。

products.tests.ts

import request from 'supertest'
import { Pool } from 'pg'
import app from '../app'
import type { Server } from 'http'


jest.mock('pg')


const { ROUTE_VERSION = '/v1' } = process.env
const route = (path: string) => [ROUTE_VERSION, path].join('')
const pool = new Pool()
let server: Server


beforeEach(() => {
server = app.listen(4000)
})


afterEach(() => {
server.close()
})


describe('GET /products', () => {
it('returns array of products', async () => {
await request(server)
.get(route('/products'))
.expect(200)
.expect((res) => {
expect(pool.query).toBeCalledTimes(1)
expect(res.body).toBeInstanceOf(Array)
expect(res.body).not.toHaveLength(0)
})
})
})

更新: 意味着在每次测试后使用 beforeEachafterEach关闭服务器,否则,它仍然像以前一样打开。

更新2: 如果不使用异步/等待,它总是会通过,因为 request是异步的,并且除非您等待它完成,否则它不会完成。

您的 app.listen块可以被包装成以下条件:

if (require.main === module) {
// ...
}

例如:

// index.js


import express from "express";


const app = express();


app.get("/", (req, res) => {
res.status(200).json({});
});


app.get("/toppings", (req, res) => {
res.status(200).json({});
});


if (require.main === module) {
app.listen(5050, () => {
console.log("Server is listening on port 5050");
});
}


export default app;
// index.test.js


import request from "supertest";
import app from "./index";


let server;


describe("test server", () => {
beforeEach(async () => {
server = await app.listen(4040); // Can be any port
global.agent = request.agent(server);
});
afterEach(async () => {
await server.close();
});


describe("connection", () => {
it("responds with status 200", () => {
return request(server)
.get("/")
.then((response) => {
expect(response.statusCode).toBe(200);
});
});
});
});