@@ -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
@@ -296,6 +298,10 @@ function mockDispatch (opts, handler) {
296298
297299 mockDispatch . timesInvoked ++
298300
301+ // Parse mockDispatch data
302+ const { data : response , delay, persist } = mockDispatch
303+ const { error } = response
304+
299305 const { timesInvoked, times } = mockDispatch
300306
301307 // If it's used up and not persistent, mark as consumed
@@ -388,7 +394,7 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) {
388394
389395 if ( isPromise ( requestBody ) ) {
390396 requestBody . then ( ( body ) => {
391- if ( body === null ) {
397+ if ( body === requestAborted ) {
392398 return
393399 }
394400 if ( body !== opts . body ) {
@@ -399,7 +405,7 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) {
399405 return true
400406 }
401407
402- if ( requestBody === null ) {
408+ if ( requestBody === requestAborted ) {
403409 return true
404410 }
405411
@@ -421,19 +427,27 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) {
421427 }
422428 }
423429
424- function handleReply ( mockDispatches , _data = data ) {
430+ function handleReply ( mockDispatches , _response = response ) {
425431 // Don't send response if the request was aborted
426432 if ( aborted ) {
427433 return
428434 }
429435
436+ if ( _response . callback ) {
437+ const { callback, ...responseDefaults } = _response
438+ mockDispatch . data = { ...responseDefaults , ...callback ( replyOpts ) }
439+ return handleReply ( mockDispatches , mockDispatch . data )
440+ }
441+
442+ const { statusCode, data, headers, trailers } = _response
443+
430444 // fetch's HeadersList is a 1D string array
431445 const optsHeaders = Array . isArray ( opts . headers )
432446 ? buildHeadersFromArray ( opts . headers )
433447 : opts . headers
434- const body = typeof _data === 'function'
435- ? _data ( { ...replyOpts , headers : optsHeaders } )
436- : _data
448+ const body = typeof data === 'function'
449+ ? data ( { ...replyOpts , headers : optsHeaders } )
450+ : data
437451
438452 // util.types.isPromise is likely needed for jest.
439453 if ( isPromise ( body ) ) {
@@ -442,7 +456,7 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) {
442456 // synchronously throw the error, which breaks some tests.
443457 // Rather, we wait for the callback to resolve if it is a
444458 // promise, and then re-run handleReply with the new body.
445- return body . then ( ( newData ) => handleReply ( mockDispatches , newData ) )
459+ return body . then ( ( newData ) => handleReply ( mockDispatches , { ... _response , data : newData } ) )
446460 }
447461
448462 // Check again if aborted after async body resolution
@@ -473,7 +487,7 @@ function dispatchRequestBody (body, handler, controller, isAborted) {
473487 }
474488
475489 if ( body == null ) {
476- return callOnRequestSent ( handler , controller ) ? body : null
490+ return callOnRequestSent ( handler , controller , isAborted ) ? body : requestAborted
477491 }
478492
479493 if ( body && typeof body [ Symbol . asyncIterator ] === 'function' ) {
@@ -485,42 +499,42 @@ function dispatchRequestBody (body, handler, controller, isAborted) {
485499
486500 for ( const chunk of body ) {
487501 if ( isAborted ( ) ) {
488- return null
502+ return requestAborted
489503 }
490504 chunks . push ( chunk )
491- if ( ! callOnBodySent ( handler , controller , chunk ) ) {
492- return null
505+ if ( ! callOnBodySent ( handler , controller , chunk ) || isAborted ( ) ) {
506+ return requestAborted
493507 }
494508 }
495509
496- return ! isAborted ( ) && callOnRequestSent ( handler , controller ) ? chunks : null
510+ return callOnRequestSent ( handler , controller , isAborted ) ? chunks : requestAborted
497511 }
498512
499513 if ( isAborted ( ) ) {
500- return null
514+ return requestAborted
501515 }
502516 if ( ! callOnBodySent ( handler , controller , body ) ) {
503- return null
517+ return requestAborted
504518 }
505519
506- return ! isAborted ( ) && callOnRequestSent ( handler , controller ) ? body : null
520+ return callOnRequestSent ( handler , controller , isAborted ) ? body : requestAborted
507521}
508522
509523async function dispatchAsyncIterableBody ( body , handler , controller , isAborted ) {
510524 const chunks = [ ]
511525
512526 for await ( const chunk of body ) {
513527 if ( isAborted ( ) ) {
514- return null
528+ return requestAborted
515529 }
516530 chunks . push ( chunk )
517- if ( ! callOnBodySent ( handler , controller , chunk ) ) {
518- return null
531+ if ( ! callOnBodySent ( handler , controller , chunk ) || isAborted ( ) ) {
532+ return requestAborted
519533 }
520534 }
521535
522- if ( isAborted ( ) || ! callOnRequestSent ( handler , controller ) ) {
523- return null
536+ if ( ! callOnRequestSent ( handler , controller , isAborted ) ) {
537+ return requestAborted
524538 }
525539
526540 return {
@@ -540,10 +554,10 @@ function callOnBodySent (handler, controller, chunk) {
540554 }
541555}
542556
543- function callOnRequestSent ( handler , controller ) {
557+ function callOnRequestSent ( handler , controller , isAborted ) {
544558 try {
545559 handler . onRequestSent ?. ( )
546- return true
560+ return ! isAborted ( )
547561 } catch ( error ) {
548562 controller . abort ( error )
549563 return false
0 commit comments