Ensure all async operations are completed before tests end
- Dominant language
- TypeScript
- Stars
- 413
- Forks
- 308
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 253
Description
For some time, Jest has been complaining about unfinished async operations when tests end. The recommended way to understand what those operations are is the `--detectOpenHandles` flag, which is broken prior to `jest@^27`. After locally bumping to that major version of Jest, I discovered that the uncompleted operations are timeouts and network calls, in `AssetsDetectionController`, `PhishingController`, and `AccountTrackerController`. See below for details.
Click for detailsJest has detected the following 8 open handles potentially keeping Jest from exiting:
● Timeout
575 | successfulFetch(url, options),
576 | new Promise((_, reject) =>
> 577 | setTimeout(() => {
| ^
578 | reject(new Error('timeout'));
579 | }, timeout),
580 | ),
at src/util.ts:577:7
at Object. (src/util.ts:576:5)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.timeoutFetch (src/util.ts:7663:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:159:26)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.getOwnerCollectibles (src/assets/AssetsDetectionController.ts:77:16)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:365:42)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at src/assets/AssetsDetectionController.ts:364:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:364:11)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.detectCollectibles (src/assets/AssetsDetectionController.ts:191:16)
at src/assets/AssetsDetectionController.test.ts:248:27
at src/assets/AssetsDetectionController.test.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.test.ts:4:12)
at Object. (src/assets/AssetsDetectionController.test.ts:246:65)
● Timeout
575 | successfulFetch(url, options),
576 | new Promise((_, reject) =>
> 577 | setTimeout(() => {
| ^
578 | reject(new Error('timeout'));
579 | }, timeout),
580 | ),
at src/util.ts:577:7
at Object. (src/util.ts:576:5)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.timeoutFetch (src/util.ts:7663:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:159:26)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.getOwnerCollectibles (src/assets/AssetsDetectionController.ts:77:16)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:365:42)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at src/assets/AssetsDetectionController.ts:364:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:364:11)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.detectCollectibles (src/assets/AssetsDetectionController.ts:191:16)
at src/assets/AssetsDetectionController.test.ts:292:27
at src/assets/AssetsDetectionController.test.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.test.ts:4:12)
at Object. (src/assets/AssetsDetectionController.test.ts:290:84)
at runMicrotasks ()
● Timeout
575 | successfulFetch(url, options),
576 | new Promise((_, reject) =>
> 577 | setTimeout(() => {
| ^
578 | reject(new Error('timeout'));
579 | }, timeout),
580 | ),
at src/util.ts:577:7
at Object. (src/util.ts:576:5)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.timeoutFetch (src/util.ts:7663:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:159:26)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.getOwnerCollectibles (src/assets/AssetsDetectionController.ts:77:16)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:365:42)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at src/assets/AssetsDetectionController.ts:364:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:364:11)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.detectCollectibles (src/assets/AssetsDetectionController.ts:191:16)
at src/assets/AssetsDetectionController.test.ts:316:21
at src/assets/AssetsDetectionController.test.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.test.ts:4:12)
at Object. (src/assets/AssetsDetectionController.test.ts:310:88)
at runMicrotasks ()
● Timeout
575 | successfulFetch(url, options),
576 | new Promise((_, reject) =>
> 577 | setTimeout(() => {
| ^
578 | reject(new Error('timeout'));
579 | }, timeout),
580 | ),
at src/util.ts:577:7
at Object. (src/util.ts:576:5)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.timeoutFetch (src/util.ts:7663:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:159:26)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.getOwnerCollectibles (src/assets/AssetsDetectionController.ts:77:16)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:365:42)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at src/assets/AssetsDetectionController.ts:364:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at AssetsDetectionController. (src/assets/AssetsDetectionController.ts:364:11)
at src/assets/AssetsDetectionController.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.ts:4:12)
at AssetsDetectionController.detectCollectibles (src/assets/AssetsDetectionController.ts:191:16)
at src/assets/AssetsDetectionController.test.ts:371:27
at src/assets/AssetsDetectionController.test.ts:8:71
at Object..__awaiter (src/assets/AssetsDetectionController.test.ts:4:12)
at Object. (src/assets/AssetsDetectionController.test.ts:324:116)
● TLSWRAP
151 | input: RequestInfo,
152 | ): Promise {
> 153 | const response = await fetch(input, { cache: 'no-cache' });
| ^
154 |
155 | switch (response.status) {
156 | case 200: {
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/node-fetch/lib/index.js:1438:15
at fetch (node_modules/node-fetch/lib/index.js:1407:9)
at Object..module.exports (node_modules/isomorphic-fetch/fetch-npm-node.js:8:19)
at PhishingController. (src/third-party/PhishingController.ts:153:28)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.queryConfig (src/third-party/PhishingController.ts:106:16)
at PhishingController. (src/third-party/PhishingController.ts:141:37)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.updatePhishingLists (src/third-party/PhishingController.ts:92:16)
at src/third-party/PhishingController.ts:99:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at PhishingController. (src/third-party/PhishingController.ts:99:11)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.poll (src/third-party/PhishingController.ts:53:16)
at new PhishingController (src/third-party/PhishingController.ts:88:10)
at Object. (src/third-party/PhishingController.test.ts:12:24)
● TLSWRAP
151 | input: RequestInfo,
152 | ): Promise {
> 153 | const response = await fetch(input, { cache: 'no-cache' });
| ^
154 |
155 | switch (response.status) {
156 | case 200: {
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/node-fetch/lib/index.js:1438:15
at fetch (node_modules/node-fetch/lib/index.js:1407:9)
at Object..module.exports (node_modules/isomorphic-fetch/fetch-npm-node.js:8:19)
at PhishingController. (src/third-party/PhishingController.ts:153:28)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.queryConfig (src/third-party/PhishingController.ts:106:16)
at PhishingController. (src/third-party/PhishingController.ts:141:37)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.updatePhishingLists (src/third-party/PhishingController.ts:92:16)
at src/third-party/PhishingController.ts:99:36
at Object. (src/util.ts:238:18)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecute (src/util.ts:6862:10)
at PhishingController. (src/third-party/PhishingController.ts:99:11)
at src/third-party/PhishingController.ts:8:71
at Object..__awaiter (src/third-party/PhishingController.ts:4:12)
at PhishingController.poll (src/third-party/PhishingController.ts:53:16)
at new PhishingController (src/third-party/PhishingController.ts:88:10)
at Object. (src/third-party/PhishingController.test.ts:20:24)
● TLSWRAP
620 | ): Promise {
621 | return new Promise((resolve, reject) => {
> 622 | ethQuery[method](...args, (error: Error, result: any) => {
| ^
623 | if (error) {
624 | reject(error);
625 | return;
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at XMLHttpRequest.Object..XMLHttpRequest._sendHxxpRequest (node_modules/xhr2/lib/xhr2.js:389:22)
at XMLHttpRequest.Object..XMLHttpRequest._sendHttp (node_modules/xhr2/lib/xhr2.js:376:12)
at XMLHttpRequest.Object..XMLHttpRequest.send (node_modules/xhr2/lib/xhr2.js:202:16)
at HttpProvider.Object..HttpProvider.sendAsync (node_modules/ethjs-provider-http/lib/index.js:100:13)
at EthQuery.Object..EthQuery.sendAsync (node_modules/eth-query/index.js:66:24)
at EthQuery.getBalance (node_modules/eth-query/index.js:94:10)
at src/util.ts:622:25
at Object.query (src/util.ts:621:10)
at AccountTrackerController. (src/assets/AccountTrackerController.ts:154:31)
at src/assets/AccountTrackerController.ts:8:71
at Object..__awaiter (src/assets/AccountTrackerController.ts:4:12)
at src/assets/AccountTrackerController.ts:153:49
at Object. (src/util.ts:265:7)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecuteWithTimeout (src/util.ts:6917:10)
at AccountTrackerController. (src/assets/AccountTrackerController.ts:153:13)
at src/assets/AccountTrackerController.ts:8:71
at Object..__awaiter (src/assets/AccountTrackerController.ts:4:12)
at AccountTrackerController.refresh (src/assets/AccountTrackerController.ts:149:24)
at src/assets/AccountTrackerController.test.ts:43:22
at src/assets/AccountTrackerController.test.ts:8:71
at Object..__awaiter (src/assets/AccountTrackerController.test.ts:4:12)
at Object. (src/assets/AccountTrackerController.test.ts:32:44)
● TLSWRAP
620 | ): Promise {
621 | return new Promise((resolve, reject) => {
> 622 | ethQuery[method](...args, (error: Error, result: any) => {
| ^
623 | if (error) {
624 | reject(error);
625 | return;
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at node_modules/nock/lib/intercept.js:427:16
at Object.module.request (node_modules/nock/lib/common.js:95:14)
at XMLHttpRequest.Object..XMLHttpRequest._sendHxxpRequest (node_modules/xhr2/lib/xhr2.js:389:22)
at XMLHttpRequest.Object..XMLHttpRequest._sendHttp (node_modules/xhr2/lib/xhr2.js:376:12)
at XMLHttpRequest.Object..XMLHttpRequest.send (node_modules/xhr2/lib/xhr2.js:202:16)
at HttpProvider.Object..HttpProvider.sendAsync (node_modules/ethjs-provider-http/lib/index.js:100:13)
at EthQuery.Object..EthQuery.sendAsync (node_modules/eth-query/index.js:66:24)
at EthQuery.getBalance (node_modules/eth-query/index.js:94:10)
at src/util.ts:622:25
at Object.query (src/util.ts:621:10)
at AccountTrackerController. (src/assets/AccountTrackerController.ts:154:31)
at src/assets/AccountTrackerController.ts:8:71
at Object..__awaiter (src/assets/AccountTrackerController.ts:4:12)
at src/assets/AccountTrackerController.ts:153:49
at Object. (src/util.ts:265:7)
at src/util.ts:6357:40
at Object..__awaiter (src/util.ts:6300:10)
at Object.safelyExecuteWithTimeout (src/util.ts:6917:10)
at AccountTrackerController. (src/assets/AccountTrackerController.ts:153:13)
at src/assets/AccountTrackerController.ts:8:71
at Object..__awaiter (src/assets/AccountTrackerController.ts:4:12)
at AccountTrackerController.refresh (src/assets/AccountTrackerController.ts:149:24)
at Object. (src/assets/AccountTrackerController.test.ts:63:16)
at runMicrotasks ()
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by running the Jest tests with --detectOpenHandles after reviewing src/util.ts and the stack traces in AssetsDetectionController, PhishingController, and AccountTrackerController. Inspect the corresponding controller tests, including src/assets/AssetsDetectionController.test.ts and src/third-party/PhishingController.test.ts. Done means the tests complete without unfinished timeouts or network handles.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100