Skip to content

Commit cb3a6b4

Browse files
committed
feat(streams): Add shouldPreserveMessage param to serializeError
1 parent 70cc036 commit cb3a6b4

File tree

3 files changed

+77
-49
lines changed

3 files changed

+77
-49
lines changed

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module.exports = {
4545
// An object that configures minimum threshold enforcement for coverage results
4646
coverageThreshold: {
4747
global: {
48-
branches: 92.59,
48+
branches: 92.77,
4949
functions: 94.73,
5050
lines: 92.64,
5151
statements: 92.64,

src/utils.test.ts

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { dataHasCause, getMessageFromCode, serializeError } from './utils';
2121
const rpcCodes = errorCodes.rpc;
2222

2323
describe('serializeError', () => {
24-
it('handles invalid error: non-object', () => {
24+
it('serializes invalid error: non-object', () => {
2525
const result = serializeError(invalidError0);
2626
expect(result).toStrictEqual({
2727
code: rpcCodes.internal,
@@ -30,7 +30,7 @@ describe('serializeError', () => {
3030
});
3131
});
3232

33-
it('handles invalid error: null', () => {
33+
it('serializes invalid error: null', () => {
3434
const result = serializeError(invalidError5);
3535
expect(result).toStrictEqual({
3636
code: rpcCodes.internal,
@@ -39,7 +39,7 @@ describe('serializeError', () => {
3939
});
4040
});
4141

42-
it('handles invalid error: undefined', () => {
42+
it('serializes invalid error: undefined', () => {
4343
const result = serializeError(invalidError6);
4444
expect(result).toStrictEqual({
4545
code: rpcCodes.internal,
@@ -48,7 +48,7 @@ describe('serializeError', () => {
4848
});
4949
});
5050

51-
it('handles invalid error: array', () => {
51+
it('serializes invalid error: array', () => {
5252
const result = serializeError(invalidError1);
5353
expect(result).toStrictEqual({
5454
code: rpcCodes.internal,
@@ -57,7 +57,27 @@ describe('serializeError', () => {
5757
});
5858
});
5959

60-
it('handles invalid error: invalid code', () => {
60+
it('serializes invalid error: array with non-JSON values', () => {
61+
const error = ['foo', Symbol('bar'), { baz: 'qux', symbol: Symbol('') }];
62+
const result = serializeError(error);
63+
expect(result).toStrictEqual({
64+
code: rpcCodes.internal,
65+
message: getMessageFromCode(rpcCodes.internal),
66+
data: {
67+
cause: ['foo', null, { baz: 'qux' }],
68+
},
69+
});
70+
71+
expect(JSON.parse(JSON.stringify(result))).toStrictEqual({
72+
code: rpcCodes.internal,
73+
message: getMessageFromCode(rpcCodes.internal),
74+
data: {
75+
cause: ['foo', null, { baz: 'qux' }],
76+
},
77+
});
78+
});
79+
80+
it('serializes invalid error: invalid code', () => {
6181
const result = serializeError(invalidError2);
6282
expect(result).toStrictEqual({
6383
code: rpcCodes.internal,
@@ -66,7 +86,7 @@ describe('serializeError', () => {
6686
});
6787
});
6888

69-
it('handles invalid error: valid code, undefined message', () => {
89+
it('serializes invalid error: valid code, undefined message', () => {
7090
const result = serializeError(invalidError3);
7191
expect(result).toStrictEqual({
7292
code: errorCodes.rpc.internal,
@@ -79,7 +99,7 @@ describe('serializeError', () => {
7999
});
80100
});
81101

82-
it('handles invalid error: non-string message with data', () => {
102+
it('serializes invalid error: non-string message with data', () => {
83103
const result = serializeError(invalidError4);
84104
expect(result).toStrictEqual({
85105
code: rpcCodes.internal,
@@ -94,7 +114,7 @@ describe('serializeError', () => {
94114
});
95115
});
96116

97-
it('handles invalid error: invalid code with string message', () => {
117+
it('serializes invalid error: invalid code with string message', () => {
98118
const result = serializeError(invalidError7);
99119
expect(result).toStrictEqual({
100120
code: rpcCodes.internal,
@@ -109,7 +129,7 @@ describe('serializeError', () => {
109129
});
110130
});
111131

112-
it('handles invalid error: invalid code, no message, custom fallback', () => {
132+
it('serializes invalid error: invalid code, no message, custom fallback', () => {
113133
const result = serializeError(invalidError2, {
114134
fallbackError: { code: rpcCodes.methodNotFound, message: 'foo' },
115135
});
@@ -120,15 +140,15 @@ describe('serializeError', () => {
120140
});
121141
});
122142

123-
it('handles valid error: code and message only', () => {
143+
it('serializes valid error: code and message only', () => {
124144
const result = serializeError(validError0);
125145
expect(result).toStrictEqual({
126146
code: 4001,
127147
message: validError0.message,
128148
});
129149
});
130150

131-
it('handles valid error: code, message, and data', () => {
151+
it('serializes valid error: code, message, and data', () => {
132152
const result = serializeError(validError1);
133153
expect(result).toStrictEqual({
134154
code: 4001,
@@ -137,23 +157,23 @@ describe('serializeError', () => {
137157
});
138158
});
139159

140-
it('handles valid error: instantiated error', () => {
160+
it('serializes valid error: instantiated error', () => {
141161
const result = serializeError(validError2);
142162
expect(result).toStrictEqual({
143163
code: rpcCodes.parse,
144164
message: getMessageFromCode(rpcCodes.parse),
145165
});
146166
});
147167

148-
it('handles valid error: other instantiated error', () => {
168+
it('serializes valid error: other instantiated error', () => {
149169
const result = serializeError(validError3);
150170
expect(result).toStrictEqual({
151171
code: rpcCodes.parse,
152172
message: dummyMessage,
153173
});
154174
});
155175

156-
it('handles valid error: instantiated error with custom message and data', () => {
176+
it('serializes valid error: instantiated error with custom message and data', () => {
157177
const result = serializeError(validError4);
158178
expect(result).toStrictEqual({
159179
code: rpcCodes.parse,
@@ -162,7 +182,7 @@ describe('serializeError', () => {
162182
});
163183
});
164184

165-
it('handles valid error: message and data', () => {
185+
it('serializes valid error: message and data', () => {
166186
const result = serializeError(Object.assign({}, validError1));
167187
expect(result).toStrictEqual({
168188
code: 4001,
@@ -171,7 +191,7 @@ describe('serializeError', () => {
171191
});
172192
});
173193

174-
it('handles including stack: no stack present', () => {
194+
it('serializes valid error: no stack present', () => {
175195
const result = serializeError(validError1);
176196
expect(result).toStrictEqual({
177197
code: 4001,
@@ -180,7 +200,7 @@ describe('serializeError', () => {
180200
});
181201
});
182202

183-
it('handles including stack: string stack present', () => {
203+
it('serializes valid error: string stack present', () => {
184204
const result = serializeError(
185205
Object.assign({}, validError1, { stack: 'foo' }),
186206
);
@@ -192,7 +212,7 @@ describe('serializeError', () => {
192212
});
193213
});
194214

195-
it('handles removing stack', () => {
215+
it('removes the stack with `shouldIncludeStack: false`', () => {
196216
const result = serializeError(
197217
Object.assign({}, validError1, { stack: 'foo' }),
198218
{ shouldIncludeStack: false },
@@ -204,7 +224,25 @@ describe('serializeError', () => {
204224
});
205225
});
206226

207-
it('handles regular Error()', () => {
227+
it('overwrites the original message with `shouldPreserveMessage: false`', () => {
228+
const error = new Error('foo');
229+
const result = serializeError(error, {
230+
shouldPreserveMessage: false,
231+
fallbackError: validError0,
232+
});
233+
expect(result).toStrictEqual({
234+
code: validError0.code,
235+
message: validError0.message,
236+
data: {
237+
cause: {
238+
message: error.message,
239+
stack: error.stack,
240+
},
241+
},
242+
});
243+
});
244+
245+
it('serializes invalid error: Error', () => {
208246
const error = new Error('foo');
209247
const result = serializeError(error);
210248
expect(result).toStrictEqual({
@@ -230,7 +268,7 @@ describe('serializeError', () => {
230268
});
231269
});
232270

233-
it('handles JsonRpcError', () => {
271+
it('serializes valid error: JsonRpcError', () => {
234272
const error = rpcErrors.invalidParams();
235273
const result = serializeError(error);
236274
expect(result).toStrictEqual({
@@ -246,7 +284,7 @@ describe('serializeError', () => {
246284
});
247285
});
248286

249-
it('handles class that has serialize function', () => {
287+
it('serializes error with serialize() method', () => {
250288
class MockClass {
251289
serialize() {
252290
return { code: 1, message: 'foo' };
@@ -289,26 +327,6 @@ describe('serializeError', () => {
289327
'Must provide fallback error with integer number code and string message.',
290328
);
291329
});
292-
293-
it('handles arrays passed as error', () => {
294-
const error = ['foo', Symbol('bar'), { baz: 'qux', symbol: Symbol('') }];
295-
const result = serializeError(error);
296-
expect(result).toStrictEqual({
297-
code: rpcCodes.internal,
298-
message: getMessageFromCode(rpcCodes.internal),
299-
data: {
300-
cause: ['foo', null, { baz: 'qux' }],
301-
},
302-
});
303-
304-
expect(JSON.parse(JSON.stringify(result))).toStrictEqual({
305-
code: rpcCodes.internal,
306-
message: getMessageFromCode(rpcCodes.internal),
307-
data: {
308-
cause: ['foo', null, { baz: 'qux' }],
309-
},
310-
});
311-
});
312330
});
313331

314332
describe('dataHasCause', () => {

src/utils.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,28 @@ export function isValidCode(code: unknown): code is number {
9696
* @param error - The error to serialize.
9797
* @param options - Options bag.
9898
* @param options.fallbackError - The error to return if the given error is
99-
* not compatible. Should be a JSON serializable value.
99+
* not compatible. Should be a JSON-serializable value.
100100
* @param options.shouldIncludeStack - Whether to include the error's stack
101101
* on the returned object.
102+
* @param options.shouldPreserveMessage - Whether to preserve the error's
103+
* message if the fallback error is used.
102104
* @returns The serialized error.
103105
*/
104106
export function serializeError(
105107
error: unknown,
106-
{ fallbackError = FALLBACK_ERROR, shouldIncludeStack = true } = {},
108+
{
109+
fallbackError = FALLBACK_ERROR,
110+
shouldIncludeStack = true,
111+
shouldPreserveMessage = true,
112+
} = {},
107113
): SerializedJsonRpcError {
108114
if (!isJsonRpcError(fallbackError)) {
109115
throw new Error(
110116
'Must provide fallback error with integer number code and string message.',
111117
);
112118
}
113119

114-
const serialized = buildError(error, fallbackError);
120+
const serialized = buildError(error, fallbackError, shouldPreserveMessage);
115121

116122
if (!shouldIncludeStack) {
117123
delete serialized.stack;
@@ -121,15 +127,18 @@ export function serializeError(
121127
}
122128

123129
/**
124-
* Construct a JSON-serializable object given an error and a JSON serializable `fallbackError`
130+
* Construct a JSON-serializable object given an error and a JSON-serializable `fallbackError`
125131
*
126132
* @param error - The error in question.
127-
* @param fallbackError - A JSON serializable fallback error.
128-
* @returns A JSON serializable error object.
133+
* @param fallbackError - A JSON-serializable fallback error.
134+
* @param shouldPreserveMessage - Whether to preserve the error's message if the fallback
135+
* error is used.
136+
* @returns A JSON-serializable error object.
129137
*/
130138
function buildError(
131139
error: unknown,
132140
fallbackError: SerializedJsonRpcError,
141+
shouldPreserveMessage: boolean,
133142
): SerializedJsonRpcError {
134143
// If an error specifies a `serialize` function, we call it and return the result.
135144
if (
@@ -151,7 +160,8 @@ function buildError(
151160
const cause = serializeCause(error);
152161
const fallbackWithCause = {
153162
...fallbackError,
154-
...(originalMessage && { message: originalMessage }),
163+
...(shouldPreserveMessage &&
164+
originalMessage && { message: originalMessage }),
155165
data: { cause },
156166
};
157167

0 commit comments

Comments
 (0)