@@ -18,6 +18,8 @@ const {
1818} = require ( 'node:util' )
1919const { InvalidArgumentError } = require ( '../core/errors' )
2020
21+ const requestAborted = Symbol ( 'request aborted' )
22+
2123function matchValue ( match , value ) {
2224 if ( typeof match === 'string' ) {
2325 return match === value
@@ -295,13 +297,9 @@ function mockDispatch (opts, handler) {
295297
296298 mockDispatch . timesInvoked ++
297299
298- // Here's where we resolve a callback if a callback is present for the dispatch data.
299- if ( mockDispatch . data . callback ) {
300- mockDispatch . data = { ...mockDispatch . data , ...mockDispatch . data . callback ( opts ) }
301- }
302-
303300 // Parse mockDispatch data
304- const { data : { statusCode, data, headers, trailers, error } , delay, persist } = mockDispatch
301+ const { data : response , delay, persist } = mockDispatch
302+ const { error } = response
305303 const { timesInvoked, times } = mockDispatch
306304
307305 // If it's used up and not persistent, mark as consumed
@@ -359,7 +357,7 @@ function mockDispatch (opts, handler) {
359357
360358 if ( isPromise ( requestBody ) ) {
361359 requestBody . then ( ( body ) => {
362- if ( body === null ) {
360+ if ( body === requestAborted ) {
363361 return
364362 }
365363 if ( body !== opts . body ) {
@@ -370,7 +368,7 @@ function mockDispatch (opts, handler) {
370368 return true
371369 }
372370
373- if ( requestBody === null ) {
371+ if ( requestBody === requestAborted ) {
374372 return true
375373 }
376374
@@ -392,19 +390,27 @@ function mockDispatch (opts, handler) {
392390 }
393391 }
394392
395- function handleReply ( mockDispatches , _data = data ) {
393+ function handleReply ( mockDispatches , _response = response ) {
396394 // Don't send response if the request was aborted
397395 if ( aborted ) {
398396 return
399397 }
400398
399+ if ( _response . callback ) {
400+ const { callback, ...responseDefaults } = _response
401+ mockDispatch . data = { ...responseDefaults , ...callback ( replyOpts ) }
402+ return handleReply ( mockDispatches , mockDispatch . data )
403+ }
404+
405+ const { statusCode, data, headers, trailers } = _response
406+
401407 // fetch's HeadersList is a 1D string array
402408 const optsHeaders = Array . isArray ( opts . headers )
403409 ? buildHeadersFromArray ( opts . headers )
404410 : opts . headers
405- const body = typeof _data === 'function'
406- ? _data ( { ...replyOpts , headers : optsHeaders } )
407- : _data
411+ const body = typeof data === 'function'
412+ ? data ( { ...replyOpts , headers : optsHeaders } )
413+ : data
408414
409415 // util.types.isPromise is likely needed for jest.
410416 if ( isPromise ( body ) ) {
@@ -413,7 +419,7 @@ function mockDispatch (opts, handler) {
413419 // synchronously throw the error, which breaks some tests.
414420 // Rather, we wait for the callback to resolve if it is a
415421 // promise, and then re-run handleReply with the new body.
416- return body . then ( ( newData ) => handleReply ( mockDispatches , newData ) )
422+ return body . then ( ( newData ) => handleReply ( mockDispatches , { ... _response , data : newData } ) )
417423 }
418424
419425 // Check again if aborted after async body resolution
@@ -444,7 +450,7 @@ function dispatchRequestBody (body, handler, controller, isAborted) {
444450 }
445451
446452 if ( body == null ) {
447- return callOnRequestSent ( handler , controller ) ? body : null
453+ return callOnRequestSent ( handler , controller , isAborted ) ? body : requestAborted
448454 }
449455
450456 if ( body && typeof body [ Symbol . asyncIterator ] === 'function' ) {
@@ -456,42 +462,42 @@ function dispatchRequestBody (body, handler, controller, isAborted) {
456462
457463 for ( const chunk of body ) {
458464 if ( isAborted ( ) ) {
459- return null
465+ return requestAborted
460466 }
461467 chunks . push ( chunk )
462- if ( ! callOnBodySent ( handler , controller , chunk ) ) {
463- return null
468+ if ( ! callOnBodySent ( handler , controller , chunk ) || isAborted ( ) ) {
469+ return requestAborted
464470 }
465471 }
466472
467- return ! isAborted ( ) && callOnRequestSent ( handler , controller ) ? chunks : null
473+ return callOnRequestSent ( handler , controller , isAborted ) ? chunks : requestAborted
468474 }
469475
470476 if ( isAborted ( ) ) {
471- return null
477+ return requestAborted
472478 }
473479 if ( ! callOnBodySent ( handler , controller , body ) ) {
474- return null
480+ return requestAborted
475481 }
476482
477- return ! isAborted ( ) && callOnRequestSent ( handler , controller ) ? body : null
483+ return callOnRequestSent ( handler , controller , isAborted ) ? body : requestAborted
478484}
479485
480486async function dispatchAsyncIterableBody ( body , handler , controller , isAborted ) {
481487 const chunks = [ ]
482488
483489 for await ( const chunk of body ) {
484490 if ( isAborted ( ) ) {
485- return null
491+ return requestAborted
486492 }
487493 chunks . push ( chunk )
488- if ( ! callOnBodySent ( handler , controller , chunk ) ) {
489- return null
494+ if ( ! callOnBodySent ( handler , controller , chunk ) || isAborted ( ) ) {
495+ return requestAborted
490496 }
491497 }
492498
493- if ( isAborted ( ) || ! callOnRequestSent ( handler , controller ) ) {
494- return null
499+ if ( ! callOnRequestSent ( handler , controller , isAborted ) ) {
500+ return requestAborted
495501 }
496502
497503 return {
@@ -511,10 +517,10 @@ function callOnBodySent (handler, controller, chunk) {
511517 }
512518}
513519
514- function callOnRequestSent ( handler , controller ) {
520+ function callOnRequestSent ( handler , controller , isAborted ) {
515521 try {
516522 handler . onRequestSent ?. ( )
517- return true
523+ return ! isAborted ( )
518524 } catch ( error ) {
519525 controller . abort ( error )
520526 return false
0 commit comments