Skip to content

Commit f27e8d3

Browse files
committedJul 1, 2021
Merge #1739 into Got 12
1 parent 1e1e506 commit f27e8d3

14 files changed

+73
-23
lines changed
 

‎source/as-promise/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class CancelError extends RequestError {
1515
constructor(request: Request) {
1616
super('Promise was canceled', {}, request);
1717
this.name = 'CancelError';
18+
this.code = 'ERR_CANCELED';
1819
}
1920

2021
get isCanceled() {

‎source/core/calculate-retry-delay.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const calculateRetryDelay: Returns<RetryFunction, number> = ({
1818
}
1919

2020
const hasMethod = retryOptions.methods.includes(error.options.method);
21-
const hasErrorCode = retryOptions.errorCodes.includes(error.code!);
21+
const hasErrorCode = retryOptions.errorCodes.includes(error.code);
2222
const hasStatusCode = error.response && retryOptions.statusCodes.includes(error.response.statusCode);
2323
if (!hasMethod || (!hasErrorCode && !hasStatusCode)) {
2424
return 0;

‎source/core/errors.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Contains a `code` property with error class code, like `ECONNREFUSED`.
1919
export class RequestError extends Error {
2020
input?: string;
2121

22-
code?: string;
22+
code: string;
2323
stack!: string;
2424
declare readonly options: Options;
2525
readonly response?: Response;
@@ -31,7 +31,7 @@ export class RequestError extends Error {
3131
Error.captureStackTrace(this, this.constructor);
3232

3333
this.name = 'RequestError';
34-
this.code = error.code;
34+
this.code = error.code ?? 'ERR_GOT_REQUEST_ERROR';
3535
this.input = (error as any).input;
3636

3737
if (isRequest(self)) {
@@ -80,6 +80,7 @@ export class MaxRedirectsError extends RequestError {
8080
constructor(request: Request) {
8181
super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
8282
this.name = 'MaxRedirectsError';
83+
this.code = 'ERR_TOO_MANY_REDIRECTS';
8384
}
8485
}
8586

@@ -95,6 +96,7 @@ export class HTTPError extends RequestError {
9596
constructor(response: PlainResponse) {
9697
super(`Response code ${response.statusCode} (${response.statusMessage!})`, {}, response.request);
9798
this.name = 'HTTPError';
99+
this.code = 'ERR_NON_2XX_3XX_RESPONSE';
98100
}
99101
}
100102

@@ -108,6 +110,7 @@ export class CacheError extends RequestError {
108110
constructor(error: Error, request: Request) {
109111
super(error.message, error, request);
110112
this.name = 'CacheError';
113+
this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_CACHE_ACCESS' : this.code;
111114
}
112115
}
113116

@@ -120,6 +123,7 @@ export class UploadError extends RequestError {
120123
constructor(error: Error, request: Request) {
121124
super(error.message, error, request);
122125
this.name = 'UploadError';
126+
this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_UPLOAD' : this.code;
123127
}
124128
}
125129

@@ -151,6 +155,7 @@ export class ReadError extends RequestError {
151155
constructor(error: Error, request: Request) {
152156
super(error.message, error, request);
153157
this.name = 'ReadError';
158+
this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_READING_RESPONSE_STREAM' : this.code;
154159
}
155160
}
156161

‎source/core/options.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,10 @@ export default class Options {
11661166
}
11671167

11681168
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
1169-
throw new Error(`Unsupported protocol: ${url.protocol}`);
1169+
const error: NodeJS.ErrnoException = new Error(`Unsupported protocol: ${url.protocol}`);
1170+
error.code = 'ERR_UNSUPPORTED_PROTOCOL';
1171+
1172+
throw error;
11701173
}
11711174

11721175
if (this._internals.username) {

‎source/core/response.ts

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export class ParseError extends RequestError {
123123

124124
super(`${error.message} in "${options.url!.toString()}"`, error, response.request);
125125
this.name = 'ParseError';
126+
this.code = 'ERR_BODY_PARSE_FAILURE';
126127
}
127128
}
128129

‎test/cache.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ test('cache error throws `CacheError`', withServer, async (t, server, got) => {
121121
const cache = {};
122122

123123
// @ts-expect-error Error tests
124-
await t.throwsAsync(got({cache}), {instanceOf: CacheError});
124+
await t.throwsAsync(got({cache}), {
125+
instanceOf: CacheError,
126+
code: 'ERR_CACHE_ACCESS'
127+
});
125128
});
126129

127130
test('doesn\'t cache response when received HTTP error', withServer, async (t, server, got) => {

‎test/cancel.ts

+24-6
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ test.serial('does not retry after cancelation', withServerAndFakeTimers, async (
7878
gotPromise.cancel();
7979
});
8080

81-
await t.throwsAsync(gotPromise, {instanceOf: CancelError});
81+
await t.throwsAsync(gotPromise, {
82+
instanceOf: CancelError,
83+
code: 'ERR_CANCELED'
84+
});
8285
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
8386
});
8487

@@ -105,7 +108,10 @@ test.serial('cleans up request timeouts', withServer, async (t, server, got) =>
105108
}
106109
});
107110

108-
await t.throwsAsync(gotPromise, {instanceOf: CancelError});
111+
await t.throwsAsync(gotPromise, {
112+
instanceOf: CancelError,
113+
code: 'ERR_CANCELED'
114+
});
109115

110116
// Wait for unhandled errors
111117
await delay(40);
@@ -127,7 +133,10 @@ test.serial('cancels in-progress request', withServerAndFakeTimers, async (t, se
127133
body.push(null);
128134
});
129135

130-
await t.throwsAsync(gotPromise, {instanceOf: CancelError});
136+
await t.throwsAsync(gotPromise, {
137+
instanceOf: CancelError,
138+
code: 'ERR_CANCELED'
139+
});
131140
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
132141
});
133142

@@ -147,7 +156,10 @@ test.serial('cancels in-progress request with timeout', withServerAndFakeTimers,
147156
body.push(null);
148157
});
149158

150-
await t.throwsAsync(gotPromise, {instanceOf: CancelError});
159+
await t.throwsAsync(gotPromise, {
160+
instanceOf: CancelError,
161+
code: 'ERR_CANCELED'
162+
});
151163
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
152164
});
153165

