From 45e509629ce85ed5673c70be9b5dc56b1ba4d1e2 Mon Sep 17 00:00:00 2001 From: Jiri Zbytovsky Date: Tue, 28 Jan 2025 15:14:37 +0100 Subject: [PATCH 1/2] feat(utils): include stackTrace in serializeError --- packages/utils/src/serializeError.ts | 8 ++++++-- packages/utils/tests/serializeError.test.ts | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/serializeError.ts b/packages/utils/src/serializeError.ts index fdfd91029c8..90b2bc7d63a 100644 --- a/packages/utils/src/serializeError.ts +++ b/packages/utils/src/serializeError.ts @@ -2,10 +2,14 @@ * Serialize an error of unknown type to a string. */ export const serializeError = (error: unknown): string => { - // Error instances are objects, but have no JSON printable properties + // Error instances are objects, but have no JSON printable properties. + // Instead, .toString() is their standard string representation. Though stack trace must be included separately + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString if (error instanceof Error) { - return error.toString(); + return JSON.stringify({ message: error.toString(), stackTrace: error.stack }); } + + // plain javascript object is not a conventional error type, but we have to count with it if (typeof error === 'object') { return JSON.stringify(error); } diff --git a/packages/utils/tests/serializeError.test.ts b/packages/utils/tests/serializeError.test.ts index 2e63eed35f4..1deb5658a47 100644 --- a/packages/utils/tests/serializeError.test.ts +++ b/packages/utils/tests/serializeError.test.ts @@ -4,17 +4,32 @@ class CustomError extends Error { somethingExtra = 'extra stuff'; toString() { - return `${super.toString()} + ${this.somethingExtra} `; + return `${super.toString()} + ${this.somethingExtra}`; } } describe(serializeError.name, () => { it('serializes an Error instance', () => { const error = new Error('example message'); - expect(serializeError(error)).toBe('Error: example message'); + /* + A very crude way to mock the stack trace.. But although we can generally mock anything in Jest, + (in this case that would be Error.prototype.captureStackTrace that sets the Error.stack property) + specifically errors are not mockable, as Jest relies on them internally and it bugs out Jest. + But couldn't we then do it at least for CustomError? No, because for Error instances, + JavaScript bypasses the prototype chain and calls Error.prototype.captureStackTrace directly. + */ + error.stack = 'Mock Stack Trace'; + expect(JSON.parse(serializeError(error))).toMatchObject({ + message: 'Error: example message', + stackTrace: 'Mock Stack Trace', + }); const customError = new CustomError('example message'); - expect(serializeError(customError)).toBe('Error: example message + extra stuff '); + customError.stack = 'Mock Stack Trace'; + expect(JSON.parse(serializeError(customError))).toMatchObject({ + message: 'Error: example message + extra stuff', + stackTrace: 'Mock Stack Trace', + }); }); it('serializes a plain object', () => { From 826002e23b9e520f7409f43d781fc8051ed9b2cf Mon Sep 17 00:00:00 2001 From: Jiri Zbytovsky Date: Tue, 28 Jan 2025 15:21:30 +0100 Subject: [PATCH 2/2] feat(connect): define TrezorError.toString with pertinent info --- packages/connect/src/constants/errors.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/connect/src/constants/errors.ts b/packages/connect/src/constants/errors.ts index 6c43740b6a3..9212134f9d2 100644 --- a/packages/connect/src/constants/errors.ts +++ b/packages/connect/src/constants/errors.ts @@ -69,6 +69,11 @@ export class TrezorError extends Error { this.code = code; this.message = message; } + + // Error.prototype.toString() does not include custom property `code` + toString() { + return `${this.name} (code: ${this.code}): ${this.message}`; + } } export const TypedError = (id: ErrorCode, message?: string) =>