Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@metamask/json-rpc-engine": "^7.0.0",
"@metamask/json-rpc-engine": "^7.1.1",
"@metamask/object-multiplex": "^1.1.0",
"@metamask/rpc-errors": "^5.1.1",
"@metamask/rpc-errors": "^6.0.0",
"@metamask/safe-event-emitter": "^3.0.0",
"@metamask/utils": "^6.2.0",
"@metamask/utils": "^8.1.0",
"detect-browser": "^5.2.0",
"extension-port-stream": "^2.0.1",
"fast-deep-equal": "^3.1.3",
Expand Down
161 changes: 98 additions & 63 deletions src/middleware/createRpcWarningMiddleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { Json, JsonRpcFailure, JsonRpcSuccess } from '@metamask/utils';
import {
Json,
JsonRpcFailure,
JsonRpcParams,
JsonRpcRequest,
JsonRpcSuccess,
} from '@metamask/utils';

import { createRpcWarningMiddleware } from './createRpcWarningMiddleware';
import messages from '../messages';

const affected = [
type Scenario = {
scenario: string;
method: string;
warning?: string;
params?: JsonRpcParams;
};

const affected: Scenario[] = [
{
scenario: 'eth_decrypt',
method: 'eth_decrypt',
Expand Down Expand Up @@ -35,7 +48,7 @@ const affected = [
},
];

const unaffected = [
const unaffected: Scenario[] = [
{
scenario: 'eth_chainId',
method: 'eth_chainId',
Expand All @@ -51,67 +64,84 @@ const unaffected = [
];

describe('createRpcWarningMiddleware', () => {
describe.each(affected)('$scenario', ({ method, params = {}, warning }) => {
it('should warn the first time the method is called', async () => {
const consoleWarnSpy = jest.spyOn(globalThis.console, 'warn');
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);

await engine.handle({ jsonrpc: '2.0', id: 1, method, params });

expect(consoleWarnSpy).toHaveBeenCalledWith(warning);
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
});

it('should not warn the second time the method is called', async () => {
const consoleWarnSpy = jest.spyOn(globalThis.console, 'warn');
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);

await engine.handle({ jsonrpc: '2.0', id: 1, method, params });
await engine.handle({ jsonrpc: '2.0', id: 1, method, params });

expect(consoleWarnSpy).toHaveBeenCalledWith(warning);
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
});

it('should allow the method to succeed', async () => {
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);
engine.push((_req, res, _next, end) => {
res.result = 'success!';
end();
describe.each(affected)(
'$scenario',
({ method, params = {}, warning }: Scenario) => {
it('should warn the first time the method is called', async () => {
const consoleWarnSpy = jest.spyOn(globalThis.console, 'warn');
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);

await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
params,
} as JsonRpcRequest);
expect(consoleWarnSpy).toHaveBeenCalledWith(warning);
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
});

const response = (await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
})) as JsonRpcSuccess<Json>;

expect(response.result).toBe('success!');
});

it('should allow the method to fail', async () => {
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);
engine.push(() => {
throw new Error('Failure!');
it('should not warn the second time the method is called', async () => {
const consoleWarnSpy = jest.spyOn(globalThis.console, 'warn');
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);

await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
params,
} as JsonRpcRequest);
await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
params,
} as JsonRpcRequest);

expect(consoleWarnSpy).toHaveBeenCalledWith(warning);
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
});

const result = (await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
})) as JsonRpcFailure;
it('should allow the method to succeed', async () => {
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);
engine.push((_req, res, _next, end) => {
res.result = 'success!';
end();
});

const response = (await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
})) as JsonRpcSuccess<Json>;

expect(response.result).toBe('success!');
});

expect(result.error.message).toBe('Failure!');
});
});
it('should allow the method to fail', async () => {
const middleware = createRpcWarningMiddleware(globalThis.console);
const engine = new JsonRpcEngine();
engine.push(middleware);
engine.push(() => {
throw new Error('Failure!');
});

const result = (await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
})) as JsonRpcFailure;

expect(result.error.message).toBe('Internal JSON-RPC error.');
});
},
);

