Skip to content

Commit 6f6cc35

Browse files
authored
Preserve the original error name instead of returning raw AbortError (#57550) (#57653)
* Preserve the original error name instead of returning raw AbortError * use Error as the default error name
1 parent c23d770 commit 6f6cc35

File tree

6 files changed

+47
-12
lines changed

6 files changed

+47
-12
lines changed

docs/development/core/public/kibana-plugin-public.ihttpfetcherror.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface IHttpFetchError extends Error
1616
| Property | Type | Description |
1717
| --- | --- | --- |
1818
| [body](./kibana-plugin-public.ihttpfetcherror.body.md) | <code>any</code> | |
19+
| [name](./kibana-plugin-public.ihttpfetcherror.name.md) | <code>string</code> | |
1920
| [req](./kibana-plugin-public.ihttpfetcherror.req.md) | <code>Request</code> | |
2021
| [request](./kibana-plugin-public.ihttpfetcherror.request.md) | <code>Request</code> | |
2122
| [res](./kibana-plugin-public.ihttpfetcherror.res.md) | <code>Response</code> | |

src/core/public/http/fetch.test.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('Fetch', () => {
3737
});
3838
afterEach(() => {
3939
fetchMock.restore();
40+
fetchInstance.removeAllInterceptors();
4041
});
4142

4243
describe('http requests', () => {
@@ -287,6 +288,42 @@ describe('Fetch', () => {
287288
});
288289
});
289290

291+
it('preserves the name of the original error', async () => {
292+
expect.assertions(1);
293+
294+
const abortError = new DOMException('The operation was aborted.', 'AbortError');
295+
296+
fetchMock.get('*', Promise.reject(abortError));
297+
298+
await fetchInstance.fetch('/my/path').catch(e => {
299+
expect(e.name).toEqual('AbortError');
300+
});
301+
});
302+
303+
it('exposes the request to the interceptors in case of aborted request', async () => {
304+
const responseErrorSpy = jest.fn();
305+
const abortError = new DOMException('The operation was aborted.', 'AbortError');
306+
307+
fetchMock.get('*', Promise.reject(abortError));
308+
309+
fetchInstance.intercept({
310+
responseError: responseErrorSpy,
311+
});
312+
313+
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow();
314+
315+
expect(responseErrorSpy).toHaveBeenCalledTimes(1);
316+
const interceptedResponse = responseErrorSpy.mock.calls[0][0];
317+
318+
expect(interceptedResponse.request).toEqual(
319+
expect.objectContaining({
320+
method: 'GET',
321+
url: 'http://localhost/myBase/my/path',
322+
})
323+
);
324+
expect(interceptedResponse.error.name).toEqual('AbortError');
325+
});
326+
290327
it('should support get() helper', async () => {
291328
fetchMock.get('*', {});
292329
await fetchInstance.get('/my/path', { method: 'POST' });
@@ -368,11 +405,6 @@ describe('Fetch', () => {
368405
fetchMock.get('*', { foo: 'bar' });
369406
});
370407

371-
afterEach(() => {
372-
fetchMock.restore();
373-
fetchInstance.removeAllInterceptors();
374-
});
375-
376408
it('should make request and receive response', async () => {
377409
fetchInstance.intercept({});
378410

src/core/public/http/fetch.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,7 @@ export class Fetch {
146146
try {
147147
response = await window.fetch(request);
148148
} catch (err) {
149-
if (err.name === 'AbortError') {
150-
throw err;
151-
} else {
152-
throw new HttpFetchError(err.message, request);
153-
}
149+
throw new HttpFetchError(err.message, err.name ?? 'Error', request);
154150
}
155151

156152
const contentType = response.headers.get('Content-Type') || '';
@@ -170,11 +166,11 @@ export class Fetch {
170166
}
171167
}
172168
} catch (err) {
173-
throw new HttpFetchError(err.message, request, response, body);
169+
throw new HttpFetchError(err.message, err.name ?? 'Error', request, response, body);
174170
}
175171

176172
if (!response.ok) {
177-
throw new HttpFetchError(response.statusText, request, response, body);
173+
throw new HttpFetchError(response.statusText, 'Error', request, response, body);
178174
}
179175

180176
return { fetchOptions, request, response, body };

src/core/public/http/http_fetch_error.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@ import { IHttpFetchError } from './types';
2121

2222
/** @internal */
2323
export class HttpFetchError extends Error implements IHttpFetchError {
24+
public readonly name: string;
2425
public readonly req: Request;
2526
public readonly res?: Response;
2627

2728
constructor(
2829
message: string,
30+
name: string,
2931
public readonly request: Request,
3032
public readonly response?: Response,
3133
public readonly body?: any
3234
) {
3335
super(message);
36+
this.name = name;
3437
this.req = request;
3538
this.res = response;
3639

src/core/public/http/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ export interface IHttpResponseInterceptorOverrides<TResponseBody = any> {
291291

292292
/** @public */
293293
export interface IHttpFetchError extends Error {
294+
readonly name: string;
294295
readonly request: Request;
295296
readonly response?: Response;
296297
/**

src/core/public/public.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,8 @@ export type IContextProvider<THandler extends HandlerFunction<any>, TContextName
733733
export interface IHttpFetchError extends Error {
734734
// (undocumented)
735735
readonly body?: any;
736+
// (undocumented)
737+
readonly name: string;
736738
// @deprecated (undocumented)
737739
readonly req: Request;
738740
// (undocumented)

0 commit comments

Comments
 (0)