Skip to content

Commit

Permalink
Optionally serialize stack (#22)
Browse files Browse the repository at this point in the history
* add option for serializing stack

* add test cases
  • Loading branch information
rekmarks authored Jul 29, 2020
1 parent ccd9ba8 commit f905b5c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 11 deletions.
7 changes: 6 additions & 1 deletion @types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ export interface IProviderCustomErrorOptions extends IErrorOptions {
message: string,
}

interface SerializeErrorOptions {
fallbackError?: object,
shouldSerializeStack?: boolean,
}

export interface ISerializeError {
(error: any, fallbackError?: DefaultError): IEthereumRpcError<any>
(error: any, options?: SerializeErrorOptions): IEthereumRpcError<any>
}

export interface IGetMessageFromCode {
Expand Down
19 changes: 12 additions & 7 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,27 @@ function isValidCode (code) {
* Merely copies the given error's values if it is already compatible.
* If the given error is not fully compatible, it will be preserved on the
* returned object's data.originalError property.
* Adds a 'stack' property if it exists on the given error.
*
* @param {any} error - The error to serialize.
* @param {object} fallbackError - The custom fallback error values if the
* given error is invalid.
* @return {object} A standardized error object.
* @param {Object} [options] - An options object.
* @param {Object} [options.fallbackError] - The custom fallback error values if
* the given error is invalid.
* @param {boolean} [options.shouldIncludeStack] - Whether the 'stack' property
* of the given error should be included on the serialized error, if present.
* @return {Object} A standardized, plain error object.
*/
function serializeError (error, fallbackError = FALLBACK_ERROR) {
function serializeError (
error,
{ fallbackError = FALLBACK_ERROR, shouldIncludeStack = false } = {},
) {

if (
!fallbackError ||
!Number.isInteger(fallbackError.code) ||
typeof fallbackError.message !== 'string'
) {
throw new Error(
'fallbackError must contain integer number code and string message.',
'Must provide fallback error with integer number code and string message.',
)
}

Expand Down Expand Up @@ -119,7 +124,7 @@ function serializeError (error, fallbackError = FALLBACK_ERROR) {
serialized.data = { originalError: assignOriginalError(error) }
}

if (error && error.stack) {
if (shouldIncludeStack && error && typeof error.stack === 'string') {
serialized.stack = error.stack
}
return serialized
Expand Down
99 changes: 96 additions & 3 deletions test/serializeError.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ const invalidError7 = { code: 34, message: dummyMessage, data: { ...dummyData }
const validError0 = { code: 4001, message: dummyMessage }
const validError1 = { code: 4001, message: dummyMessage, data: { ...dummyData } }
const validError2 = ethErrors.rpc.parse()
delete validError2.stack
const validError3 = ethErrors.rpc.parse(dummyMessage)
delete validError3.stack
const validError4 = ethErrors.rpc.parse({
message: dummyMessage,
data: { ...dummyData },
})
delete validError4.stack

test('invalid error: non-object', (t) => {
const result = serializeError(invalidError0)
Expand Down Expand Up @@ -156,6 +159,25 @@ test('invalid error: invalid code with string message', (t) => {
t.end()
})

test('invalid error: invalid code, no message, custom fallback', (t) => {
const result = serializeError(
invalidError2,
{ fallbackError: { code: rpcCodes.methodNotFound, message: 'foo' } },
)
t.ok(
dequal(
result,
{
code: rpcCodes.methodNotFound,
message: 'foo',
data: { originalError: { ...invalidError2 } },
},
),
'serialized error matches expected result',
)
t.end()
})

test('valid error: code and message only', (t) => {
const result = serializeError(validError0)
t.ok(
Expand Down Expand Up @@ -195,7 +217,6 @@ test('valid error: instantiated error', (t) => {
{
code: rpcCodes.parse,
message: getMessageFromCode(rpcCodes.parse),
stack: validError2.stack,
},
),
'serialized error matches expected result',
Expand All @@ -211,7 +232,6 @@ test('valid error: instantiated error', (t) => {
{
code: rpcCodes.parse,
message: dummyMessage,
stack: validError3.stack,
},
),
'serialized error matches expected result',
Expand All @@ -228,7 +248,80 @@ test('valid error: instantiated error with custom message and data', (t) => {
code: rpcCodes.parse,
message: validError4.message,
data: { ...validError4.data },
stack: validError4.stack,
},
),
'serialized error matches expected result',
)
t.end()
})

test('valid error: message, data, and stack', (t) => {
const result = serializeError({ ...validError1, stack: 'foo' })
t.ok(
dequal(
result,
{
code: 4001,
message: validError1.message,
data: { ...validError1.data },
},
),
'serialized error matches expected result',
)
t.end()
})

test('include stack: no stack present', (t) => {
const result = serializeError(
validError1,
{ shouldIncludeStack: true },
)
t.ok(
dequal(
result,
{
code: 4001,
message: validError1.message,
data: { ...validError1.data },
},
),
'serialized error matches expected result',
)
t.end()
})

test('include stack: string stack present', (t) => {
const result = serializeError(
{ ...validError1, stack: 'foo' },
{ shouldIncludeStack: true },
)
t.ok(
dequal(
result,
{
code: 4001,
message: validError1.message,
data: { ...validError1.data },
stack: 'foo',
},
),
'serialized error matches expected result',
)
t.end()
})

test('include stack: non-string stack present', (t) => {
const result = serializeError(
{ ...validError1, stack: 2 },
{ shouldIncludeStack: true },
)
t.ok(
dequal(
result,
{
code: 4001,
message: validError1.message,
data: { ...validError1.data },
},
),
'serialized error matches expected result',
Expand Down

0 comments on commit f905b5c

Please sign in to comment.