From 1f012329e3522a79480117f53a22a1aac154a0b1 Mon Sep 17 00:00:00 2001
From: Steven Luscher <steveluscher@users.noreply.github.com>
Date: Fri, 23 Feb 2024 23:15:43 +0000
Subject: [PATCH] Reject requests with `AbortSignal` reason

---
 fetch.js     |   4 +-
 test/test.js | 110 ++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 107 insertions(+), 7 deletions(-)

diff --git a/fetch.js b/fetch.js
index f39a983a..0fca6ccb 100644
--- a/fetch.js
+++ b/fetch.js
@@ -528,7 +528,7 @@ export function fetch(input, init) {
     var request = new Request(input, init)
 
     if (request.signal && request.signal.aborted) {
-      return reject(new DOMException('Aborted', 'AbortError'))
+      return reject(request.signal.reason);
     }
 
     var xhr = new XMLHttpRequest()
@@ -570,7 +570,7 @@ export function fetch(input, init) {
 
     xhr.onabort = function() {
       setTimeout(function() {
-        reject(new DOMException('Aborted', 'AbortError'))
+        reject(request.signal ? request.signal.reason : new DOMException('Aborted', 'AbortError'))
       }, 0)
     }
 
diff --git a/test/test.js b/test/test.js
index ce0007c0..d29d5f15 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1205,7 +1205,7 @@ exercise.forEach(function(exerciseMode) {
           assert.deepEqual(controller.signal, request.signal);
         })
 
-        test('initially aborted signal', function () {
+        test('initially aborted signal without reason', function () {
           var controller = new AbortController()
           controller.abort()
 
@@ -1221,8 +1221,24 @@ exercise.forEach(function(exerciseMode) {
             }
           )
         })
+        
+        test('initially aborted signal with reason', function () {
+          var controller = new AbortController()
+          controller.abort('Something bad happened')
 
-        test('initially aborted signal within Request', function() {
+          return fetch('/request', {
+            signal: controller.signal
+          }).then(
+            function() {
+              assert.ok(false)
+            },
+            function(error) {
+              assert.equal(error, 'Something bad happened')
+            }
+          )
+        })
+
+        test('initially aborted signal without reason within Request', function() {
           var controller = new AbortController()
           controller.abort()
 
@@ -1238,7 +1254,23 @@ exercise.forEach(function(exerciseMode) {
           )
         })
 
-        test('mid-request', function() {
+        test('initially aborted signal with reason within Request', function() {
+          var controller = new AbortController()
+          controller.abort('Something bad happened')
+
+          var request = new Request('/request', {signal: controller.signal})
+
+          return fetch(request).then(
+            function() {
+              assert.ok(false)
+            },
+            function(error) {
+              assert.equal(error, 'Something bad happened')
+            }
+          )
+        })
+
+        test('mid-request without reason', function() {
           var controller = new AbortController()
 
           setTimeout(function() {
@@ -1256,8 +1288,27 @@ exercise.forEach(function(exerciseMode) {
             }
           )
         })
+        
+        test('mid-request with reason', function() {
+          var controller = new AbortController()
+
+          setTimeout(function() {
+            controller.abort('Something bad happened')
+          }, 30)
+
+          return fetch('/slow?_=' + new Date().getTime(), {
+            signal: controller.signal
+          }).then(
+            function() {
+              assert.ok(false)
+            },
+            function(error) {
+              assert.equal(error, 'Something bad happened')
+            }
+          )
+        })
 
-        test('mid-request within Request', function() {
+        test('mid-request without reason within Request', function() {
           var controller = new AbortController()
           var request = new Request('/slow?_=' + new Date().getTime(), {signal: controller.signal})
 
@@ -1275,7 +1326,25 @@ exercise.forEach(function(exerciseMode) {
           )
         })
 
-        test('abort multiple with same signal', function() {
+        test('mid-request with reason within Request', function() {
+          var controller = new AbortController()
+          var request = new Request('/slow?_=' + new Date().getTime(), {signal: controller.signal})
+
+          setTimeout(function() {
+            controller.abort('Something bad happened')
+          }, 30)
+
+          return fetch(request).then(
+            function() {
+              assert.ok(false)
+            },
+            function(error) {
+              assert.equal(error, 'Something bad happened')
+            }
+          )
+        })
+
+        test('abort multiple without reason with same signal', function() {
           var controller = new AbortController()
 
           setTimeout(function() {
@@ -1305,6 +1374,37 @@ exercise.forEach(function(exerciseMode) {
             )
           ])
         })
+
+        test('abort multiple with reason with same signal', function() {
+          var controller = new AbortController()
+
+          setTimeout(function() {
+            controller.abort('Something bad happened')
+          }, 30)
+
+          return Promise.all([
+            fetch('/slow?_=' + new Date().getTime(), {
+              signal: controller.signal
+            }).then(
+              function() {
+                assert.ok(false)
+              },
+              function(error) {
+                assert.equal(error, 'Something bad happened')
+              }
+            ),
+            fetch('/slow?_=' + new Date().getTime(), {
+              signal: controller.signal
+            }).then(
+              function() {
+                assert.ok(false)
+              },
+              function(error) {
+                assert.equal(error, 'Something bad happened')
+              }
+            )
+          ])
+        })
       })
 
       suite('response', function() {