From 26db0aee46ad5dcac7753fe5cd685ca14c21c20d Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Fri, 14 Apr 2023 10:21:29 -0600 Subject: [PATCH] Convert NetworkController net client tests to TS (#18490) In order to be able to better compare differences between the version of NetworkController in this repo and the version in the `core` repo before we replace this version with the `core` version, this commit converts the NetworkController network client tests to TypeScript. The added types here are copied from the `core` repo. We plan on making more improvements on the `core` side at some point to polish the tests and types and reduce some of the duplication, but for now we're just trying to keep things as similar as possible. --- .eslintrc.js | 2 +- ....test.js => create-network-client.test.ts} | 0 ...-response.js => block-hash-in-response.ts} | 18 +- .../{block-param.js => block-param.ts} | 19 +- .../{helpers.js => helpers.ts} | 400 ++++++++++-------- .../{no-block-param.js => no-block-param.ts} | 13 +- ...leware.js => not-handled-by-middleware.ts} | 18 +- .../{shared-tests.js => shared-tests.ts} | 14 +- package.json | 1 + yarn.lock | 8 + 10 files changed, 297 insertions(+), 196 deletions(-) rename app/scripts/controllers/network/{create-network-client.test.js => create-network-client.test.ts} (100%) rename app/scripts/controllers/network/provider-api-tests/{block-hash-in-response.js => block-hash-in-response.ts} (96%) rename app/scripts/controllers/network/provider-api-tests/{block-param.js => block-param.ts} (99%) rename app/scripts/controllers/network/provider-api-tests/{helpers.js => helpers.ts} (56%) rename app/scripts/controllers/network/provider-api-tests/{no-block-param.js => no-block-param.ts} (99%) rename app/scripts/controllers/network/provider-api-tests/{not-handled-by-middleware.js => not-handled-by-middleware.ts} (83%) rename app/scripts/controllers/network/provider-api-tests/{shared-tests.js => shared-tests.ts} (98%) diff --git a/.eslintrc.js b/.eslintrc.js index bcbfb44b7..89578fa19 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -267,7 +267,7 @@ module.exports = { 'app/scripts/controllers/app-state.test.js', 'app/scripts/controllers/network/**/*.test.js', 'app/scripts/controllers/network/**/*.test.ts', - 'app/scripts/controllers/network/provider-api-tests/*.js', + 'app/scripts/controllers/network/provider-api-tests/*.ts', 'app/scripts/controllers/permissions/**/*.test.js', 'app/scripts/lib/**/*.test.js', 'app/scripts/migrations/*.test.js', diff --git a/app/scripts/controllers/network/create-network-client.test.js b/app/scripts/controllers/network/create-network-client.test.ts similarity index 100% rename from app/scripts/controllers/network/create-network-client.test.js rename to app/scripts/controllers/network/create-network-client.test.ts diff --git a/app/scripts/controllers/network/provider-api-tests/block-hash-in-response.js b/app/scripts/controllers/network/provider-api-tests/block-hash-in-response.ts similarity index 96% rename from app/scripts/controllers/network/provider-api-tests/block-hash-in-response.js rename to app/scripts/controllers/network/provider-api-tests/block-hash-in-response.ts index c1778f628..4ee0f633d 100644 --- a/app/scripts/controllers/network/provider-api-tests/block-hash-in-response.js +++ b/app/scripts/controllers/network/provider-api-tests/block-hash-in-response.ts @@ -1,6 +1,15 @@ /* eslint-disable jest/require-top-level-describe, jest/no-export */ -import { withMockedCommunications, withNetworkClient } from './helpers'; +import { + ProviderType, + withMockedCommunications, + withNetworkClient, +} from './helpers'; + +type TestsForRpcMethodThatCheckForBlockHashInResponseOptions = { + providerType: ProviderType; + numberOfParameters: number; +}; /** * Defines tests which exercise the behavior exhibited by an RPC method that @@ -15,8 +24,11 @@ import { withMockedCommunications, withNetworkClient } from './helpers'; * either `infura` or `custom` (default: "infura"). */ export function testsForRpcMethodsThatCheckForBlockHashInResponse( - method, - { numberOfParameters, providerType }, + method: string, + { + numberOfParameters, + providerType, + }: TestsForRpcMethodThatCheckForBlockHashInResponseOptions, ) { if (providerType !== 'infura' && providerType !== 'custom') { throw new Error( diff --git a/app/scripts/controllers/network/provider-api-tests/block-param.js b/app/scripts/controllers/network/provider-api-tests/block-param.ts similarity index 99% rename from app/scripts/controllers/network/provider-api-tests/block-param.js rename to app/scripts/controllers/network/provider-api-tests/block-param.ts index 49bd6e772..92fb65f04 100644 --- a/app/scripts/controllers/network/provider-api-tests/block-param.js +++ b/app/scripts/controllers/network/provider-api-tests/block-param.ts @@ -3,6 +3,7 @@ import { buildMockParams, buildRequestWithReplacedBlockParam, + ProviderType, waitForPromiseToBeFulfilledAfterRunningAllTimers, withMockedCommunications, withNetworkClient, @@ -13,6 +14,12 @@ import { buildJsonRpcEngineEmptyResponseErrorMessage, } from './shared-tests'; +type TestsForRpcMethodSupportingBlockParam = { + providerType: ProviderType; + blockParamIndex: number; + numberOfParameters: number; +}; + /** * Defines tests which exercise the behavior exhibited by an RPC method that * takes a block parameter. The value of this parameter can be either a block @@ -28,8 +35,12 @@ import { */ /* eslint-disable-next-line jest/no-export */ export function testsForRpcMethodSupportingBlockParam( - method, - { blockParamIndex, numberOfParameters, providerType }, + method: string, + { + blockParamIndex, + numberOfParameters, + providerType, + }: TestsForRpcMethodSupportingBlockParam, ) { describe.each([ ['given no block tag', undefined], @@ -1718,9 +1729,9 @@ export function testsForRpcMethodSupportingBlockParam( [ ['less than the current block number', '0x200'], ['equal to the curent block number', '0x100'], - ], + ] as any, '%s', - (_nestedDesc, currentBlockNumber) => { + (_nestedDesc: string, currentBlockNumber: string) => { it('makes an additional request to the RPC endpoint', async () => { await withMockedCommunications({ providerType }, async (comms) => { const request = { diff --git a/app/scripts/controllers/network/provider-api-tests/helpers.js b/app/scripts/controllers/network/provider-api-tests/helpers.ts similarity index 56% rename from app/scripts/controllers/network/provider-api-tests/helpers.js rename to app/scripts/controllers/network/provider-api-tests/helpers.ts index afa91a7bb..edcc1ca02 100644 --- a/app/scripts/controllers/network/provider-api-tests/helpers.js +++ b/app/scripts/controllers/network/provider-api-tests/helpers.ts @@ -1,14 +1,13 @@ -import nock from 'nock'; +import nock, { Scope as NockScope } from 'nock'; import sinon from 'sinon'; +import type { JSONRPCResponse } from '@json-rpc-specification/meta-schema'; import EthQuery from 'eth-query'; -import { createNetworkClient } from '../create-network-client'; - -/** - * @typedef {import('nock').Scope} NockScope - * - * A object returned by the `nock` function for mocking requests to a particular - * base URL. - */ +import { Hex } from '@metamask/utils'; +import { BuiltInInfuraNetwork } from '../../../../../shared/constants/network'; +import { + createNetworkClient, + NetworkClientType, +} from '../create-network-client'; /** * A dummy value for the `infuraProjectId` option that `createInfuraClient` @@ -41,9 +40,9 @@ const originalSetTimeout = setTimeout; * keeps failing, you can set `process.env.DEBUG_PROVIDER_TESTS` to `1`. This * will turn on some extra logging. * - * @param {any[]} args - The arguments that `console.log` takes. + * @param args - The arguments that `console.log` takes. */ -function debug(...args) { +function debug(...args: any) { if (process.env.DEBUG_PROVIDER_TESTS === '1') { console.log(...args); } @@ -52,96 +51,89 @@ function debug(...args) { /** * Builds a Nock scope object for mocking provider requests. * - * @param {string} rpcUrl - The URL of the RPC endpoint. - * @returns {NockScope} The nock scope. + * @param rpcUrl - The URL of the RPC endpoint. + * @returns The nock scope. */ -function buildScopeForMockingRequests(rpcUrl) { +function buildScopeForMockingRequests(rpcUrl: string): NockScope { return nock(rpcUrl).filteringRequestBody((body) => { debug('Nock Received Request: ', body); return body; }); } -/** - * @typedef {{ nockScope: NockScope, blockNumber: string }} MockBlockTrackerRequestOptions - * - * The options to `mockNextBlockTrackerRequest` and `mockAllBlockTrackerRequests`. - */ +type Request = { method: string; params?: any[] }; +type Response = { + id?: number | string; + jsonrpc?: '2.0'; + error?: any; + result?: any; + httpStatus?: number; +}; +type ResponseBody = { body: JSONRPCResponse }; +type BodyOrResponse = ResponseBody | Response; +type CurriedMockRpcCallOptions = { + request: Request; + // The response data. + response?: BodyOrResponse; + /** + * An error to throw while making the request. + * Takes precedence over `response`. + */ + error?: Error | string; + /** + * The amount of time that should pass before the + * request resolves with the response. + */ + delay?: number; + /** + * The number of times that the request is + * expected to be made. + */ + times?: number; +}; -/** - * Mocks the next request for the latest block that the block tracker will make. - * - * @param {MockBlockTrackerRequestOptions} args - The arguments. - * @param {NockScope} args.nockScope - A nock scope (a set of mocked requests - * scoped to a certain base URL). - * @param {string} args.blockNumber - The block number that the block tracker - * should report, as a 0x-prefixed hex string. - */ -async function mockNextBlockTrackerRequest({ - nockScope, - blockNumber = DEFAULT_LATEST_BLOCK_NUMBER, -}) { - await mockRpcCall({ - nockScope, - request: { method: 'eth_blockNumber', params: [] }, - response: { result: blockNumber }, - }); -} +type MockRpcCallOptions = { + // A nock scope (a set of mocked requests scoped to a certain base URL). + nockScope: nock.Scope; +} & CurriedMockRpcCallOptions; -/** - * Mocks all requests for the latest block that the block tracker will make. - * - * @param {MockBlockTrackerRequestOptions} args - The arguments. - * @param {NockScope} args.nockScope - A nock scope (a set of mocked requests - * scoped to a certain base URL). - * @param {string} args.blockNumber - The block number that the block tracker - * should report, as a 0x-prefixed hex string. - */ -async function mockAllBlockTrackerRequests({ - nockScope, - blockNumber = DEFAULT_LATEST_BLOCK_NUMBER, -}) { - await mockRpcCall({ - nockScope, - request: { method: 'eth_blockNumber', params: [] }, - response: { result: blockNumber }, - }).persist(); -} - -/** - * @typedef {{ nockScope: NockScope, request: object, response: object, delay?: number }} MockRpcCallOptions - * - * The options to `mockRpcCall`. - */ +type MockRpcCallResult = nock.Interceptor | nock.Scope; /** * Mocks a JSON-RPC request sent to the provider with the given response. * Provider type is inferred from the base url set on the nockScope. * - * @param {MockRpcCallOptions} args - The arguments. - * @param {NockScope} args.nockScope - A nock scope (a set of mocked requests - * scoped to a certain base URL). - * @param {object} args.request - The request data. - * @param {{body: string} | {httpStatus?: number; id?: number; method?: string; params?: string[]}} [args.response] - Information - * concerning the response that the request should have. If a `body` property is - * present, this is taken as the complete response body. If an `httpStatus` - * property is present, then it is taken as the HTTP status code to respond - * with. Properties other than these two are used to build a complete response - * body (including `id` and `jsonrpc` properties). - * @param {Error | string} [args.error] - An error to throw while making the - * request. Takes precedence over `response`. - * @param {number} [args.delay] - The amount of time that should pass before the - * request resolves with the response. - * @param {number} [args.times] - The number of times that the request is - * expected to be made. - * @returns {NockScope} The nock scope. + * @param args - The arguments. + * @param args.nockScope - A nock scope (a set of mocked requests scoped to a + * certain base URL). + * @param args.request - The request data. + * @param args.response - Information concerning the response that the request + * should have. If a `body` property is present, this is taken as the complete + * response body. If an `httpStatus` property is present, then it is taken as + * the HTTP status code to respond with. Properties other than these two are + * used to build a complete response body (including `id` and `jsonrpc` + * properties). + * @param args.error - An error to throw while making the request. Takes + * precedence over `response`. + * @param args.delay - The amount of time that should pass before the request + * resolves with the response. + * @param args.times - The number of times that the request is expected to be + * made. + * @returns The nock scope. */ -function mockRpcCall({ nockScope, request, response, error, delay, times }) { +function mockRpcCall({ + nockScope, + request, + response, + error, + delay, + times, +}: MockRpcCallOptions): MockRpcCallResult { // eth-query always passes `params`, so even if we don't supply this property, // for consistency with makeRpcCall, assume that the `body` contains it const { method, params = [], ...rest } = request; let httpStatus = 200; - let completeResponse = { id: 2, jsonrpc: '2.0' }; + let completeResponse: JSONRPCResponse = { id: 2, jsonrpc: '2.0' }; if (response !== undefined) { if ('body' in response) { completeResponse = response.body; @@ -156,6 +148,7 @@ function mockRpcCall({ nockScope, request, response, error, delay, times }) { } } } + /* @ts-expect-error The types for Nock do not include `basePath` in the interface for Nock.Scope. */ const url = nockScope.basePath.includes('infura.io') ? `/v3/${MOCK_INFURA_PROJECT_ID}` : '/'; @@ -189,7 +182,7 @@ function mockRpcCall({ nockScope, request, response, error, delay, times }) { if (error !== undefined) { return nockRequest.replyWithError(error); } else if (completeResponse !== undefined) { - return nockRequest.reply(httpStatus, (_, requestBody) => { + return nockRequest.reply(httpStatus, (_, requestBody: any) => { if (response !== undefined && !('body' in response)) { if (response.id === undefined) { completeResponse.id = requestBody.id; @@ -204,16 +197,72 @@ function mockRpcCall({ nockScope, request, response, error, delay, times }) { return nockRequest; } +type MockBlockTrackerRequestOptions = { + /** + * A nock scope (a set of mocked requests scoped to a certain base url). + */ + nockScope: NockScope; + /** + * The block number that the block tracker should report, as a 0x-prefixed hex + * string. + */ + blockNumber: string; +}; + +/** + * Mocks the next request for the latest block that the block tracker will make. + * + * @param args - The arguments. + * @param args.nockScope - A nock scope (a set of mocked requests scoped to a + * certain base URL). + * @param args.blockNumber - The block number that the block tracker should + * report, as a 0x-prefixed hex string. + */ +function mockNextBlockTrackerRequest({ + nockScope, + blockNumber = DEFAULT_LATEST_BLOCK_NUMBER, +}: MockBlockTrackerRequestOptions) { + mockRpcCall({ + nockScope, + request: { method: 'eth_blockNumber', params: [] }, + response: { result: blockNumber }, + }); +} + +/** + * Mocks all requests for the latest block that the block tracker will make. + * + * @param args - The arguments. + * @param args.nockScope - A nock scope (a set of mocked requests scoped to a + * certain base URL). + * @param args.blockNumber - The block number that the block tracker should + * report, as a 0x-prefixed hex string. + */ +async function mockAllBlockTrackerRequests({ + nockScope, + blockNumber = DEFAULT_LATEST_BLOCK_NUMBER, +}: MockBlockTrackerRequestOptions) { + const result = await mockRpcCall({ + nockScope, + request: { method: 'eth_blockNumber', params: [] }, + response: { result: blockNumber }, + }); + + if ('persist' in result) { + result.persist(); + } +} + /** * Makes a JSON-RPC call through the given eth-query object. * - * @param {any} ethQuery - The eth-query object. - * @param {object} request - The request data. - * @returns {Promise} A promise that either resolves with the result from - * the JSON-RPC response if it is successful or rejects with the error from the - * JSON-RPC response otherwise. + * @param ethQuery - The eth-query object. + * @param request - The request data. + * @returns A promise that either resolves with the result from the JSON-RPC + * response if it is successful or rejects with the error from the JSON-RPC + * response otherwise. */ -function makeRpcCall(ethQuery, request) { +function makeRpcCall(ethQuery: EthQuery, request: Request) { return new Promise((resolve, reject) => { debug('[makeRpcCall] making request', request); ethQuery.sendAsync(request, (error, result) => { @@ -227,41 +276,43 @@ function makeRpcCall(ethQuery, request) { }); } -/** - * @typedef {{providerType: 'infura' | 'custom', infuraNetwork?: string}} WithMockedCommunicationsOptions - * - * The options bag that `Communications` takes. - */ +export type ProviderType = 'infura' | 'custom'; -/** - * @typedef {{mockNextBlockTrackerRequest: (options: Omit) => void, mockAllBlockTrackerRequests: (options: Omit) => void, mockRpcCall: (options: Omit) => NockScope, rpcUrl: string, infuraNetwork: string}} Communications - * - * Provides methods to mock different kinds of requests to the provider. - */ +export type MockOptions = { + infuraNetwork?: BuiltInInfuraNetwork; + providerType: ProviderType; + customRpcUrl?: string; + customChainId?: Hex; +}; -/** - * @typedef {(comms: Communications) => Promise} WithMockedCommunicationsCallback - * - * The callback that `mockingCommunications` takes. - */ +export type MockCommunications = { + mockNextBlockTrackerRequest: (options?: any) => void; + mockAllBlockTrackerRequests: (options?: any) => void; + mockRpcCall: (options: CurriedMockRpcCallOptions) => MockRpcCallResult; + rpcUrl: string; + infuraNetwork: BuiltInInfuraNetwork; +}; /** * Sets up request mocks for requests to the provider. * - * @param {WithMockedCommunicationsOptions} options - An options bag. - * @param {"infura" | "custom"} options.providerType - The type of network - * client being tested. - * @param {string} [options.infuraNetwork] - The name of the Infura network being - * tested, assuming that `providerType` is "infura" (default: "mainnet"). - * @param {string} [options.customRpcUrl] - The URL of the custom RPC endpoint, - * assuming that `providerType` is "custom". - * @param {WithMockedCommunicationsCallback} fn - A function which will be - * called with an object that allows interaction with the network client. - * @returns {Promise} The return value of the given function. + * @param options - An options bag. + * @param options.providerType - The type of network client being tested. + * @param options.infuraNetwork - The name of the Infura network being tested, + * assuming that `providerType` is "infura" (default: "mainnet"). + * @param options.customRpcUrl - The URL of the custom RPC endpoint, assuming + * that `providerType` is "custom". + * @param fn - A function which will be called with an object that allows + * interaction with the network client. + * @returns The return value of the given function. */ export async function withMockedCommunications( - { providerType, infuraNetwork = 'mainnet', customRpcUrl = MOCK_RPC_URL }, - fn, + { + providerType, + infuraNetwork = 'mainnet', + customRpcUrl = MOCK_RPC_URL, + }: MockOptions, + fn: (comms: MockCommunications) => Promise, ) { if (providerType !== 'infura' && providerType !== 'custom') { throw new Error( @@ -274,11 +325,11 @@ export async function withMockedCommunications( ? `https://${infuraNetwork}.infura.io` : customRpcUrl; const nockScope = buildScopeForMockingRequests(rpcUrl); - const curriedMockNextBlockTrackerRequest = (localOptions) => + const curriedMockNextBlockTrackerRequest = (localOptions: any) => mockNextBlockTrackerRequest({ nockScope, ...localOptions }); - const curriedMockAllBlockTrackerRequests = (localOptions) => + const curriedMockAllBlockTrackerRequests = (localOptions: any) => mockAllBlockTrackerRequests({ nockScope, ...localOptions }); - const curriedMockRpcCall = (localOptions) => + const curriedMockRpcCall = (localOptions: any) => mockRpcCall({ nockScope, ...localOptions }); const comms = { @@ -297,12 +348,12 @@ export async function withMockedCommunications( } } -/** - * @typedef {{blockTracker: import('eth-block-tracker').PollingBlockTracker, clock: sinon.SinonFakeTimers, makeRpcCall: (request: Partial) => Promise, makeRpcCallsInSeries: (requests: Partial[]) => Promise}} MockNetworkClient - * - * Provides methods to interact with the suite of middleware that - * `createInfuraClient` or `createJsonRpcClient` exposes. - */ +type MockNetworkClient = { + blockTracker: any; + clock: sinon.SinonFakeTimers; + makeRpcCall: (request: Request) => Promise; + makeRpcCallsInSeries: (requests: Request[]) => Promise; +}; /** * Some middleware contain logic which retries the request if some condition @@ -321,14 +372,14 @@ export async function withMockedCommunications( * `setTimeout` handler. */ export async function waitForPromiseToBeFulfilledAfterRunningAllTimers( - promise, - clock, + promise: any, + clock: any, ) { let hasPromiseBeenFulfilled = false; let numTimesClockHasBeenAdvanced = 0; promise - .catch((error) => { + .catch((error: any) => { // This is used to silence Node.js warnings about the rejection // being handled asynchronously. The error is handled later when // `promise` is awaited, but we log it here anyway in case it gets @@ -350,36 +401,22 @@ export async function waitForPromiseToBeFulfilledAfterRunningAllTimers( return promise; } -/** - * @typedef {{providerType: "infura" | "custom", infuraNetwork?: string, customRpcUrl?: string, customChainId?: string}} WithClientOptions - * - * The options bag that `withNetworkClient` takes. - */ - -/** - * @typedef {(client: MockNetworkClient) => Promise} WithClientCallback - * - * The callback that `withNetworkClient` takes. - */ - /** * Builds a provider from the middleware (for the provider type) along with a * block tracker, runs the given function with those two things, and then * ensures the block tracker is stopped at the end. * - * @param {WithClientOptions} options - An options bag. - * @param {"infura" | "custom"} options.providerType - The type of network - * client being tested. - * @param {string} [options.infuraNetwork] - The name of the Infura network being - * tested, assuming that `providerType` is "infura" (default: "mainnet"). - * @param {string} [options.customRpcUrl] - The URL of the custom RPC endpoint, - * assuming that `providerType` is "custom". - * @param {string} [options.customChainId] - The chain id belonging to the - * custom RPC endpoint, assuming that `providerType` is "custom" (default: - * "0x1"). - * @param {WithClientCallback} fn - A function which will be called with an - * object that allows interaction with the network client. - * @returns {Promise} The return value of the given function. + * @param options - An options bag. + * @param options.providerType - The type of network client being tested. + * @param options.infuraNetwork - The name of the Infura network being tested, + * assuming that `providerType` is "infura" (default: "mainnet"). + * @param options.customRpcUrl - The URL of the custom RPC endpoint, assuming + * that `providerType` is "custom". + * @param options.customChainId - The chain id belonging to the custom RPC + * endpoint, assuming that `providerType` is "custom" (default: "0x1"). + * @param fn - A function which will be called with an object that allows + * interaction with the network client. + * @returns The return value of the given function. */ export async function withNetworkClient( { @@ -387,8 +424,8 @@ export async function withNetworkClient( infuraNetwork = 'mainnet', customRpcUrl = MOCK_RPC_URL, customChainId = '0x1', - }, - fn, + }: MockOptions, + fn: (client: MockNetworkClient) => Promise, ) { if (providerType !== 'infura' && providerType !== 'custom') { throw new Error( @@ -414,20 +451,21 @@ export async function withNetworkClient( ? createNetworkClient({ network: infuraNetwork, infuraProjectId: MOCK_INFURA_PROJECT_ID, - type: 'infura', + type: NetworkClientType.Infura, }) : createNetworkClient({ chainId: customChainId, rpcUrl: customRpcUrl, - type: 'custom', + type: NetworkClientType.Custom, }); process.env.IN_TEST = inTest; const { provider, blockTracker } = clientUnderTest; const ethQuery = new EthQuery(provider); - const curriedMakeRpcCall = (request) => makeRpcCall(ethQuery, request); - const makeRpcCallsInSeries = async (requests) => { + const curriedMakeRpcCall = (request: Request) => + makeRpcCall(ethQuery, request); + const makeRpcCallsInSeries = async (requests: Request[]) => { const responses = []; for (const request of requests) { responses.push(await curriedMakeRpcCall(request)); @@ -451,6 +489,13 @@ export async function withNetworkClient( } } +type BuildMockParamsOptions = { + // The block parameter value to set. + blockParam: any; + // The index of the block parameter. + blockParamIndex: number; +}; + /** * Build mock parameters for a JSON-RPC call. * @@ -460,16 +505,15 @@ export async function withNetworkClient( * The block parameter can be set to a custom value. If no value is given, it * is set as undefined. * - * @param {object} args - Arguments. - * @param {number} args.blockParamIndex - The index of the block parameter. - * @param {any} [args.blockParam] - The block parameter value to set. - * @returns {any[]} The mock params. + * @param args - Arguments. + * @param args.blockParamIndex - The index of the block parameter. + * @param args.blockParam - The block parameter value to set. + * @returns The mock params. */ -export function buildMockParams({ blockParam, blockParamIndex }) { - if (blockParamIndex === undefined) { - throw new Error(`Missing 'blockParamIndex'`); - } - +export function buildMockParams({ + blockParam, + blockParamIndex, +}: BuildMockParamsOptions) { const params = new Array(blockParamIndex).fill('some value'); params[blockParamIndex] = blockParam; @@ -480,18 +524,18 @@ export function buildMockParams({ blockParam, blockParamIndex }) { * Returns a partial JSON-RPC request object, with the "block" param replaced * with the given value. * - * @param {object} request - The request object. - * @param {string} request.method - The request method. - * @param {params} [request.params] - The request params. - * @param {number} blockParamIndex - The index within the `params` array of the - * block param. - * @param {any} blockParam - The desired block param value. - * @returns {object} The updated request object. + * @param request - The request object. + * @param request.method - The request method. + * @param request.params - The request params. + * @param blockParamIndex - The index within the `params` array of the block + * param. + * @param blockParam - The desired block param value. + * @returns The updated request object. */ export function buildRequestWithReplacedBlockParam( - { method, params = [] }, - blockParamIndex, - blockParam, + { method, params = [] }: Request, + blockParamIndex: number, + blockParam: any, ) { const updatedParams = params.slice(); updatedParams[blockParamIndex] = blockParam; diff --git a/app/scripts/controllers/network/provider-api-tests/no-block-param.js b/app/scripts/controllers/network/provider-api-tests/no-block-param.ts similarity index 99% rename from app/scripts/controllers/network/provider-api-tests/no-block-param.js rename to app/scripts/controllers/network/provider-api-tests/no-block-param.ts index 08ae7edd0..662c7fac9 100644 --- a/app/scripts/controllers/network/provider-api-tests/no-block-param.js +++ b/app/scripts/controllers/network/provider-api-tests/no-block-param.ts @@ -1,6 +1,7 @@ /* eslint-disable jest/require-top-level-describe, jest/no-export */ import { + ProviderType, waitForPromiseToBeFulfilledAfterRunningAllTimers, withMockedCommunications, withNetworkClient, @@ -11,6 +12,11 @@ import { buildJsonRpcEngineEmptyResponseErrorMessage, } from './shared-tests'; +type TestsForRpcMethodAssumingNoBlockParamOptions = { + providerType: ProviderType; + numberOfParameters: number; +}; + /** * Defines tests which exercise the behavior exhibited by an RPC method which is * assumed to not take a block parameter. Even if it does, the value of this @@ -23,8 +29,11 @@ import { * either `infura` or `custom` (default: "infura"). */ export function testsForRpcMethodAssumingNoBlockParam( - method, - { numberOfParameters, providerType }, + method: string, + { + numberOfParameters, + providerType, + }: TestsForRpcMethodAssumingNoBlockParamOptions, ) { if (providerType !== 'infura' && providerType !== 'custom') { throw new Error( diff --git a/app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.js b/app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.ts similarity index 83% rename from app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.js rename to app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.ts index 693d9f779..ee92bb07f 100644 --- a/app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.js +++ b/app/scripts/controllers/network/provider-api-tests/not-handled-by-middleware.ts @@ -1,7 +1,16 @@ /* eslint-disable jest/require-top-level-describe, jest/no-export */ import { fill } from 'lodash'; -import { withMockedCommunications, withNetworkClient } from './helpers'; +import { + ProviderType, + withMockedCommunications, + withNetworkClient, +} from './helpers'; + +type TestsForRpcMethodNotHandledByMiddlewareOptions = { + providerType: ProviderType; + numberOfParameters: number; +}; /** * Defines tests which exercise the behavior exhibited by an RPC method that @@ -15,8 +24,11 @@ import { withMockedCommunications, withNetworkClient } from './helpers'; * RPC method takes. */ export function testsForRpcMethodNotHandledByMiddleware( - method, - { providerType, numberOfParameters }, + method: string, + { + providerType, + numberOfParameters, + }: TestsForRpcMethodNotHandledByMiddlewareOptions, ) { if (providerType !== 'infura' && providerType !== 'custom') { throw new Error( diff --git a/app/scripts/controllers/network/provider-api-tests/shared-tests.js b/app/scripts/controllers/network/provider-api-tests/shared-tests.ts similarity index 98% rename from app/scripts/controllers/network/provider-api-tests/shared-tests.js rename to app/scripts/controllers/network/provider-api-tests/shared-tests.ts index 04412d3f0..6337bb56a 100644 --- a/app/scripts/controllers/network/provider-api-tests/shared-tests.js +++ b/app/scripts/controllers/network/provider-api-tests/shared-tests.ts @@ -2,7 +2,11 @@ import { testsForRpcMethodsThatCheckForBlockHashInResponse } from './block-hash-in-response'; import { testsForRpcMethodSupportingBlockParam } from './block-param'; -import { withMockedCommunications, withNetworkClient } from './helpers'; +import { + ProviderType, + withMockedCommunications, + withNetworkClient, +} from './helpers'; import { testsForRpcMethodAssumingNoBlockParam } from './no-block-param'; import { testsForRpcMethodNotHandledByMiddleware } from './not-handled-by-middleware'; @@ -13,7 +17,7 @@ import { testsForRpcMethodNotHandledByMiddleware } from './not-handled-by-middle * @param reason - The exact reason for failure. * @returns The error message. */ -export function buildInfuraClientRetriesExhaustedErrorMessage(reason) { +export function buildInfuraClientRetriesExhaustedErrorMessage(reason: string) { return new RegExp( `^InfuraProvider - cannot complete request. All retries exhausted\\..+${reason}`, 'us', @@ -27,7 +31,7 @@ export function buildInfuraClientRetriesExhaustedErrorMessage(reason) { * @param method - The RPC method. * @returns The error message. */ -export function buildJsonRpcEngineEmptyResponseErrorMessage(method) { +export function buildJsonRpcEngineEmptyResponseErrorMessage(method: string) { return new RegExp( `^JsonRpcEngine: Response has no error or result for request:.+"method": "${method}"`, 'us', @@ -42,7 +46,7 @@ export function buildJsonRpcEngineEmptyResponseErrorMessage(method) { * @param reason - The reason. * @returns The error message. */ -export function buildFetchFailedErrorMessage(url, reason) { +export function buildFetchFailedErrorMessage(url: string, reason: string) { return new RegExp( `^request to ${url}(/[^/ ]*)+ failed, reason: ${reason}`, 'us', @@ -57,7 +61,7 @@ export function buildFetchFailedErrorMessage(url, reason) { * exposed by `createInfuraClient` is tested; if `custom`, then the middleware * exposed by `createJsonRpcClient` will be tested. */ -export function testsForProviderType(providerType) { +export function testsForProviderType(providerType: ProviderType) { // Ethereum JSON-RPC spec: // Infura documentation: diff --git a/package.json b/package.json index c3eb9e568..710d9fa11 100644 --- a/package.json +++ b/package.json @@ -368,6 +368,7 @@ "@babel/preset-typescript": "^7.16.7", "@babel/register": "^7.5.5", "@ethersproject/bignumber": "^5.7.0", + "@json-rpc-specification/meta-schema": "^1.0.6", "@lavamoat/allow-scripts": "^2.0.3", "@lavamoat/lavapack": "^5.0.0", "@metamask/auto-changelog": "^2.1.0", diff --git a/yarn.lock b/yarn.lock index 81c7c68e9..d6733e961 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3286,6 +3286,13 @@ __metadata: languageName: node linkType: hard +"@json-rpc-specification/meta-schema@npm:^1.0.6": + version: 1.0.6 + resolution: "@json-rpc-specification/meta-schema@npm:1.0.6" + checksum: 2eb9c6c6c73bb38350c7180d1ad3c5b8462406926cae753741895b457d7b1b9f0b74148daf3462bb167cef39efdd1d9090308edf4d4938956863acb643c146eb + languageName: node + linkType: hard + "@keystonehq/base-eth-keyring@npm:^0.7.1": version: 0.7.1 resolution: "@keystonehq/base-eth-keyring@npm:0.7.1" @@ -24143,6 +24150,7 @@ __metadata: "@ethersproject/providers": ^5.7.2 "@formatjs/intl-relativetimeformat": ^5.2.6 "@fortawesome/fontawesome-free": ^5.13.0 + "@json-rpc-specification/meta-schema": ^1.0.6 "@keystonehq/bc-ur-registry-eth": ^0.12.1 "@keystonehq/metamask-airgapped-keyring": ^0.6.1 "@lavamoat/allow-scripts": ^2.0.3