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