import signale , { debug } from './logger' ; import { findInterceptor , assignResponse , getBody , getQuery , loggerTrace } from './utils' ; import { DEFAULT_RESP_HEADERS } from './consts' ; import type { Options , DefResponse , Storage , Interceptor , Request , Response , DriverRequest } from './types' ; const logger = debug ( 'teremock:request' ) ; export interface Params extends Options { reqSet : { add : ( x : string ) => void ; get : ( ) => Set < string > ; } ; _onReqStarted : ( request : Request ) => void ; _onMatch : ( interceptor : Interceptor , req : Request ) => void ; storage : Storage ; } async function sleep ( time ) { return new Promise ( ( resolve , _reject ) => { setTimeout ( resolve , time ) ; } ) ; } export interface BeforeRespondArg { respond : ( response : Response , interceptor : Interceptor ) => Promise < void > ; request : Request ; response : DefResponse ; responseOverrides ? : Partial < Response > ; interceptor : Interceptor ; mog : Function ; increment : ( ) => number ; } async function beforeRespond ( { respond , request , response , mog , interceptor , increment , responseOverrides , } ) { let partResp ; if ( typeof response === 'function' ) { const argRequest = { ... request , query : getQuery ( request . url ) , } ; mog ( `» response is a function, responding with its returns` ) ; partResp = await response ( argRequest ) ; mog ( `» response() returns` , partResp ) ; } else { partResp = response ; } const bodyStrOrUnd = getBody ( partResp . body ) ; mog ( '» responding with' , ( bodyStrOrUnd ?? '' ) . slice ( 0 , 100 ) ) ; const resp = { ... partResp , headers : { ... DEFAULT_RESP_HEADERS , ... partResp . headers , } , body : bodyStrOrUnd , } ; let resultResponse = assignResponse ( resp , responseOverrides ) ; const ttfb = resultResponse ?. ttfb ?? 0 ; const actualDelay = Array . isArray ( ttfb ) ? ttfb [ increment ( ) % ttfb . length ] : ttfb ; mog ( '» actualDelay' , actualDelay ) ; await sleep ( Math . floor ( actualDelay ) ) ; if ( resultResponse . status >= 300 && resultResponse . status < 400 ) { const { body , ... rest } = resultResponse ; resultResponse = rest ; } await respond ( resultResponse , interceptor ) ; } export default function createHandler ( initialParams ) { let i = 0 ; const increment = ( ) => i ++ ; logger ( 'creating request handler' ) ; return async function handleRequest ( { request , abort , next , respond } , extraParams = { } ) { const params = { ... initialParams , ... extraParams } ; const { interceptors , storage , reqSet , ci , responseOverrides , getMockId , _onMatch } = params ; const reqParams = { url : request . url , method : request . method , body : request . body , headers : request . headers } ; loggerTrace ( `${ request . url } ← handling request` ) ; logger ( `» intercepted request with method "${ request . method }" and url "${ request . url }"` ) ; logger ( `request handling for:` , reqParams ) ; logger ( `request headers :` , request . headers ) ; const interceptor = findInterceptor ( { interceptors , request } ) ; if ( ! interceptor ) { signale . warn ( `interceptor not found, request to "${ request . url }" will be aborted` ) ; signale . warn ( `it is recommended to add interceptors to cover all request from your test app` ) ; signale . warn ( `see https://github.com/diokuz/teremock#interceptor for details` ) ; logger ( '» interceptor not found, aborting' ) ; await abort ( 'aborted' ) ; return ; } _onMatch ( interceptor , request ) ; const mockId = getMockId ( { ... request , naming : interceptor . naming ?? { } , name : interceptor . name , body : getBody ( request . body ) } ) ; const mog = debug ( `teremock:${ mockId }` ) ; mog ( `interceptor found` , interceptor ) ; if ( interceptor . pass ) { loggerTrace ( `${ request . url } ← passing to real server` ) ; mog ( `» interceptor.pass is true, sending it to real server next(interceptor)` ) ; await next ( interceptor ) ; return ; } params . _onReqStarted ( request ) ; reqSet . add ( mockId ) ; mog ( '» reqSet is' , Array . from ( reqSet . get ( ) ) ) ; if ( interceptor . response ) { loggerTrace ( `${ request . url } ← inline response` ) ; mog ( `» interceptor.response defined, responding with it` ) ; await beforeRespond ( { request , response : interceptor . response , responseOverrides , respond , interceptor , mog , increment , } ) ; return ; } mog ( `» trying to get mock with id "${ mockId }"` ) ; if ( await storage . has ( mockId ) ) { mog ( `» mock "${ mockId }" exists!` ) ; const mock = await storage . get ( mockId ) ; loggerTrace ( `${ request . url } ← mock ${ mockId } found in storage` ) ; mog ( `» successfully read from "${ mockId }", responding` ) ; await beforeRespond ( { request , response : mock . response , responseOverrides , respond , interceptor , mog , increment , } ) ; } else { loggerTrace ( `${ request . url } ← mock not found in storage` ) ; mog ( `» mock does not exist!` , ci ) ; if ( ci ) { signale . warn ( `mock file not found in ci mode, url is "${ request . url }"` ) ; } else { mog ( '» about to next()...' ) ; await next ( interceptor ) ; } } } ; }