diff --git a/fetch.js b/fetch.js index f39a983a..88d37bdb 100644 --- a/fetch.js +++ b/fetch.js @@ -226,8 +226,8 @@ function Body() { /* fetch-mock wraps the Response object in an ES6 Proxy to provide useful test harness features such as flush. However, on - ES5 browsers without fetch or Proxy support pollyfills must be used; - the proxy-pollyfill is unable to proxy an attribute unless it exists + ES5 browsers without fetch or Proxy support polyfills must be used; + the proxy-polyfill is unable to proxy an attribute unless it exists on the object before the Proxy is created. This change ensures Response.bodyUsed exists on the instance, while maintaining the semantic of setting Request.bodyUsed in the constructor before @@ -528,6 +528,9 @@ export function fetch(input, init) { var request = new Request(input, init) if (request.signal && request.signal.aborted) { + if (request.signal.throwIfAborted) { + request.signal.throwIfAborted() + } return reject(new DOMException('Aborted', 'AbortError')) } @@ -570,7 +573,15 @@ export function fetch(input, init) { xhr.onabort = function() { setTimeout(function() { - reject(new DOMException('Aborted', 'AbortError')) + if (request.signal && request.signal.aborted && request.signal.throwIfAborted) { + try { + request.signal.throwIfAborted() + } catch (e) { + reject(e) + } + } else { + reject(new DOMException('Aborted', 'AbortError')) + } }, 0) } diff --git a/test/test.js b/test/test.js index ce0007c0..d32a10bf 100644 --- a/test/test.js +++ b/test/test.js @@ -1238,6 +1238,49 @@ exercise.forEach(function(exerciseMode) { ) }) + test('initially timed-out signal', function() { + var signal = AbortSignal.timeout(0) + var sleep = new Promise((resolve) => { + setTimeout(function() { + resolve() + }, 10) + }) + + return sleep.then(function() { + return fetch('/request', {signal}) + }).then( + function() { + assert.ok(false) + }, + function(error) { + if (!IEorEdge) assert.instanceOf(error, WHATWGFetch.DOMException) + assert.equal(error.name, 'TimeoutError') + } + ) + }) + + test('initially timed-out signal within Request', function() { + var signal = AbortSignal.timeout(0) + var sleep = new Promise((resolve) => { + setTimeout(function() { + resolve() + }, 10) + }) + + return sleep.then(function() { + var request = new Request('/request', {signal}) + return fetch(request) + }).then( + function() { + assert.ok(false) + }, + function(error) { + if (!IEorEdge) assert.instanceOf(error, WHATWGFetch.DOMException) + assert.equal(error.name, 'TimeoutError') + } + ) + }) + test('mid-request', function() { var controller = new AbortController() @@ -1275,6 +1318,82 @@ exercise.forEach(function(exerciseMode) { ) }) + test('mid-request with custom abort reason', function() { + var controller = new AbortController() + + setTimeout(function() { + controller.abort('CustomReason') + }, 30) + + return fetch('/slow?_=' + new Date().getTime(), { + signal: controller.signal + }).then( + function() { + assert.ok(false) + }, + function(error) { + // https://bugs.webkit.org/show_bug.cgi?id=246069 + if (Safari && exerciseMode === 'native') { + assert.equal(error.name, 'AbortError') + } else { + assert.equal(error, 'CustomReason') + } + } + ) + }) + + test('mid-request with custom abort reason within Request', function() { + var controller = new AbortController() + var request = new Request('/slow?_=' + new Date().getTime(), {signal: controller.signal}) + + setTimeout(function() { + controller.abort('CustomReason') + }, 30) + + return fetch(request).then( + function() { + assert.ok(false) + }, + function(error) { + // https://bugs.webkit.org/show_bug.cgi?id=246069 + if (Safari && exerciseMode === 'native') { + assert.equal(error.name, 'AbortError') + } else { + assert.equal(error, 'CustomReason') + } + } + ) + }) + + test('mid-request timeout', function() { + return fetch('/slow?_=' + new Date().getTime(), { + signal: AbortSignal.timeout(30) + }).then( + function() { + assert.ok(false) + }, + function(error) { + // https://bugs.webkit.org/show_bug.cgi?id=246069 + const expected = (Safari && exerciseMode === 'native') ? 'AbortError' : 'TimeoutError' + assert.equal(error.name, expected) + } + ) + }) + + test('mid-request timeout within Request', function() { + var request = new Request('/slow?_=' + new Date().getTime(), {signal: AbortSignal.timeout(30)}) + return fetch(request).then( + function() { + assert.ok(false) + }, + function(error) { + // https://bugs.webkit.org/show_bug.cgi?id=246069 + const expected = (Safari && exerciseMode === 'native') ? 'AbortError' : 'TimeoutError' + assert.equal(error.name, expected) + } + ) + }) + test('abort multiple with same signal', function() { var controller = new AbortController()