describe.each(unaffected)('$scenario', ({ method, params = {} }) => {
it('should not issue a warning', async () => {
Expand All @@ -120,7 +150,12 @@ describe('createRpcWarningMiddleware', () => {
const engine = new JsonRpcEngine();
engine.push(middleware);

await engine.handle({ jsonrpc: '2.0', id: 1, method, params });
await engine.handle({
jsonrpc: '2.0',
id: 1,
method,
params,
} as JsonRpcRequest);

expect(consoleWarnSpy).not.toHaveBeenCalled();
});
Expand All @@ -139,7 +174,7 @@ describe('createRpcWarningMiddleware', () => {
id: 1,
method,
params,
})) as JsonRpcSuccess<Json>;
} as JsonRpcRequest)) as JsonRpcSuccess<Json>;

expect(response.result).toBe('success!');
});
Expand All @@ -157,9 +192,9 @@ describe('createRpcWarningMiddleware', () => {
id: 1,
method,
params,
})) as JsonRpcFailure;
} as JsonRpcRequest)) as JsonRpcFailure;

expect(result.error.message).toBe('Failure!');
expect(result.error.message).toBe('Internal JSON-RPC error.');
});
});
});
5 changes: 3 additions & 2 deletions test/mocks/MockConnectionStream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Json,
JsonRpcNotification,
JsonRpcRequest,
JsonRpcResponse,
Expand Down Expand Up @@ -71,7 +72,7 @@ export class MockConnectionStream extends Duplex {
* @param substream - The substream this reply is included in.
* @param message - The JSON RPC response.
*/
reply(substream: string, message: JsonRpcResponse) {
reply(substream: string, message: JsonRpcResponse<Json>) {
this.push({ name: substream, data: message });
}

Expand All @@ -81,7 +82,7 @@ export class MockConnectionStream extends Duplex {
* @param substream - The substream this notification is included in.
* @param message - The JSON RPC notification.
*/
notify(substream: string, message: JsonRpcNotification<unknown>) {
notify(substream: string, message: JsonRpcNotification) {
this.push({ name: substream, data: message });
}
}
3 changes: 2 additions & 1 deletion test/mocks/MockPort.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Json,
JsonRpcNotification,
JsonRpcRequest,
JsonRpcResponse,
Expand Down Expand Up @@ -77,7 +78,7 @@ export class MockPort {
* @param substream - The substream this reply is included in.
* @param message - The JSON RPC response.
*/
reply(substream: string, message: JsonRpcResponse) {
reply(substream: string, message: JsonRpcResponse<Json>) {
if (!this.#connected) {
throw new Error(
'It is not possible to reply after the port has disconnected',
Expand Down
61 changes: 24 additions & 37 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1071,14 +1071,14 @@ __metadata:
languageName: node
linkType: hard

"@metamask/json-rpc-engine@npm:^7.0.0":
version: 7.0.0
resolution: "@metamask/json-rpc-engine@npm:7.0.0"
"@metamask/json-rpc-engine@npm:^7.1.1":
version: 7.1.1
resolution: "@metamask/json-rpc-engine@npm:7.1.1"
dependencies:
"@metamask/rpc-errors": ^5.0.0
"@metamask/safe-event-emitter": ^2.0.0
"@metamask/utils": ^5.0.1
checksum: d22347ee4597bc72cdc34e65a27872ed8e77de188c5b95fed9133c25289cd4abd7aafa72e3e326d8a7449a857c275ed6435642727c30c51319f5d97a579c5f49
"@metamask/rpc-errors": ^6.0.0
"@metamask/safe-event-emitter": ^3.0.0
"@metamask/utils": ^8.1.0
checksum: 9dddd9142965ccd86313cda5bf13f15bf99c6c14631f93aab78de353317d548a334b5b125cdc134edd7d54e2f2e4961a0bdcd24fba997b2913083955df8fefa1
languageName: node
linkType: hard

Expand All @@ -1103,11 +1103,11 @@ __metadata:
"@metamask/eslint-config-jest": ^11.0.0
"@metamask/eslint-config-nodejs": ^11.0.1
"@metamask/eslint-config-typescript": ^11.0.0
"@metamask/json-rpc-engine": ^7.0.0
"@metamask/json-rpc-engine": ^7.1.1
"@metamask/object-multiplex": ^1.1.0
"@metamask/rpc-errors": ^5.1.1
"@metamask/rpc-errors": ^6.0.0
"@metamask/safe-event-emitter": ^3.0.0
"@metamask/utils": ^6.2.0
"@metamask/utils": ^8.1.0
"@types/chrome": ^0.0.233
"@types/jest": ^28.1.6
"@types/node": ^17.0.23
Expand Down Expand Up @@ -1145,13 +1145,13 @@ __metadata:
languageName: unknown
linkType: soft

"@metamask/rpc-errors@npm:^5.0.0, @metamask/rpc-errors@npm:^5.1.1":
version: 5.1.1
resolution: "@metamask/rpc-errors@npm:5.1.1"
"@metamask/rpc-errors@npm:^6.0.0":
version: 6.0.0
resolution: "@metamask/rpc-errors@npm:6.0.0"
dependencies:
"@metamask/utils": ^5.0.0
"@metamask/utils": ^8.0.0
fast-safe-stringify: ^2.0.6
checksum: ccd1b24da66af3ae63960b79c04b86efb8b96acb89ca6f7e0bbfe636d23ba5cddeba533c0692eafb87c44ec6f840085372d0f21b39e05df9a80700ff61538a30
checksum: 7e1ee1a98972266af4a34f0bbc842cdc11dc565056f0b8fbc93aa95663a7027eab8ff1fecbe3e09c38a1dc199f8219a6c69b2237015b2fdb8de0e5b35027c3f8
languageName: node
linkType: hard

Expand All @@ -1169,30 +1169,17 @@ __metadata:
languageName: node
linkType: hard

"@metamask/utils@npm:^5.0.0, @metamask/utils@npm:^5.0.1":
version: 5.0.2
resolution: "@metamask/utils@npm:5.0.2"
dependencies:
"@ethereumjs/tx": ^4.1.2
"@types/debug": ^4.1.7
debug: ^4.3.4
semver: ^7.3.8
superstruct: ^1.0.3
checksum: eca82e42911b2840deb4f32f0f215c5ffd14d22d68afbbe92d3180e920e509e310777b15eab29def3448f3535b66596ceb4c23666ec846adacc8e1bb093ff882
languageName: node
linkType: hard

"@metamask/utils@npm:^6.2.0":
version: 6.2.0
resolution: "@metamask/utils@npm:6.2.0"
"@metamask/utils@npm:^8.0.0, @metamask/utils@npm:^8.1.0":
version: 8.1.0
resolution: "@metamask/utils@npm:8.1.0"
dependencies:
"@ethereumjs/tx": ^4.1.2
"@noble/hashes": ^1.3.1
"@types/debug": ^4.1.7
debug: ^4.3.4
semver: ^7.3.8
semver: ^7.5.4
superstruct: ^1.0.3
checksum: 0bc675358ecc09b3bc04da613d73666295d7afa51ff6b8554801585966900b24b8545bd93b8b2e9a17db867ebe421fe884baf3558ec4ca3199fa65504f677c1b
checksum: 4cbee36d0c227f3e528930e83f75a0c6b71b55b332c3e162f0e87f3dd86ae017d0b20405d76ea054ab99e4d924d3d9b8b896ed12a12aae57b090350e5a625999
languageName: node
linkType: hard

Expand Down Expand Up @@ -6257,14 +6244,14 @@ __metadata:
languageName: node
linkType: hard

"semver@npm:7.x, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8":
version: 7.5.0
resolution: "semver@npm:7.5.0"
"semver@npm:7.x, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.4":
version: 7.5.4
resolution: "semver@npm:7.5.4"
dependencies:
lru-cache: ^6.0.0
bin:
semver: bin/semver.js
checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b
checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3
languageName: node
linkType: hard

Expand Down