MetaMask / MetaMask/core

Ensure all async operations are completed before tests end

Open
#493 0 comments 0 reactions 0 assignees View on GitHub
team-wallet-framework wf-bugs
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.