@@ -227,7 +239,10 @@ test.serial('throws on incomplete (canceled) response - promise #2', withServer,
227239
promise.cancel();
228240
}, 500);
229241

230-
await t.throwsAsync(promise, {instanceOf: CancelError});
242+
await t.throwsAsync(promise, {
243+
instanceOf: CancelError,
244+
code: 'ERR_CANCELED'
245+
});
231246
});
232247

233248
test.serial('throws on incomplete (canceled) response - stream', withServerAndFakeTimers, async (t, server, got, clock) => {
@@ -255,5 +270,8 @@ test('throws when canceling cached request', withServer, async (t, server, got)
255270
const promise = got({cache});
256271
promise.cancel();
257272

258-
await t.throwsAsync(promise, {instanceOf: CancelError});
273+
await t.throwsAsync(promise, {
274+
instanceOf: CancelError,
275+
code: 'ERR_CANCELED'
276+
});
259277
});

‎test/error.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ test('properties', withServer, async (t, server, got) => {
2727
t.truthy(error.options);
2828
t.true({}.propertyIsEnumerable.call(error, 'options'));
2929
t.false({}.propertyIsEnumerable.call(error, 'response'));
30-
t.is(error.code, undefined);
30+
t.is(error.code, 'ERR_NON_2XX_3XX_RESPONSE');
3131
t.is(error.message, 'Response code 404 (Not Found)');
3232
t.deepEqual(error.options.url, url);
3333
t.is(error.response.headers.connection, 'close');
@@ -40,6 +40,7 @@ test('catches dns errors', async t => {
4040
t.regex(error.message, /ENOTFOUND|EAI_AGAIN/);
4141
t.is((error.options.url as URL).host, 'doesntexist');
4242
t.is(error.options.method, 'GET');
43+
t.is(error.code, 'ENOTFOUND');
4344
});
4445

4546
test('`options.body` form error message', async t => {
@@ -132,7 +133,8 @@ test('`http.request` error', async t => {
132133
}
133134
}), {
134135
instanceOf: RequestError,
135-
message: 'The header content contains invalid characters'
136+
message: 'The header content contains invalid characters',
137+
code: 'ERR_GOT_REQUEST_ERROR'
136138
});
137139
});
138140

@@ -236,7 +238,8 @@ test('promise does not hang on timeout on HTTP error', withServer, async (t, ser
236238
request: 100
237239
}
238240
}), {
239-
instanceOf: TimeoutError
241+
instanceOf: TimeoutError,
242+
code: 'ETIMEDOUT'
240243
});
241244
});
242245

‎test/http.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ test('doesn\'t throw if `options.throwHttpErrors` is false', withServer, async (
9393
test('invalid protocol throws', async t => {
9494
await t.throwsAsync(got('c:/nope.com').json(), {
9595
instanceOf: RequestError,
96-
message: 'Unsupported protocol: c:'
96+
message: 'Unsupported protocol: c:',
97+
code: 'ERR_UNSUPPORTED_PROTOCOL'
9798
});
9899
});
99100

@@ -226,7 +227,8 @@ test('throws an error if the server aborted the request', withServer, async (t,
226227
});
227228

228229
const error = await t.throwsAsync<ReadError>(got(''), {
229-
message: 'The server aborted pending request'
230+
message: 'The server aborted pending request',
231+
code: 'ECONNRESET'
230232
});
231233

232234
t.truthy(error.response.retryCount);

‎test/post.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ test('throws on upload error', withServer, async (t, server, got) => {
334334
}
335335
})), {
336336
instanceOf: UploadError,
337-
message
337+
message,
338+
code: 'ERR_UPLOAD'
338339
});
339340
});
340341

