Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
8 changes: 4 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ module.exports = {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 90.09,
functions: 84.21,
lines: 95.32,
statements: 95.32,
branches: 94.31,
functions: 85,
lines: 96.85,
statements: 96.85,
},
},

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@metamask/utils": "^3.2.0",
"@metamask/utils": "^5.0.0",
"fast-safe-stringify": "^2.0.6"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/__fixtures__/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const dummyMessage = 'baz';

export const invalidError0 = 0;
export const invalidError1 = ['foo', 'bar', 3];
export const invalidError2 = { code: 34 };
export const invalidError2 = { code: 'foo' };
export const invalidError3 = { code: 4001 };
export const invalidError4 = {
code: 4001,
Expand All @@ -15,7 +15,7 @@ export const invalidError4 = {
export const invalidError5 = null;
export const invalidError6 = undefined;
export const invalidError7 = {
code: 34,
code: 'foo',
message: dummyMessage,
data: Object.assign({}, dummyData),
};
Expand Down
13 changes: 4 additions & 9 deletions src/classes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import safeStringify from 'fast-safe-stringify';
import { Json } from '@metamask/utils';
import { Json, JsonRpcError } from '@metamask/utils';

export type SerializedEthereumRpcError = {
code: number;
message: string;
data?: Json;
stack?: string;
};
export { JsonRpcError };

/**
* Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors
Expand Down Expand Up @@ -40,8 +35,8 @@ export class EthereumRpcError<T extends Json> extends Error {
*
* @returns A plain object with all public class properties.
*/
serialize(): SerializedEthereumRpcError {
const serialized: SerializedEthereumRpcError = {
serialize(): JsonRpcError {
const serialized: JsonRpcError = {
code: this.code,
message: this.message,
};
Expand Down
151 changes: 125 additions & 26 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
validError3,
validError4,
dummyMessage,
dummyData,
} from './__fixtures__';
import { getMessageFromCode, serializeError } from './utils';
import { errorCodes } from '.';
import { errorCodes, ethErrors } from '.';

const rpcCodes = errorCodes.rpc;

Expand All @@ -25,7 +26,7 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: { originalError: invalidError0 },
data: { cause: invalidError0 },
});
});

Expand All @@ -34,7 +35,7 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: { originalError: invalidError5 },
data: { cause: invalidError5 },
});
});

Expand All @@ -43,7 +44,7 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: { originalError: invalidError6 },
data: { cause: null },
});
});

Expand All @@ -52,7 +53,7 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: { originalError: invalidError1 },
data: { cause: invalidError1 },
});
});

Expand All @@ -61,34 +62,50 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: { originalError: invalidError2 },
data: { cause: invalidError2 },
});
});

it('handles invalid error: valid code, undefined message', () => {
const result = serializeError(invalidError3);
expect(result).toStrictEqual({
code: 4001,
message: getMessageFromCode(4001),
data: { originalError: Object.assign({}, invalidError3) },
code: errorCodes.rpc.internal,
message: getMessageFromCode(errorCodes.rpc.internal),
data: {
cause: {
code: 4001,
},
},
});
});

it('handles invalid error: non-string message with data', () => {
const result = serializeError(invalidError4);
expect(result).toStrictEqual({
code: 4001,
message: getMessageFromCode(4001),
data: { originalError: Object.assign({}, invalidError4) },
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: {
cause: {
code: invalidError4.code,
message: invalidError4.message,
data: Object.assign({}, dummyData),
},
},
});
});

it('handles invalid error: invalid code with string message', () => {
const result = serializeError(invalidError7);
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: dummyMessage,
data: { originalError: Object.assign({}, invalidError7) },
message: getMessageFromCode(rpcCodes.internal),
data: {
cause: {
code: invalidError7.code,
message: invalidError7.message,
data: Object.assign({}, dummyData),
},
},
});
});

