diff --git a/app/scripts/controllers/network/network-controller.test.ts b/app/scripts/controllers/network/network-controller.test.ts index 41d851745..0a5df1f6f 100644 --- a/app/scripts/controllers/network/network-controller.test.ts +++ b/app/scripts/controllers/network/network-controller.test.ts @@ -2632,33 +2632,106 @@ describe('NetworkController', () => { describe('rollbackToPreviousProvider', () => { for (const { networkType } of INFURA_NETWORKS) { describe(`if the previous provider configuration had a type of "${networkType}"`, () => { + it('emits networkWillChange', async () => { + await withController( + { + state: { + providerConfig: buildProviderConfig({ + type: networkType, + }), + networkConfigurations: { + testNetworkConfiguration: { + id: 'testNetworkConfiguration', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), + ticker: 'TEST', + nickname: 'test network', + rpcPrefs: { + blockExplorerUrl: 'https://test-block-explorer.com', + }, + }, + }, + }, + }, + async ({ controller, messenger }) => { + const fakeProvider = buildFakeProvider(); + const fakeNetworkClient = buildFakeClient(fakeProvider); + mockCreateNetworkClient().mockReturnValue(fakeNetworkClient); + await controller.setActiveNetwork('testNetworkConfiguration'); + + const networkWillChange = waitForPublishedEvents({ + messenger, + eventType: 'NetworkController:networkWillChange', + operation: () => { + // Intentionally not awaited because we're capturing an event + // emitted partway through the operation + controller.rollbackToPreviousProvider(); + }, + }); + + await expect(networkWillChange).toBeFulfilled(); + }, + ); + }); + + it('emits networkDidChange', async () => { + await withController( + { + state: { + providerConfig: buildProviderConfig({ + type: networkType, + }), + networkConfigurations: { + testNetworkConfiguration: { + id: 'testNetworkConfiguration', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), + ticker: 'TEST', + nickname: 'test network', + rpcPrefs: { + blockExplorerUrl: 'https://test-block-explorer.com', + }, + }, + }, + }, + }, + async ({ controller, messenger }) => { + const fakeProvider = buildFakeProvider(); + const fakeNetworkClient = buildFakeClient(fakeProvider); + mockCreateNetworkClient().mockReturnValue(fakeNetworkClient); + await controller.setActiveNetwork('testNetworkConfiguration'); + + const networkDidChange = waitForPublishedEvents({ + messenger, + eventType: 'NetworkController:networkDidChange', + operation: () => { + // Intentionally not awaited because we're capturing an event + // emitted partway through the operation + controller.rollbackToPreviousProvider(); + }, + }); + + await expect(networkDidChange).toBeFulfilled(); + }, + ); + }); + it('overwrites the the current provider configuration with the previous provider configuration', async () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID - // of the network selected, it just needs to exist - chainId: '0x111', - // NOTE: This doesn't need to match the logical chain ID - // of the network selected, it just needs to exist - rpcUrl: 'https://mock-rpc-url-1', - ticker: 'TEST1', - nickname: 'test network 1', - rpcPrefs: { - blockExplorerUrl: 'https://test-block-explorer-1.com', - }, - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', - rpcUrl: 'https://mock-rpc-url-2', - chainId: '0x222', - ticker: 'TEST2', - nickname: 'test network 2', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), + ticker: 'TEST', + nickname: 'test network', rpcPrefs: { - blockExplorerUrl: 'https://test-block-explorer-2.com', + blockExplorerUrl: 'https://test-block-explorer.com', }, }, }, @@ -2673,8 +2746,8 @@ describe('NetworkController', () => { ]; mockCreateNetworkClient() .calledWith({ - rpcUrl: 'https://mock-rpc-url-2', - chainId: '0x222', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -2688,111 +2761,38 @@ describe('NetworkController', () => { expect(controller.store.getState().providerConfig).toStrictEqual({ type: 'rpc', id: 'testNetworkConfiguration', - rpcUrl: 'https://mock-rpc-url-2', - chainId: '0x222', - ticker: 'TEST2', - nickname: 'test network 2', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), + ticker: 'TEST', + nickname: 'test network', rpcPrefs: { - blockExplorerUrl: 'https://test-block-explorer-2.com', + blockExplorerUrl: 'https://test-block-explorer.com', }, }); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); - expect(controller.store.getState().providerConfig).toStrictEqual({ - type: networkType, - chainId: '0x111', - rpcUrl: 'https://mock-rpc-url-1', - ticker: 'TEST1', - nickname: 'test network 1', - rpcPrefs: { - blockExplorerUrl: 'https://test-block-explorer-1.com', - }, - }); + expect(controller.store.getState().providerConfig).toStrictEqual( + buildProviderConfig({ + type: networkType, + }), + ); }, ); }); - it('emits networkWillChange', async () => { + it('resets the network status to "unknown" before updating the provider', async () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', - ticker: 'TEST', - }, - }, - }, - infuraProjectId: 'some-infura-project-id', - }, - async ({ controller, messenger }) => { - const fakeProviders = [buildFakeProvider(), buildFakeProvider()]; - const fakeNetworkClients = [ - buildFakeClient(fakeProviders[0]), - buildFakeClient(fakeProviders[1]), - ]; - mockCreateNetworkClient() - .calledWith({ - rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', - type: NetworkClientType.Custom, - }) - .mockReturnValue(fakeNetworkClients[0]) - .calledWith({ - network: networkType, - infuraProjectId: 'some-infura-project-id', - type: NetworkClientType.Infura, - }) - .mockReturnValue(fakeNetworkClients[1]); - await controller.setActiveNetwork('testNetworkConfiguration'); - - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - const networkWillChange = await waitForPublishedEvents({ - messenger, - eventType: 'NetworkController:networkWillChange', - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - - expect(networkWillChange).toBeTruthy(); - }, - }); - }, - ); - }); - - it('resets the network status to "unknown" before emitting networkDidChange', async () => { - await withController( - { - state: { - providerConfig: { - type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, - networkConfigurations: { - testNetworkConfiguration: { - id: 'testNetworkConfiguration', - rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, @@ -2824,7 +2824,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -2839,54 +2839,42 @@ describe('NetworkController', () => { 'available', ); - await waitForLookupNetworkToComplete({ + await waitForStateChanges({ controller, - operation: async () => { - await waitForStateChanges({ - controller, - propertyPath: ['networkStatus'], - // We only care about the first state change, because it - // happens before networkDidChange - count: 1, - operation: () => { - // Intentionally not awaited because we want to check state - // while this operation is in-progress - controller.rollbackToPreviousProvider(); - }, - beforeResolving: () => { - expect(controller.store.getState().networkStatus).toBe( - 'unknown', - ); - }, - }); + propertyPath: ['networkStatus'], + // We only care about the first state change, because it + // happens before networkDidChange + count: 1, + operation: () => { + // Intentionally not awaited because we want to check state + // while this operation is in-progress + controller.rollbackToPreviousProvider(); + }, + beforeResolving: () => { + expect(controller.store.getState().networkStatus).toBe( + 'unknown', + ); }, }); }, ); }); - it('clears EIP-1559 support for the network from state before emitting networkDidChange', async () => { + it('clears EIP-1559 support for the network from state before updating the provider', async () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, - networkDetails: { - EIPS: {}, - other: 'details', - }, }, infuraProjectId: 'some-infura-project-id', }, @@ -2911,7 +2899,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -2928,27 +2916,22 @@ describe('NetworkController', () => { }, }); - await waitForLookupNetworkToComplete({ + await waitForStateChanges({ controller, - operation: async () => { - await waitForStateChanges({ - controller, - propertyPath: ['networkDetails'], - // We only care about the first state change, because it - // happens before networkDidChange - count: 1, - operation: () => { - // Intentionally not awaited because we want to check state - // while this operation is in-progress - controller.rollbackToPreviousProvider(); - }, - beforeResolving: () => { - expect( - controller.store.getState().networkDetails, - ).toStrictEqual({ - EIPS: {}, - }); - }, + propertyPath: ['networkDetails'], + // We only care about the first state change, because it + // happens before networkDidChange + count: 1, + operation: () => { + // Intentionally not awaited because we want to check state + // while this operation is in-progress + controller.rollbackToPreviousProvider(); + }, + beforeResolving: () => { + expect( + controller.store.getState().networkDetails, + ).toStrictEqual({ + EIPS: {}, }); }, }); @@ -2960,17 +2943,14 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, @@ -2998,7 +2978,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -3010,12 +2990,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[1]); await controller.setActiveNetwork('testNetworkConfiguration'); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); const { provider } = controller.getProviderAndBlockTracker(); assert(provider, 'Provider is somehow unset'); @@ -3036,17 +3011,14 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, @@ -3062,7 +3034,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -3076,12 +3048,7 @@ describe('NetworkController', () => { const { provider: providerBefore } = controller.getProviderAndBlockTracker(); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); const { provider: providerAfter } = controller.getProviderAndBlockTracker(); @@ -3090,82 +3057,18 @@ describe('NetworkController', () => { ); }); - it('emits networkDidChange', async () => { - await withController( - { - state: { - providerConfig: { - type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, - networkConfigurations: { - testNetworkConfiguration: { - id: 'testNetworkConfiguration', - rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', - ticker: 'TEST', - }, - }, - }, - infuraProjectId: 'some-infura-project-id', - }, - async ({ controller, messenger }) => { - const fakeProviders = [buildFakeProvider(), buildFakeProvider()]; - const fakeNetworkClients = [ - buildFakeClient(fakeProviders[0]), - buildFakeClient(fakeProviders[1]), - ]; - mockCreateNetworkClient() - .calledWith({ - rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', - type: NetworkClientType.Custom, - }) - .mockReturnValue(fakeNetworkClients[0]) - .calledWith({ - network: networkType, - infuraProjectId: 'some-infura-project-id', - type: NetworkClientType.Infura, - }) - .mockReturnValue(fakeNetworkClients[1]); - - await controller.setActiveNetwork('testNetworkConfiguration'); - - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - const networkDidChange = await waitForPublishedEvents({ - messenger, - eventType: 'NetworkController:networkDidChange', - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - - expect(networkDidChange).toBeTruthy(); - }, - }); - }, - ); - }); - it('emits infuraIsBlocked or infuraIsUnblocked, depending on whether Infura is blocking requests for the previous network', async () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, @@ -3191,7 +3094,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -3213,15 +3116,10 @@ describe('NetworkController', () => { eventType: 'NetworkController:infuraIsBlocked', }); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); - expect(await promiseForNoInfuraIsUnblockedEvents).toBeTruthy(); - expect(await promiseForInfuraIsBlocked).toBeTruthy(); + await expect(promiseForNoInfuraIsUnblockedEvents).toBeFulfilled(); + await expect(promiseForInfuraIsBlocked).toBeFulfilled(); }, ); }); @@ -3230,17 +3128,14 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, @@ -3273,7 +3168,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -3306,24 +3201,17 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { + providerConfig: buildProviderConfig({ type: networkType, - // NOTE: This doesn't need to match the logical chain ID of - // the network selected, it just needs to exist - chainId: '0x111', - }, + }), networkConfigurations: { testNetworkConfiguration: { id: 'testNetworkConfiguration', rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), ticker: 'TEST', }, }, - networkDetails: { - EIPS: {}, - other: 'details', - }, }, infuraProjectId: 'some-infura-project-id', }, @@ -3357,7 +3245,7 @@ describe('NetworkController', () => { mockCreateNetworkClient() .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x222', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[0]) @@ -3396,20 +3284,80 @@ describe('NetworkController', () => { } describe(`if the previous provider configuration had a type of "rpc"`, () => { + it('emits networkWillChange', async () => { + await withController( + { + state: { + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, + }), + }, + }, + async ({ controller, messenger }) => { + const fakeProvider = buildFakeProvider(); + const fakeNetworkClient = buildFakeClient(fakeProvider); + mockCreateNetworkClient().mockReturnValue(fakeNetworkClient); + await controller.setProviderType(NETWORK_TYPES.GOERLI); + + const networkWillChange = waitForPublishedEvents({ + messenger, + eventType: 'NetworkController:networkWillChange', + operation: () => { + // Intentionally not awaited because we're capturing an event + // emitted partway through the operation + controller.rollbackToPreviousProvider(); + }, + }); + + await expect(networkWillChange).toBeFulfilled(); + }, + ); + }); + + it('emits networkDidChange', async () => { + await withController( + { + state: { + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, + }), + }, + }, + async ({ controller, messenger }) => { + const fakeProvider = buildFakeProvider(); + const fakeNetworkClient = buildFakeClient(fakeProvider); + mockCreateNetworkClient().mockReturnValue(fakeNetworkClient); + await controller.setProviderType(NETWORK_TYPES.GOERLI); + + const networkDidChange = waitForPublishedEvents({ + messenger, + eventType: 'NetworkController:networkDidChange', + operation: () => { + // Intentionally not awaited because we're capturing an event + // emitted partway through the operation + controller.rollbackToPreviousProvider(); + }, + }); + + await expect(networkDidChange).toBeFulfilled(); + }, + ); + }); + it('overwrites the the current provider configuration with the previous provider configuration', async () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), nickname: 'network', ticker: 'TEST', rpcPrefs: { blockExplorerUrl: 'https://test-block-explorer.com', }, - }, + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3428,7 +3376,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); @@ -3436,7 +3384,7 @@ describe('NetworkController', () => { expect(controller.store.getState().providerConfig).toStrictEqual({ type: 'goerli', rpcUrl: undefined, - chainId: '0x5', + chainId: toHex(5), ticker: 'GoerliETH', nickname: undefined, rpcPrefs: { @@ -3445,86 +3393,32 @@ describe('NetworkController', () => { id: undefined, }); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - expect(controller.store.getState().providerConfig).toStrictEqual({ - type: 'rpc', - rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - nickname: 'network', - ticker: 'TEST', - rpcPrefs: { - blockExplorerUrl: 'https://test-block-explorer.com', - }, - }); + await controller.rollbackToPreviousProvider(); + expect(controller.store.getState().providerConfig).toStrictEqual( + buildProviderConfig({ + type: 'rpc', + rpcUrl: 'https://mock-rpc-url', + chainId: toHex(1337), + nickname: 'network', + ticker: 'TEST', + rpcPrefs: { + blockExplorerUrl: 'https://test-block-explorer.com', + }, + }), + ); }, ); }); - it('emits networkWillChange', async () => { + it('resets the network state to "unknown" before updating the provider', async () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, - }, - infuraProjectId: 'some-infura-project-id', - }, - async ({ controller, messenger }) => { - const fakeProviders = [buildFakeProvider(), buildFakeProvider()]; - const fakeNetworkClients = [ - buildFakeClient(fakeProviders[0]), - buildFakeClient(fakeProviders[1]), - ]; - mockCreateNetworkClient() - .calledWith({ - network: NETWORK_TYPES.GOERLI, - infuraProjectId: 'some-infura-project-id', - type: NetworkClientType.Infura, - }) - .mockReturnValue(fakeNetworkClients[0]) - .calledWith({ - rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - type: NetworkClientType.Custom, - }) - .mockReturnValue(fakeNetworkClients[1]); - await controller.setProviderType('goerli'); - - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - const networkWillChange = await waitForPublishedEvents({ - messenger, - eventType: 'NetworkController:networkWillChange', - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - - expect(networkWillChange).toBeTruthy(); - }, - }); - }, - ); - }); - - it('resets the network state to "unknown" before emitting networkDidChange', async () => { - await withController( - { - state: { - providerConfig: { - type: 'rpc', - rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3559,48 +3453,43 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); await controller.setProviderType('goerli'); expect(controller.store.getState().networkStatus).toBe('available'); - await waitForLookupNetworkToComplete({ + await waitForStateChanges({ controller, - operation: async () => { - await waitForStateChanges({ - controller, - propertyPath: ['networkStatus'], - // We only care about the first state change, because it - // happens before networkDidChange - count: 1, - operation: () => { - // Intentionally not awaited because we want to check state - // while this operation is in-progress - controller.rollbackToPreviousProvider(); - }, - beforeResolving: () => { - expect(controller.store.getState().networkStatus).toBe( - 'unknown', - ); - }, - }); + propertyPath: ['networkStatus'], + // We only care about the first state change, because it + // happens before networkDidChange + count: 1, + operation: () => { + // Intentionally not awaited because we want to check state + // while this operation is in-progress + controller.rollbackToPreviousProvider(); + }, + beforeResolving: () => { + expect(controller.store.getState().networkStatus).toBe( + 'unknown', + ); }, }); }, ); }); - it('clears EIP-1559 support for the network from state before emitting networkDidChange', async () => { + it('clears EIP-1559 support for the network from state before updating the provider', async () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3631,7 +3520,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); @@ -3642,27 +3531,22 @@ describe('NetworkController', () => { }, }); - await waitForLookupNetworkToComplete({ + await waitForStateChanges({ controller, - operation: async () => { - await waitForStateChanges({ - controller, - propertyPath: ['networkDetails'], - // We only care about the first state change, because it - // happens before networkDidChange - count: 1, - operation: () => { - // Intentionally not awaited because we want to check state - // while this operation is in-progress - controller.rollbackToPreviousProvider(); - }, - beforeResolving: () => { - expect( - controller.store.getState().networkDetails, - ).toStrictEqual({ - EIPS: {}, - }); - }, + propertyPath: ['networkDetails'], + // We only care about the first state change, because it + // happens before networkDidChange + count: 1, + operation: () => { + // Intentionally not awaited because we want to check state + // while this operation is in-progress + controller.rollbackToPreviousProvider(); + }, + beforeResolving: () => { + expect( + controller.store.getState().networkDetails, + ).toStrictEqual({ + EIPS: {}, }); }, }); @@ -3674,11 +3558,11 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3709,18 +3593,13 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); await controller.setProviderType('goerli'); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); const { provider } = controller.getProviderAndBlockTracker(); assert(provider, 'Provider is somehow unset'); @@ -3741,11 +3620,11 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3764,7 +3643,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); @@ -3772,12 +3651,7 @@ describe('NetworkController', () => { const { provider: providerBefore } = controller.getProviderAndBlockTracker(); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); const { provider: providerAfter } = controller.getProviderAndBlockTracker(); @@ -3786,66 +3660,15 @@ describe('NetworkController', () => { ); }); - it('emits networkDidChange', async () => { - await withController( - { - state: { - providerConfig: { - type: 'rpc', - rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, - }, - infuraProjectId: 'some-infura-project-id', - }, - async ({ controller, messenger }) => { - const fakeProviders = [buildFakeProvider(), buildFakeProvider()]; - const fakeNetworkClients = [ - buildFakeClient(fakeProviders[0]), - buildFakeClient(fakeProviders[1]), - ]; - mockCreateNetworkClient() - .calledWith({ - network: NETWORK_TYPES.GOERLI, - infuraProjectId: 'some-infura-project-id', - type: NetworkClientType.Infura, - }) - .mockReturnValue(fakeNetworkClients[0]) - .calledWith({ - rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - type: NetworkClientType.Custom, - }) - .mockReturnValue(fakeNetworkClients[1]); - await controller.setProviderType('goerli'); - - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - const networkDidChange = await waitForPublishedEvents({ - messenger, - eventType: 'NetworkController:networkDidChange', - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - - expect(networkDidChange).toBeTruthy(); - }, - }); - }, - ); - }); - it('emits infuraIsUnblocked', async () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3864,26 +3687,21 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); await controller.setProviderType('goerli'); - await waitForLookupNetworkToComplete({ - controller, + const promiseForInfuraIsUnblocked = waitForPublishedEvents({ + messenger, + eventType: 'NetworkController:infuraIsUnblocked', operation: async () => { - const infuraIsUnblocked = await waitForPublishedEvents({ - messenger, - eventType: 'NetworkController:infuraIsUnblocked', - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); - - expect(infuraIsUnblocked).toBeTruthy(); + await controller.rollbackToPreviousProvider(); }, }); + + await expect(promiseForInfuraIsUnblocked).toBeFulfilled(); }, ); }); @@ -3892,11 +3710,11 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -3938,7 +3756,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); @@ -3957,15 +3775,11 @@ describe('NetworkController', () => { await withController( { state: { - providerConfig: { - type: 'rpc', + providerConfig: buildProviderConfig({ + type: NETWORK_TYPES.RPC, rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', - }, - networkDetails: { - EIPS: {}, - other: 'details', - }, + chainId: toHex(1337), + }), }, infuraProjectId: 'some-infura-project-id', }, @@ -4005,7 +3819,7 @@ describe('NetworkController', () => { .mockReturnValue(fakeNetworkClients[0]) .calledWith({ rpcUrl: 'https://mock-rpc-url', - chainId: '0x1337', + chainId: toHex(1337), type: NetworkClientType.Custom, }) .mockReturnValue(fakeNetworkClients[1]); @@ -4016,12 +3830,7 @@ describe('NetworkController', () => { }, }); - await waitForLookupNetworkToComplete({ - controller, - operation: async () => { - await controller.rollbackToPreviousProvider(); - }, - }); + await controller.rollbackToPreviousProvider(); expect(controller.store.getState().networkDetails).toStrictEqual({ EIPS: { 1559: true, @@ -6894,46 +6703,6 @@ async function waitForPublishedEvents({ return await promiseForEventPayloads; } -/** - * `lookupNetwork` is a method in NetworkController which is called internally - * by a few methods. `lookupNetwork` is asynchronous as it makes network - * requests under the hood, but unfortunately, the method is not awaited after - * being called. Hence, if it is called during a test, even if the network - * requests are initiated within the test, they may complete after that test - * ends. This is a problem because it may cause Nock mocks set up in a later - * test to get used up prematurely, causing failures. - * - * To fix this, we need to wait for `lookupNetwork` to fully finish before - * continuing. Since the latest thing that happens in `lookupNetwork` is to - * update EIP-1559 compatibility in state, we can wait for the `networkDetails` - * state to get updated specifically. Unfortunately, we don't know how many - * times this will happen, so this function does incur some time when it's used. - * To speed up tests, you can pass `numberOfNetworkDetailsChanges`. - * - * @param args - The arguments. - * @param args.controller - The network controller. - * @param args.numberOfNetworkDetailsChanges - The number of times that - * `networkDetails` is expected to be updated. - * @param args.operation - The function that presumably involves - * `lookupNetwork`. - */ -async function waitForLookupNetworkToComplete({ - controller, - numberOfNetworkDetailsChanges = null, - operation, -}: { - controller: NetworkController; - numberOfNetworkDetailsChanges?: number | null; - operation: () => void | Promise; -}) { - await waitForStateChanges({ - controller, - propertyPath: ['networkDetails'], - operation, - count: numberOfNetworkDetailsChanges, - }); -} - /** * Returns whether two places in different state objects have different values. * diff --git a/test/jest/setup.js b/test/jest/setup.js index d1ba51e61..a3c5d2568 100644 --- a/test/jest/setup.js +++ b/test/jest/setup.js @@ -40,6 +40,45 @@ beforeEach(() => { }); expect.extend({ + /** + * Tests that the given promise is fulfilled within a certain amount of time + * (which is the default time that Jest tests wait before timing out as + * configured in the Jest configuration file). + * + * Inspired by . + * + * @param {Promise} promise - The promise to test. + * @returns The result of the matcher. + */ + async toBeFulfilled(promise) { + if (this.isNot) { + throw new Error( + "Using `.not.toBeFulfilled(...)` is not supported. Use `.rejects` to test the promise's rejection value instead.", + ); + } + + let rejectionValue = UNRESOLVED; + try { + await promise; + } catch (e) { + rejectionValue = e; + } + + if (rejectionValue !== UNRESOLVED) { + return { + message: () => + `Expected promise to be fulfilled, but it was rejected with ${rejectionValue}.`, + pass: false, + }; + } + + return { + message: () => + 'This message should not be displayed as it is for the negative case, which will never happen.', + pass: true, + }; + }, + /** * Tests that the given promise is never fulfilled or rejected past a certain * amount of time (which is the default time that Jest tests wait before diff --git a/types/global.d.ts b/types/global.d.ts index 042d05558..f1e8c1b18 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -7,6 +7,14 @@ declare class Platform { closeCurrentWindow: () => void; } + export declare global { var platform: Platform; + + namespace jest { + interface Matchers { + toBeFulfilled(): Promise; + toNeverResolve(): Promise; + } + } }