Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally serialize stack #22

Merged
merged 5 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
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