import xhrMock , { proxy } from "xhr-mock" ; import { isNode , HttpMethods } from "../lib/msRest" ; import fetchMock , * as fetch from "fetch-mock" ; import { Readable } from "stream" ; import node_fetch from "node-fetch" ; export type UrlFilter = string | RegExp ; export type MockResponseData = { status ? : number ; body ? : any ; headers ? : any ; } ; export type MockResponseFunction = ( url ? : string , method ? : string , body ? : any , headers ? : any ) => Promise < MockResponseData > ; export type MockResponse = MockResponseData | MockResponseFunction ; export interface HttpMockFacade { setup ( ) : void ; teardown ( ) : void ; passThrough ( url ? ) : void ; timeout ( method , url ? ) : void ; mockHttpMethod ( method , url , response ) : void ; get ( url , response ) : void ; post ( url , response ) : void ; put ( url , response ) : void ; getFetch ( ) : typeof node_fetch | undefined ; } export function getHttpMock ( ) { return isNode ? new FetchHttpMock ( ) : new BrowserHttpMock ( ) ; } class FetchHttpMock implements HttpMockFacade { private _fetch : fetchMock . FetchMockSandbox ; constructor ( ) { this . _fetch = fetchMock . sandbox ( ) ; } getFetch ( ) { return ( this . _fetch as unknown ) as typeof node_fetch ; } setup ( ) { this . _fetch . resetHistory ( ) ; } teardown ( ) { this . _fetch . resetHistory ( ) ; } passThrough ( _url ? ) { this . _fetch . reset ( ) ; } timeout ( _method , url ) { const delay = new Promise ( ( resolve ) => { setTimeout ( ( ) => resolve ( { $uri : url , delay : 500 } ) , 2500 ) ; } ) ; this . _fetch . mock ( url , delay ) ; } convertStreamToBuffer ( stream ) { return new Promise ( ( resolve ) => { const buffer = [ ] ; stream . on ( "data" , ( chunk ) => { buffer . push ( chunk ) ; } ) ; stream . on ( "end" , ( ) => { return resolve ( buffer ) ; } ) ; } ) ; } mockHttpMethod ( method , url , response ) { let mockResponse = response ; if ( typeof response === "function" ) { const mockFunction = response ; mockResponse = ( async ( url , opts ) => { if ( opts . body && typeof opts . body . pipe === "function" ) { opts . body = await this . convertStreamToBuffer ( opts . body ) ; } return mockFunction ( url , method , opts . body , opts . headers ) ; } ) as fetch . MockResponseFunction ; } const matcher = ( _url , opts ) => url === _url && opts . method === method ; this . _fetch . mock ( matcher , mockResponse ) ; } get ( url , response ) { this . mockHttpMethod ( "GET" , url , response ) ; } post ( url , response ) { this . mockHttpMethod ( "POST" , url , response ) ; } put ( url , response ) { this . mockHttpMethod ( "PUT" , url , response ) ; } } export class BrowserHttpMock implements HttpMockFacade { setup ( ) { xhrMock . setup ( ) ; } teardown ( ) { xhrMock . teardown ( ) ; } mockHttpMethod ( method , url , response ) { if ( typeof response === "function" ) { xhrMock . use ( method , url , async ( req , res ) => { const result = await response ( req . url ( ) . toString ( ) , req . method ( ) . toString ( ) , req . body ( ) , req . headers ( ) ) ; return res . status ( result . status || 200 ) . body ( result . body || { } ) . headers ( result . headers || { } ) ; } ) ; } else { xhrMock . use ( method , url , { status : response . status , body : response . body , } ) ; } } get ( url , response ) { this . mockHttpMethod ( "GET" , url , response ) ; } post ( url , response ) { this . mockHttpMethod ( "POST" , url , response ) ; } put ( url , response ) { this . mockHttpMethod ( "PUT" , url , response ) ; } passThrough ( url ? ) { if ( url ) { console . warn ( "Browser mock doesn't support filtered passThrough calls." ) ; } xhrMock . use ( proxy ) ; } timeout ( method , url ) { return this . mockHttpMethod ( method , url , ( ) => new Promise ( ( ) => { } ) ) ; } getFetch ( ) { return undefined ; } }