mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
26db0aee46
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.
285 lines
10 KiB
TypeScript
285 lines
10 KiB
TypeScript
/* eslint-disable jest/require-top-level-describe, jest/no-export */
|
|
|
|
import {
|
|
ProviderType,
|
|
withMockedCommunications,
|
|
withNetworkClient,
|
|
} from './helpers';
|
|
|
|
type TestsForRpcMethodThatCheckForBlockHashInResponseOptions = {
|
|
providerType: ProviderType;
|
|
numberOfParameters: number;
|
|
};
|
|
|
|
/**
|
|
* Defines tests which exercise the behavior exhibited by an RPC method that
|
|
* use `blockHash` in the response data to determine whether the response is
|
|
* cacheable.
|
|
*
|
|
* @param method - The name of the RPC method under test.
|
|
* @param additionalArgs - Additional arguments.
|
|
* @param additionalArgs.numberOfParameters - The number of parameters supported
|
|
* by the method under test.
|
|
* @param additionalArgs.providerType - The type of provider being tested;
|
|
* either `infura` or `custom` (default: "infura").
|
|
*/
|
|
export function testsForRpcMethodsThatCheckForBlockHashInResponse(
|
|
method: string,
|
|
{
|
|
numberOfParameters,
|
|
providerType,
|
|
}: TestsForRpcMethodThatCheckForBlockHashInResponseOptions,
|
|
) {
|
|
if (providerType !== 'infura' && providerType !== 'custom') {
|
|
throw new Error(
|
|
`providerType must be either "infura" or "custom", was "${providerType}" instead`,
|
|
);
|
|
}
|
|
|
|
it('does not hit the RPC endpoint more than once for identical requests and it has a valid blockHash', async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResult = { blockHash: '0x1' };
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResult },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual([mockResult, mockResult]);
|
|
});
|
|
});
|
|
|
|
it('hits the RPC endpoint and does not reuse the result of a previous request if the latest block number was updated since', async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResults = [{ blockHash: '0x100' }, { blockHash: '0x200' }];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// Note that we have to mock these requests in a specific order. The
|
|
// first block tracker request occurs because of the first RPC
|
|
// request. The second block tracker request, however, does not occur
|
|
// because of the second RPC request, but rather because we call
|
|
// `clock.runAll()` below.
|
|
comms.mockNextBlockTrackerRequest({ blockNumber: '0x1' });
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockNextBlockTrackerRequest({ blockNumber: '0x2' });
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
async (client) => {
|
|
const firstResult = await client.makeRpcCall(requests[0]);
|
|
// Proceed to the next iteration of the block tracker so that a new
|
|
// block is fetched and the current block is updated.
|
|
client.clock.runAll();
|
|
const secondResult = await client.makeRpcCall(requests[1]);
|
|
return [firstResult, secondResult];
|
|
},
|
|
);
|
|
|
|
expect(results).toStrictEqual(mockResults);
|
|
});
|
|
});
|
|
|
|
it('does not reuse the result of a previous request if result.blockHash was null', async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResults = [
|
|
{ blockHash: null, extra: 'some value' },
|
|
{ blockHash: '0x100', extra: 'some other value' },
|
|
];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual(mockResults);
|
|
});
|
|
});
|
|
|
|
it('does not reuse the result of a previous request if result.blockHash was undefined', async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResults = [
|
|
{ extra: 'some value' },
|
|
{ blockHash: '0x100', extra: 'some other value' },
|
|
];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual(mockResults);
|
|
});
|
|
});
|
|
|
|
it('does not reuse the result of a previous request if result.blockHash was "0x0000000000000000000000000000000000000000000000000000000000000000"', async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResults = [
|
|
{
|
|
blockHash:
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
extra: 'some value',
|
|
},
|
|
{ blockHash: '0x100', extra: 'some other value' },
|
|
];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual(mockResults);
|
|
});
|
|
});
|
|
|
|
for (const emptyValue of [null, undefined, '\u003cnil\u003e']) {
|
|
it(`does not retry an empty response of "${emptyValue}"`, async () => {
|
|
const request = { method };
|
|
const mockResult = emptyValue;
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request,
|
|
response: { result: mockResult },
|
|
});
|
|
|
|
const result = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCall }) => makeRpcCall(request),
|
|
);
|
|
|
|
expect(result).toStrictEqual(mockResult);
|
|
});
|
|
});
|
|
|
|
it(`does not reuse the result of a previous request if it was "${emptyValue}"`, async () => {
|
|
const requests = [{ method }, { method }];
|
|
const mockResults = [emptyValue, { blockHash: '0x100' }];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual(mockResults);
|
|
});
|
|
});
|
|
}
|
|
|
|
for (const paramIndex of [...Array(numberOfParameters).keys()]) {
|
|
it(`does not reuse the result of a previous request with a valid blockHash if parameter at index "${paramIndex}" differs`, async () => {
|
|
const firstMockParams = [
|
|
...new Array(numberOfParameters).fill('some value'),
|
|
];
|
|
const secondMockParams = firstMockParams.slice();
|
|
secondMockParams[paramIndex] = 'another value';
|
|
const requests = [
|
|
{
|
|
method,
|
|
params: firstMockParams,
|
|
},
|
|
{ method, params: secondMockParams },
|
|
];
|
|
const mockResults = [{ blockHash: '0x100' }, { blockHash: '0x200' }];
|
|
|
|
await withMockedCommunications({ providerType }, async (comms) => {
|
|
// The first time a block-cacheable request is made, the latest block
|
|
// number is retrieved through the block tracker first. It doesn't
|
|
// matter what this is — it's just used as a cache key.
|
|
comms.mockNextBlockTrackerRequest();
|
|
comms.mockRpcCall({
|
|
request: requests[0],
|
|
response: { result: mockResults[0] },
|
|
});
|
|
comms.mockRpcCall({
|
|
request: requests[1],
|
|
response: { result: mockResults[1] },
|
|
});
|
|
|
|
const results = await withNetworkClient(
|
|
{ providerType },
|
|
({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests),
|
|
);
|
|
|
|
expect(results).toStrictEqual([mockResults[0], mockResults[1]]);
|
|
});
|
|
});
|
|
}
|
|
}
|