import { convertNodeHttpToRequest , runHttpQuery } from 'apollo-server-core' ; import { ApolloServer } from 'apollo-server-express' ; import express from 'express' ; import { DocumentNode , ExecutionResult , print } from 'graphql' ; import httpMocks , { RequestOptions , ResponseOptions } from 'node-mocks-http' ; const mockRequest = ( options = { } ) => httpMocks . createRequest ( { method : 'POST' , ... options , } ) ; const mockResponse = ( options = { } ) => httpMocks . createResponse ( options ) ; export type StringOrAst = string | DocumentNode ; export type Options < T extends object > = { variables ? : T ; } ; export type TestClientConfig = { apolloServer : ApolloServer ; extendMockRequest ? : RequestOptions ; extendMockResponse ? : ResponseOptions ; } ; export type TestQuery = < T extends object = { } , V extends object = { } > ( operation : StringOrAst , options ? : Options < V > ) => Promise < ExecutionResult < T > > ; export type TestSetOptions = ( options : { request ? : RequestOptions ; response ? : ResponseOptions ; } ) => void ; export function createTestClient ( { apolloServer , extendMockRequest = { } , extendMockResponse = { } , } ) { const app = express ( ) ; apolloServer . applyMiddleware ( { app } ) ; let mockRequestOptions = extendMockRequest ; let mockResponseOptions = extendMockResponse ; /**
     * Set the options after TestClient creation
     * Useful when you don't want to create a new instance just for a specific change in the request or response.
     *  */ const setOptions = ( { request , response , } ) => { if ( request ) { mockRequestOptions = request ; } if ( response ) { mockResponseOptions = response ; } } ; const test = async < T extends object = { } , V extends object = { } > ( operation , { variables } = { } ) => { const req = mockRequest ( mockRequestOptions ) ; const res = mockResponse ( mockResponseOptions ) ; const graphQLOptions = await apolloServer . createGraphQLServerOptions ( req , res ) ; const { graphqlResponse } = await runHttpQuery ( [ req , res ] , { method : 'POST' , options : graphQLOptions , query : { query : typeof operation === 'string' ? operation : print ( operation ) , variables , } , request : convertNodeHttpToRequest ( req ) , } ) ; return JSON . parse ( graphqlResponse ) as T ; } ; return { query : test , mutate : test , setOptions , } ; }