‎test/promise.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,14 @@ test('promise.json() can be called before a file stream body is open', withServe
7171

7272
const promise = got({body});
7373
const checks = [
74-
t.throwsAsync(promise, {instanceOf: CancelError}),
75-
t.throwsAsync(promise.json(), {instanceOf: CancelError})
74+
t.throwsAsync(promise, {
75+
instanceOf: CancelError,
76+
code: 'ERR_CANCELED'
77+
}),
78+
t.throwsAsync(promise.json(), {
79+
instanceOf: CancelError,
80+
code: 'ERR_CANCELED'
81+
})
7682
];
7783

7884
promise.cancel();

‎test/redirects.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ test('throws on endless redirects - default behavior', withServer, async (t, ser
8484
const error = await t.throwsAsync<MaxRedirectsError>(got(''), {message: 'Redirected 10 times. Aborting.'});
8585

8686
t.deepEqual(error.response.redirectUrls.map(x => String(x)), Array.from({length: 10}).fill(`${server.url}/`));
87+
t.is(error.code, 'ERR_TOO_MANY_REDIRECTS');
8788
});
8889

8990
test('custom `maxRedirects` option', withServer, async (t, server, got) => {
@@ -97,6 +98,7 @@ test('custom `maxRedirects` option', withServer, async (t, server, got) => {
9798
const error = await t.throwsAsync<MaxRedirectsError>(got('', {maxRedirects: 5}), {message: 'Redirected 5 times. Aborting.'});
9899

99100
t.deepEqual(error.response.redirectUrls.map(x => String(x)), Array.from({length: 5}).fill(`${server.url}/`));
101+
t.is(error.code, 'ERR_TOO_MANY_REDIRECTS');
100102
});
101103

102104
test('searchParams are not breaking redirects', withServer, async (t, server, got) => {
@@ -123,7 +125,8 @@ test('redirects GET and HEAD requests', withServer, async (t, server, got) => {
123125
});
124126

125127
await t.throwsAsync(got.get(''), {
126-
instanceOf: MaxRedirectsError
128+
instanceOf: MaxRedirectsError,
129+
code: 'ERR_TOO_MANY_REDIRECTS'
127130
});
128131
});
129132

@@ -136,7 +139,8 @@ test('redirects POST requests', withServer, async (t, server, got) => {
136139
});
137140

138141
await t.throwsAsync(got.post({body: 'wow'}), {
139-
instanceOf: MaxRedirectsError
142+
instanceOf: MaxRedirectsError,
143+
code: 'ERR_TOO_MANY_REDIRECTS'
140144
});
141145
});
142146

‎test/response-parse.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ test('wraps parsing errors', withServer, async (t, server, got) => {
9898
const error = await t.throwsAsync<ParseError>(got({responseType: 'json'}), {instanceOf: ParseError});
9999
t.true(error.message.includes((error.options.url as URL).hostname));
100100
t.is((error.options.url as URL).pathname, '/');
101+
t.is(error.code, 'ERR_BODY_PARSE_FAILURE');
101102
});
102103

103104
test('parses non-200 responses', withServer, async (t, server, got) => {
@@ -134,6 +135,7 @@ test('parse errors have `response` property', withServer, async (t, server, got)
134135

135136
t.is(error.response.statusCode, 200);
136137
t.is(error.response.body, '/');
138+
t.is(error.code, 'ERR_BODY_PARSE_FAILURE');
137139
});
138140

139141
test('sets correct headers', withServer, async (t, server, got) => {
@@ -184,7 +186,8 @@ test('shortcuts throw ParseErrors', withServer, async (t, server, got) => {
184186

185187
await t.throwsAsync(got('').json(), {
186188
instanceOf: ParseError,
187-
message: /^Unexpected token o in JSON at position 1 in/
189+
message: /^Unexpected token o in JSON at position 1 in/,
190+
code: 'ERR_BODY_PARSE_FAILURE'
188191
});
189192
});
190193

‎test/retry.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ test('custom error codes', async t => {
188188
},
189189
retry: {
190190
calculateDelay: ({error}) => {
191-
t.is(error.code! as typeof errorCode, errorCode);
191+
t.is(error.code, errorCode);
192192
return 0;
193193
},
194194
methods: [

0 commit comments

Comments
 (0)
Please sign in to comment.