From 7002613721195e657aa6e7d95f3a8326b1968f30 Mon Sep 17 00:00:00 2001 From: medfreeman Date: Fri, 22 Oct 2021 13:55:28 +0200 Subject: [PATCH] fix(redux-requests-fetch): fix handling of request abortion with native `AbortController` Add `isNativeAbortError` guard function & tests Rethrow `'REQUEST_ABORTED'` when a native `AbortError` is emitted --- .../src/fetch-api-driver.js | 8 ++++++++ packages/redux-requests-fetch/src/helpers.js | 7 +++++++ .../redux-requests-fetch/src/helpers.spec.js | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 packages/redux-requests-fetch/src/helpers.js create mode 100644 packages/redux-requests-fetch/src/helpers.spec.js diff --git a/packages/redux-requests-fetch/src/fetch-api-driver.js b/packages/redux-requests-fetch/src/fetch-api-driver.js index 323a98b29..711a4f0bb 100644 --- a/packages/redux-requests-fetch/src/fetch-api-driver.js +++ b/packages/redux-requests-fetch/src/fetch-api-driver.js @@ -1,5 +1,7 @@ import isAbsoluteUrl from 'axios/lib/helpers/isAbsoluteURL'; +import { isNativeAbortError } from './helpers'; + const responseTypes = ['arraybuffer', 'blob', 'formData', 'json', 'text', null]; const getData = (response, responseType) => { @@ -50,6 +52,12 @@ export const createDriver = ( throw response; }, ); + }).catch(error => { + if (isNativeAbortError(error)) { + throw 'REQUEST_ABORTED'; + } + + throw error; }); responsePromise.cancel = () => abortSource.abort(); diff --git a/packages/redux-requests-fetch/src/helpers.js b/packages/redux-requests-fetch/src/helpers.js new file mode 100644 index 000000000..7be95921f --- /dev/null +++ b/packages/redux-requests-fetch/src/helpers.js @@ -0,0 +1,7 @@ +// a real browser will throw an instance of `DomException`, polyfills an instance of `AbortError` +// https://developer.mozilla.org/en-US/docs/Web/API/AbortController#examples +// old browsers would set the exception `code` property equal to DOMException.ABORT_ERR +// https://developer.mozilla.org/en-US/docs/Web/API/DOMException/code +export const isNativeAbortError = err => + ['DOMException', 'AbortError'].includes(err.constructor.name) && + (err.name === 'AbortError' || err.code === DOMException.ABORT_ERR); diff --git a/packages/redux-requests-fetch/src/helpers.spec.js b/packages/redux-requests-fetch/src/helpers.spec.js new file mode 100644 index 000000000..6e9aa55ef --- /dev/null +++ b/packages/redux-requests-fetch/src/helpers.spec.js @@ -0,0 +1,18 @@ +import { isNativeAbortError } from './helpers'; + +describe('helpers', () => { + describe('isNativeAbortError', () => { + + it('properly identifies a native `AbortError`', () => { + expect(isNativeAbortError(new DOMException('request aborted', 'AbortError'))).toBe(true); + }); + + it('does not identify another Error', () => { + expect(isNativeAbortError(new Error())).toBe(false); + }); + + it('does not identify a string', () => { + expect(isNativeAbortError('REQUEST_ABORTED')).toBe(false); + }); + }); +});