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
This commit is contained in:
Pierre Gayvallet 2020-02-14 11:50:16 +01:00 committed by GitHub
parent c23d770536
commit 6f6cc356f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 12 deletions

View file

@ -16,6 +16,7 @@ export interface IHttpFetchError extends Error
| Property | Type | Description |
| --- | --- | --- |
| [body](./kibana-plugin-public.ihttpfetcherror.body.md) | <code>any</code> | |
| [name](./kibana-plugin-public.ihttpfetcherror.name.md) | <code>string</code> | |
| [req](./kibana-plugin-public.ihttpfetcherror.req.md) | <code>Request</code> | |
| [request](./kibana-plugin-public.ihttpfetcherror.request.md) | <code>Request</code> | |
| [res](./kibana-plugin-public.ihttpfetcherror.res.md) | <code>Response</code> | |

View file

@ -37,6 +37,7 @@ describe('Fetch', () => {
});
afterEach(() => {
fetchMock.restore();
fetchInstance.removeAllInterceptors();
});
describe('http requests', () => {
@ -287,6 +288,42 @@ describe('Fetch', () => {
});
});
it('preserves the name of the original error', async () => {
expect.assertions(1);
const abortError = new DOMException('The operation was aborted.', 'AbortError');
fetchMock.get('*', Promise.reject(abortError));
await fetchInstance.fetch('/my/path').catch(e => {
expect(e.name).toEqual('AbortError');
});
});
it('exposes the request to the interceptors in case of aborted request', async () => {
const responseErrorSpy = jest.fn();
const abortError = new DOMException('The operation was aborted.', 'AbortError');
fetchMock.get('*', Promise.reject(abortError));
fetchInstance.intercept({
responseError: responseErrorSpy,
});
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow();
expect(responseErrorSpy).toHaveBeenCalledTimes(1);
const interceptedResponse = responseErrorSpy.mock.calls[0][0];
expect(interceptedResponse.request).toEqual(
expect.objectContaining({
method: 'GET',
url: 'http://localhost/myBase/my/path',
})
);
expect(interceptedResponse.error.name).toEqual('AbortError');
});
it('should support get() helper', async () => {
fetchMock.get('*', {});
await fetchInstance.get('/my/path', { method: 'POST' });
@ -368,11 +405,6 @@ describe('Fetch', () => {
fetchMock.get('*', { foo: 'bar' });
});
afterEach(() => {
fetchMock.restore();
fetchInstance.removeAllInterceptors();
});
it('should make request and receive response', async () => {
fetchInstance.intercept({});

View file

@ -146,11 +146,7 @@ export class Fetch {
try {
response = await window.fetch(request);
} catch (err) {
if (err.name === 'AbortError') {
throw err;
} else {
throw new HttpFetchError(err.message, request);
}
throw new HttpFetchError(err.message, err.name ?? 'Error', request);
}
const contentType = response.headers.get('Content-Type') || '';
@ -170,11 +166,11 @@ export class Fetch {
}
}
} catch (err) {
throw new HttpFetchError(err.message, request, response, body);
throw new HttpFetchError(err.message, err.name ?? 'Error', request, response, body);
}
if (!response.ok) {
throw new HttpFetchError(response.statusText, request, response, body);
throw new HttpFetchError(response.statusText, 'Error', request, response, body);
}
return { fetchOptions, request, response, body };

View file

@ -21,16 +21,19 @@ import { IHttpFetchError } from './types';
/** @internal */
export class HttpFetchError extends Error implements IHttpFetchError {
public readonly name: string;
public readonly req: Request;
public readonly res?: Response;
constructor(
message: string,
name: string,
public readonly request: Request,
public readonly response?: Response,
public readonly body?: any
) {
super(message);
this.name = name;
this.req = request;
this.res = response;

View file

@ -291,6 +291,7 @@ export interface IHttpResponseInterceptorOverrides<TResponseBody = any> {
/** @public */
export interface IHttpFetchError extends Error {
readonly name: string;
readonly request: Request;
readonly response?: Response;
/**

View file

@ -733,6 +733,8 @@ export type IContextProvider<THandler extends HandlerFunction<any>, TContextName
export interface IHttpFetchError extends Error {
// (undocumented)
readonly body?: any;
// (undocumented)
readonly name: string;
// @deprecated (undocumented)
readonly req: Request;
// (undocumented)