Expand All @@ -99,7 +116,7 @@ describe('serializeError', () => {
expect(result).toStrictEqual({
code: rpcCodes.methodNotFound,
message: 'foo',
data: { originalError: Object.assign({}, invalidError2) },
data: { cause: Object.assign({}, invalidError2) },
});
});

Expand Down Expand Up @@ -145,10 +162,8 @@ describe('serializeError', () => {
});
});

it('handles valid error: message, data, and stack', () => {
const result = serializeError(
Object.assign({}, validError1, { stack: 'foo' }),
);
it('handles valid error: message and data', () => {
const result = serializeError(Object.assign({}, validError1));
expect(result).toStrictEqual({
code: 4001,
message: validError1.message,
Expand All @@ -157,7 +172,7 @@ describe('serializeError', () => {
});

it('handles including stack: no stack present', () => {
const result = serializeError(validError1, { shouldIncludeStack: true });
const result = serializeError(validError1);
expect(result).toStrictEqual({
code: 4001,
message: validError1.message,
Expand All @@ -168,7 +183,6 @@ describe('serializeError', () => {
it('handles including stack: string stack present', () => {
const result = serializeError(
Object.assign({}, validError1, { stack: 'foo' }),
{ shouldIncludeStack: true },
);
expect(result).toStrictEqual({
code: 4001,
Expand All @@ -178,17 +192,102 @@ describe('serializeError', () => {
});
});

it('handles including stack: non-string stack present', () => {
it('handles removing stack', () => {
const result = serializeError(
Object.assign({}, validError1, { stack: 2 }),
{
shouldIncludeStack: true,
},
Object.assign({}, validError1, { stack: 'foo' }),
{ shouldIncludeStack: false },
);
expect(result).toStrictEqual({
code: 4001,
message: validError1.message,
data: Object.assign({}, validError1.data),
});
});

it('handles regular Error()', () => {
const error = new Error('foo');
const result = serializeError(error);
expect(result).toStrictEqual({
code: errorCodes.rpc.internal,
message: getMessageFromCode(errorCodes.rpc.internal),
data: {
cause: {
message: error.message,
stack: error.stack,
},
},
});

expect(JSON.parse(JSON.stringify(result))).toStrictEqual({
code: errorCodes.rpc.internal,
message: getMessageFromCode(errorCodes.rpc.internal),
data: {
cause: {
message: error.message,
stack: error.stack,
},
},
});
});

it('handles EthereumRpcError', () => {
const error = ethErrors.rpc.invalidParams();
const result = serializeError(error);
expect(result).toStrictEqual({
code: error.code,
message: error.message,
stack: error.stack,
});

expect(JSON.parse(JSON.stringify(result))).toStrictEqual({
code: error.code,
message: error.message,
stack: error.stack,
});
});

it('removes non JSON-serializable props on cause', () => {
const error = new Error('foo');
// @ts-expect-error Intentionally using wrong type
error.message = () => undefined;
const result = serializeError(error);
expect(result).toStrictEqual({
code: errorCodes.rpc.internal,
message: getMessageFromCode(errorCodes.rpc.internal),
data: {
cause: {
stack: error.stack,
},
},
});
});

it('throws if fallback is invalid', () => {
expect(() =>
// @ts-expect-error Intentionally using wrong type
serializeError(new Error(), { fallbackError: new Error() }),
).toThrow(
'Must provide fallback error with integer number code and string message.',
);
});

it('handles arrays passed as error', () => {
const error = ['foo', Symbol('bar'), { baz: 'qux', symbol: Symbol('') }];
const result = serializeError(error);
expect(result).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: {
cause: ['foo', null, { baz: 'qux' }],
},
});

expect(JSON.parse(JSON.stringify(result))).toStrictEqual({
code: rpcCodes.internal,
message: getMessageFromCode(rpcCodes.internal),
data: {
cause: ['foo', null, { baz: 'qux' }],
},
});
});
});
Loading