Jest 检测到以下 1 个打开的句柄可能会阻止 Jest 退出:TCPSERVERWRAP
Jest has detected the following 1 open handle potentially keeping Jest from exiting: TCPSERVERWRAP
我在这里做一个基本的端到端测试,目前它失败了,但首先我无法摆脱打开的句柄。
Ran all test suites.
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPSERVERWRAP
40 | }
41 | return request(app.getHttpServer())
> 42 | .post('/graphql')
| ^
43 | .send(mutation)
44 | .expect(HttpStatus.OK)
45 | .expect((response) => {
at Test.Object.<anonymous>.Test.serverAddress (../node_modules/supertest/lib/test.js:61:33)
at new Test (../node_modules/supertest/lib/test.js:38:12)
at Object.obj.<computed> [as post] (../node_modules/supertest/index.js:27:14)
at Object.<anonymous> (app.e2e-spec.ts:42:8)
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
describe('AppController (e2e)', () => {
let app: INestApplication
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
})
afterAll(async () => {
await app.close()
})
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
it('mutation', async () => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
return request(app.getHttpServer())
.post('/graphql')
.send(mutation)
.expect(HttpStatus.OK)
.expect( (response) => {
expect(response.body).toBe({
id: expect.any(String),
title: 'Mon programme',
})
})
})
})
知道什么阻碍了测试运行程序吗?
请注意,由于我使用的是 NestJs,所以我不需要在测试结束时使用 .end(done)
方法。
PS: 显然我在这个问题上有很多代码,我需要添加更多细节,但不知道我还能说些什么。
您再次重新创建整个应用程序 beforeEach
,但仅在 afterAll
中将其拆除,这意味着您可能在此过程中泄漏了一些内存。您正在为 app 变量分配一个新实例,但很可能存在阻止垃圾收集器清除先前实例的隐藏引用 - 就像 request
函数获得的引用。
将 beforeEach
更改为 beforeAll
,您应该可以开始了。
我还没有找到完美的解决方案,但目前我采用了这个解决方法:
jest --config ./test/jest-e2e.json --forceExit
forceExit 选项以某种方式杀死 openHandles 并解锁所有内容。
然而,我仍在寻找处理该问题的“正确方法”。
而不是 it
尝试使用 test
并将 done
作为参数传递并调用它。这对我有用。
test('mutation', async (done) => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
const response = request(app.getHttpServer())
.post('/graphql')
.send(mutation)
expect(response).to.be(HttpStatus.Ok)
done()
})
// 每次测试
it('the description', (done) => {
request(app)
.get('/some-path')
.end(done);
});
这就是问题所在
it('/ (GET)', () => {
return request(app.getHttpServer())
^^^^^^^^^^^^^^^^^^^^^
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
服务器未关闭,测试后保持打开状态。您需要创建一个变量来引用实例并在每次测试后关闭它。
我只是花了几个小时试图弄清楚这一点。希望这对遇到类似问题的人有所帮助。
这是您的代码示例以及我的修复想法:
describe('AppController (e2e)', () => {
let app: INestApplication
let server: SERVER_TYPE
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
// Reference the server instance
server = app.getHttpServer()
})
afterEach(async () => {
await app.close()
// Close the server instance after each test
server.close()
})
it('/ (GET)', async () => {
// Make the request on the server instance
await return request(server)
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
此外,我注意到您正在使用 beforeEach
和 afterAll
。您每次都在为每个测试创建一个新应用程序,所以我认为这也可能导致 HTTP 服务器出现一些问题。不过我不确定。
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
beforeEach(() => {
...
})
afterEach(() => {
...
})
describe('tests', () => {
...
})
但是,这只是我的偏好,由您决定。 :)
更新:打算使用 beforeEach
而不是 beforeAll
因为我们需要在每次测试之前关闭服务器,而不是全局设置和拆卸。
更新 2:使用 async/await 否则,它将始终通过,因为请求是异步的并且不会完成,除非您等待它完成。
Toomuchrice4u 的回答对我很有帮助。我在组件使用的一项服务中有一个注销方法,所以我在 afterEach
中调用它,如下所示:
afterEach(async () => {
await userService.logout();
});
我在这里做一个基本的端到端测试,目前它失败了,但首先我无法摆脱打开的句柄。
Ran all test suites.
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPSERVERWRAP
40 | }
41 | return request(app.getHttpServer())
> 42 | .post('/graphql')
| ^
43 | .send(mutation)
44 | .expect(HttpStatus.OK)
45 | .expect((response) => {
at Test.Object.<anonymous>.Test.serverAddress (../node_modules/supertest/lib/test.js:61:33)
at new Test (../node_modules/supertest/lib/test.js:38:12)
at Object.obj.<computed> [as post] (../node_modules/supertest/index.js:27:14)
at Object.<anonymous> (app.e2e-spec.ts:42:8)
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
describe('AppController (e2e)', () => {
let app: INestApplication
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
})
afterAll(async () => {
await app.close()
})
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
it('mutation', async () => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
return request(app.getHttpServer())
.post('/graphql')
.send(mutation)
.expect(HttpStatus.OK)
.expect( (response) => {
expect(response.body).toBe({
id: expect.any(String),
title: 'Mon programme',
})
})
})
})
知道什么阻碍了测试运行程序吗?
请注意,由于我使用的是 NestJs,所以我不需要在测试结束时使用 .end(done)
方法。
PS: 显然我在这个问题上有很多代码,我需要添加更多细节,但不知道我还能说些什么。
您再次重新创建整个应用程序 beforeEach
,但仅在 afterAll
中将其拆除,这意味着您可能在此过程中泄漏了一些内存。您正在为 app 变量分配一个新实例,但很可能存在阻止垃圾收集器清除先前实例的隐藏引用 - 就像 request
函数获得的引用。
将 beforeEach
更改为 beforeAll
,您应该可以开始了。
我还没有找到完美的解决方案,但目前我采用了这个解决方法:
jest --config ./test/jest-e2e.json --forceExit
forceExit 选项以某种方式杀死 openHandles 并解锁所有内容。 然而,我仍在寻找处理该问题的“正确方法”。
而不是 it
尝试使用 test
并将 done
作为参数传递并调用它。这对我有用。
test('mutation', async (done) => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
const response = request(app.getHttpServer())
.post('/graphql')
.send(mutation)
expect(response).to.be(HttpStatus.Ok)
done()
})
// 每次测试
it('the description', (done) => {
request(app)
.get('/some-path')
.end(done);
});
这就是问题所在
it('/ (GET)', () => {
return request(app.getHttpServer())
^^^^^^^^^^^^^^^^^^^^^
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
服务器未关闭,测试后保持打开状态。您需要创建一个变量来引用实例并在每次测试后关闭它。 我只是花了几个小时试图弄清楚这一点。希望这对遇到类似问题的人有所帮助。
这是您的代码示例以及我的修复想法:
describe('AppController (e2e)', () => {
let app: INestApplication
let server: SERVER_TYPE
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
// Reference the server instance
server = app.getHttpServer()
})
afterEach(async () => {
await app.close()
// Close the server instance after each test
server.close()
})
it('/ (GET)', async () => {
// Make the request on the server instance
await return request(server)
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
此外,我注意到您正在使用 beforeEach
和 afterAll
。您每次都在为每个测试创建一个新应用程序,所以我认为这也可能导致 HTTP 服务器出现一些问题。不过我不确定。
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
beforeEach(() => {
...
})
afterEach(() => {
...
})
describe('tests', () => {
...
})
但是,这只是我的偏好,由您决定。 :)
更新:打算使用 beforeEach
而不是 beforeAll
因为我们需要在每次测试之前关闭服务器,而不是全局设置和拆卸。
更新 2:使用 async/await 否则,它将始终通过,因为请求是异步的并且不会完成,除非您等待它完成。
Toomuchrice4u 的回答对我很有帮助。我在组件使用的一项服务中有一个注销方法,所以我在 afterEach
中调用它,如下所示:
afterEach(async () => {
await userService.logout();
});