diff --git a/src/libs/Middleware/Logging.js b/src/libs/Middleware/Logging.js index 7c76b513eb1f..af58c6d9e0e4 100644 --- a/src/libs/Middleware/Logging.js +++ b/src/libs/Middleware/Logging.js @@ -62,7 +62,9 @@ function Logging(response, request) { if (persisted) { PersistedRequests.remove(request); } - return; + + // Re-throw this error so the next handler can manage it + throw error; } if (error.message === CONST.ERROR.FAILED_TO_FETCH) { diff --git a/src/libs/Middleware/Reauthentication.js b/src/libs/Middleware/Reauthentication.js index d75b3bde86e0..218457b12caf 100644 --- a/src/libs/Middleware/Reauthentication.js +++ b/src/libs/Middleware/Reauthentication.js @@ -18,6 +18,12 @@ import Log from '../Log'; function Reauthentication(response, request, isFromSequentialQueue) { return response .then((data) => { + // If there is no data for some reason then we cannot reauthenticate + if (!data) { + Log.hmmm('Undefined data in Reauthentication'); + return; + } + if (NetworkStore.isOffline()) { // If we are offline and somehow handling this response we do not want to reauthenticate throw new Error('Unable to reauthenticate because we are offline'); diff --git a/src/libs/Middleware/RecheckConnection.js b/src/libs/Middleware/RecheckConnection.js index 59f15c628331..58f5cfa601c8 100644 --- a/src/libs/Middleware/RecheckConnection.js +++ b/src/libs/Middleware/RecheckConnection.js @@ -19,8 +19,11 @@ function RecheckConnection(response) { const cancelRequestTimeoutTimer = startRecheckTimeoutTimer(); return response .catch((error) => { - // Because we ran into an error we assume we might be offline and do a "connection" health test - NetworkConnection.recheckNetworkConnection(); + if (error.name !== CONST.ERROR.REQUEST_CANCELLED) { + // Because we ran into an error we assume we might be offline and do a "connection" health test + NetworkConnection.recheckNetworkConnection(); + } + throw error; }) .finally(cancelRequestTimeoutTimer); diff --git a/src/libs/Middleware/Retry.js b/src/libs/Middleware/Retry.js index c9090ef36d43..779cdb6b7c87 100644 --- a/src/libs/Middleware/Retry.js +++ b/src/libs/Middleware/Retry.js @@ -45,6 +45,11 @@ function retryFailedRequest(queuedRequest, error) { function Retry(response, request, isFromSequentialQueue) { return response .catch((error) => { + // Do not retry any requests that are cancelled + if (error.name === CONST.ERROR.REQUEST_CANCELLED) { + return; + } + if (isFromSequentialQueue) { const retryCount = PersistedRequests.incrementRetries(request); Log.info('Persisted request failed', false, {retryCount, command: request.command, error: error.message}); diff --git a/src/libs/Network/MainQueue.js b/src/libs/Network/MainQueue.js index 2070959668ce..2143cee9d851 100644 --- a/src/libs/Network/MainQueue.js +++ b/src/libs/Network/MainQueue.js @@ -89,9 +89,17 @@ function clear() { HttpUtils.cancelPendingRequests(); } +/** + * @returns {Array} + */ +function getAll() { + return networkRequestQueue; +} + export { clear, replay, push, process, + getAll, }; diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js index d8eade984048..e03c472f1557 100644 --- a/tests/unit/NetworkTest.js +++ b/tests/unit/NetworkTest.js @@ -765,3 +765,27 @@ test('persistable request will move directly to the SequentialQueue when we are expect(thirdRequestCommandName).toBe('MockCommandTwo'); }); }); + +test('cancelled requests should not be retried', () => { + const xhr = jest.spyOn(HttpUtils, 'xhr'); + + // GIVEN a mock that will return a "cancelled" request error + global.fetch = jest.fn() + .mockRejectedValue(new DOMException('Aborted', CONST.ERROR.REQUEST_CANCELLED)); + + return Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}) + .then(() => { + // WHEN we make a few requests and then cancel them + Network.post('MockCommandOne'); + Network.post('MockCommandTwo'); + Network.post('MockCommandThree'); + + // WHEN we wait for the requests to all cancel + return waitForPromisesToResolve(); + }) + .then(() => { + // THEN expect our queue to be empty and for no requests to have been retried + expect(MainQueue.getAll().length).toBe(0); + expect(xhr.mock.calls.length).toBe(3); + }); +});