import { deepStrictEqual } from 'assert' ; import { existsSync , mkdirSync , rmdirSync , unlinkSync , writeFileSync } from 'fs' ; import { get , Server } from 'http' ; import { Config , controller , createApp , dependency } from '@foal/core' ; import { InMemoryCache } from 'apollo-cache-inmemory' ; import { ApolloClient } from 'apollo-client' ; import { HttpLink } from 'apollo-link-http' ; import { buildSchema } from 'graphql' ; import { request } from 'graphql-request' ; import gql from 'graphql-tag' ; import { buildSchema as buildTypeGraphQLSchema , Field , ObjectType , Query , Resolver } from 'type-graphql' ; import { FormatError } from './format-error.decorator' ; import { GraphQLController } from './graphql.controller' ; import { schemaFromTypeGlob } from './schema-from-type-glob' ; const typeDefs = `type Query {
  user(id: Int): User
}

type User {
  id: Int
  name: String
}` ; describe ( '[Acceptance test] GraphQLController' , ( ) => { let server ; afterEach ( ( ) => { if ( existsSync ( './test-dir/my-defs.graphql' ) ) { unlinkSync ( './test-dir/my-defs.graphql' ) ; } if ( existsSync ( './test-dir' ) ) { rmdirSync ( './test-dir' ) ; } if ( server ) { server . close ( ) ; } Config . remove ( 'settings.debug' ) ; } ) ; describe ( 'should support common GraphQL clients such as' , ( ) => { class AppResolver { user ( args , context , info ) { return { id : args . id , name : 'someone!' } ; } } class ApiController extends GraphQLController { schema = buildSchema ( typeDefs ) ; @ dependency resolvers : AppResolver ; } class AppController { subControllers = [ controller ( '/graphql' , ApiController ) ] ; } beforeEach ( async ( ) => server = ( await createApp ( AppController ) ) . listen ( 3000 ) ) ; it ( 'graphql-request.' , async ( ) => { const data = await request ( 'http://localhost:3000/graphql' , 'query getUser($id: Int) { user(id: $id) { name, id } }' , { id : 3 } ) ; deepStrictEqual ( data , { user : { id : 3 , name : 'someone!' } } ) ; } ) ; it ( 'apollo-client.' , async ( ) => { const httpLink = new HttpLink ( { uri : 'http://localhost:3000/graphql' } ) ; const cache = new InMemoryCache ( ) ; const client = new ApolloClient ( { cache , link : httpLink } ) ; const { data } = await client . query ( { query : gql `query getUser($id: Int) { user(id: $id) { name, id } }` , variables : { id : 3 } } ) ; deepStrictEqual ( data , { user : { __typename : 'User' , id : 3 , name : 'someone!' } } ) ; } ) ; } ) ; it ( 'should work with type definitions located in separate files.' , async ( ) => { class AppResolver { user ( args , context , info ) { return { id : args . id , name : 'someone!' } ; } } class ApiController extends GraphQLController { schema = schemaFromTypeGlob ( './test-dir/*.graphql' ) ; @ dependency resolvers : AppResolver ; } class AppController { subControllers = [ controller ( '/graphql' , ApiController ) ] ; } mkdirSync ( './test-dir' ) ; writeFileSync ( './test-dir/my-defs.graphql' , typeDefs , 'utf8' ) ; server = ( await createApp ( AppController ) ) . listen ( 3000 ) ; const response = await new Promise ( ( resolve , reject ) => { get ( 'http://localhost:3000/graphql?query={user{name}}' , resp => { let data = '' ; resp . on ( 'data' , chunk => { data += chunk ; } ) ; resp . on ( 'end' , ( ) => { resolve ( JSON . parse ( data ) ) ; } ) ; } ) . on ( 'error' , err => { reject ( err ) ; } ) ; } ) ; deepStrictEqual ( response , { data : { user : { name : 'someone!' } } } ) ; } ) ; it ( 'should include in the documentation an example on how to handle errors in resolvers.' , async ( ) => { Config . set ( 'settings.debug' , false ) ; class Resolvers { @ FormatError ( ) user ( ) { throw new Error ( 'This is an error' ) ; } } class ApiController extends GraphQLController { schema = buildSchema ( typeDefs ) ; @ dependency resolvers : Resolvers ; } class AppController { subControllers = [ controller ( '/graphql' , ApiController ) ] ; } server = ( await createApp ( AppController ) ) . listen ( 3000 ) ; const response = await new Promise ( ( resolve , reject ) => { get ( 'http://localhost:3000/graphql?query={user{name}}' , resp => { let data = '' ; resp . on ( 'data' , chunk => { data += chunk ; } ) ; resp . on ( 'end' , ( ) => { resolve ( JSON . parse ( data ) ) ; } ) ; } ) . on ( 'error' , err => { reject ( err ) ; } ) ; } ) ; deepStrictEqual ( response , { data : { user : null } , errors : [ { locations : [ { column : 2 , line : 1 } ] , message : 'Internal Server Error' , path : [ 'user' ] } ] } ) ; } ) ; it ( 'should support TypeGraphQL.' , async ( ) => { @ ObjectType ( ) class Recipe { @ Field ( ) title : string ; } @ Resolver ( Recipe ) class RecipeResolver { @ Query ( returns => Recipe ) async recipe ( ) { return { title : 'foobar' } ; } } class ApiController extends GraphQLController { schema = buildTypeGraphQLSchema ( { resolvers : [ RecipeResolver ] } ) ; } class AppController { subControllers = [ controller ( '/graphql' , ApiController ) ] ; } server = ( await createApp ( AppController ) ) . listen ( 3000 ) ; const response = await new Promise ( ( resolve , reject ) => { get ( 'http://localhost:3000/graphql?query={recipe{title}}' , resp => { let data = '' ; resp . on ( 'data' , chunk => { data += chunk ; } ) ; resp . on ( 'end' , ( ) => { console . log ( data ) ; resolve ( JSON . parse ( data ) ) ; } ) ; } ) . on ( 'error' , err => { reject ( err ) ; } ) ; } ) ; deepStrictEqual ( response , { data : { recipe : { title : 'foobar' } } } ) ; } ) ; } ) ;