@@ -206,3 +206,94 @@ test('empty', async () => {
206206 expect ( signal . addEventListener ) . toHaveBeenCalledTimes ( 0 ) ;
207207 expect ( signal . removeEventListener ) . toHaveBeenCalledTimes ( 0 ) ;
208208} ) ;
209+
210+ test ( 'abort with custom reason' , async ( ) => {
211+ const abortController = new AbortController ( ) ;
212+ const signal = abortController . signal ;
213+
214+ const customReason = new Error ( 'Custom abort reason' ) ;
215+
216+ const deferred1 = defer < string > ( ) ;
217+ const deferred2 = defer < number > ( ) ;
218+
219+ let innerSignal : AbortSignal ;
220+
221+ const promise = all ( signal , signal => {
222+ innerSignal = signal ;
223+ return [ deferred1 . promise , deferred2 . promise ] ;
224+ } ) ;
225+
226+ abortController . abort ( customReason ) ;
227+
228+ expect ( innerSignal ! . aborted ) . toBe ( true ) ;
229+
230+ // When external signal is aborted with custom reason,
231+ // promises should reject with AbortError
232+ deferred1 . reject ( new AbortError ( ) ) ;
233+ deferred2 . reject ( new AbortError ( ) ) ;
234+
235+ // The result should be AbortError (first rejection), not custom reason
236+ await expect ( promise ) . rejects . toMatchObject ( {
237+ name : 'AbortError' ,
238+ } ) ;
239+ } ) ;
240+
241+ test ( 'abort before all with custom reason' , async ( ) => {
242+ const abortController = new AbortController ( ) ;
243+ const signal = abortController . signal ;
244+
245+ const customReason = new Error ( 'Custom abort reason' ) ;
246+ abortController . abort ( customReason ) ;
247+
248+ const executor = jest . fn ( ( signal : AbortSignal ) => [ Promise . resolve ( 'test' ) ] ) ;
249+
250+ await expect ( all ( signal , executor ) ) . rejects . toBe ( customReason ) ;
251+
252+ expect ( executor ) . not . toHaveBeenCalled ( ) ;
253+ } ) ;
254+
255+ test ( 'innerSignal receives custom reason on external abort' , async ( ) => {
256+ const abortController = new AbortController ( ) ;
257+ const signal = abortController . signal ;
258+
259+ const customReason = new Error ( 'Custom abort reason' ) ;
260+
261+ const deferred1 = defer < string > ( ) ;
262+
263+ let innerSignal : AbortSignal ;
264+
265+ all ( signal , signal => {
266+ innerSignal = signal ;
267+ return [ deferred1 . promise ] ;
268+ } ) ;
269+
270+ abortController . abort ( customReason ) ;
271+
272+ expect ( innerSignal ! . aborted ) . toBe ( true ) ;
273+ expect ( innerSignal ! . reason ) . toBe ( customReason ) ;
274+ } ) ;
275+
276+ test ( 'innerSignal receives descriptive reason on promise rejection' , async ( ) => {
277+ const abortController = new AbortController ( ) ;
278+ const signal = abortController . signal ;
279+
280+ const deferred1 = defer < string > ( ) ;
281+ const deferred2 = defer < number > ( ) ;
282+
283+ let innerSignal : AbortSignal ;
284+
285+ all ( signal , signal => {
286+ innerSignal = signal ;
287+ return [ deferred1 . promise , deferred2 . promise ] ;
288+ } ) ;
289+
290+ deferred1 . reject ( new Error ( 'test' ) ) ;
291+
292+ await nextTick ( ) ;
293+
294+ expect ( innerSignal ! . aborted ) . toBe ( true ) ;
295+ expect ( innerSignal ! . reason ) . toMatchObject ( {
296+ name : 'AbortError' ,
297+ message : 'One of the promises passed to all() rejected' ,
298+ } ) ;
299+ } ) ;
0 commit comments