text: "use strict";
  
  var _graphql = require("../graphql");
  
  var _ = require("..");
  
  var _Resolver = require("../Resolver");
  
  var _ObjectTypeComposer = require("../ObjectTypeComposer");
  
  var _InputTypeComposer = require("../InputTypeComposer");
  
  var _InterfaceTypeComposer = require("../InterfaceTypeComposer");
  
  var _ScalarTypeComposer = require("../ScalarTypeComposer");
  
  var _EnumTypeComposer = require("../EnumTypeComposer");
  
  var _UnionTypeComposer = require("../UnionTypeComposer");
  
  var _graphqlVersion = require("../utils/graphqlVersion");
  
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
  
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
  
  beforeEach(() => {
    _.schemaComposer.clear();
  });
  describe('ObjectTypeComposer', () => {
    let objectType;
    let tc;
    beforeEach(() => {
      objectType = new _graphql.GraphQLObjectType({
        name: 'Readable',
        fields: {
          field1: {
            type: _graphql.GraphQLString
          },
          field2: {
            type: _graphql.GraphQLString
          }
        }
      });
      tc = new _ObjectTypeComposer.ObjectTypeComposer(objectType, _.schemaComposer);
    });
    describe('fields manipulation', () => {
      it('getFields()', () => {
        const fieldNames = Object.keys(tc.getFields());
        expect(fieldNames).toEqual(expect.arrayContaining(['field1', 'field2']));
  
        const tc2 = _ObjectTypeComposer.ObjectTypeComposer.create('SomeType', _.schemaComposer);
  
        expect(tc2.getFields()).toEqual({});
      });
      describe('getField()', () => {
        it('should return field config', () => {
          expect(tc.getFieldType('field1')).toBe(_graphql.GraphQLString);
        });
        it('should throw error if field does not exist', () => {
          expect(() => tc.getField('unexisted')).toThrowError(/Cannot get field.*does not exist/);
        });
      });
      describe('setFields()', () => {
        it('should add field with standart config', () => {
          tc.setFields({
            field3: {
              type: _graphql.GraphQLString
            }
          });
          const fields = objectType.getFields();
          expect(Object.keys(fields)).toContain('field3');
          expect(fields.field3.type).toBe(_graphql.GraphQLString);
        });
        it('should add fields with converting types from string to object', () => {
          tc.setFields({
            field3: {
              type: 'String'
            },
            field4: {
              type: '[Int]'
            },
            field5: 'Boolean!'
          });
          expect(tc.getFieldType('field3')).toBe(_graphql.GraphQLString);
          expect(tc.getFieldType('field4')).toBeInstanceOf(_graphql.GraphQLList);
          expect(tc.getFieldType('field4').ofType).toBe(_graphql.GraphQLInt);
          expect(tc.getFieldType('field5')).toBeInstanceOf(_graphql.GraphQLNonNull);
          expect(tc.getFieldType('field5').ofType).toBe(_graphql.GraphQLBoolean);
        });
        it('should add fields with converting args types from string to object', () => {
          tc.setFields({
            field3: {
              type: 'String',
              args: {
                arg1: {
                  type: 'String!'
                },
                arg2: '[Float]'
              }
            }
          });
          expect(tc.getFieldArgType('field3', 'arg1')).toBeInstanceOf(_graphql.GraphQLNonNull);
          expect(tc.getFieldArgType('field3', 'arg1').ofType).toBe(_graphql.GraphQLString);
          expect(tc.getFieldArgType('field3', 'arg2')).toBeInstanceOf(_graphql.GraphQLList);
          expect(tc.getFieldArgType('field3', 'arg2').ofType).toBe(_graphql.GraphQLFloat);
        });
        it('should add projection via `setField` and `addFields`', () => {
          tc.setFields({
            field3: {
              type: _graphql.GraphQLString,
              projection: {
                field1: true,
                field2: true
              }
            },
            field4: {
              type: _graphql.GraphQLString
            },
            field5: {
              type: _graphql.GraphQLString,
              projection: {
                field4: true
              }
            }
          });
        });
        it('accept types as function', () => {
          const typeAsFn = () => _graphql.GraphQLString;
  
          tc.setFields({
            input3: {
              type: typeAsFn
            }
          });
          expect(tc.getField('input3').type).toBe(typeAsFn);
          expect(tc.getFieldType('input3')).toBe(_graphql.GraphQLString); // show provide unwrapped/unhoisted type for graphql
  
          if (_graphqlVersion.graphqlVersion >= 14) {
            expect(tc.getType()._fields().input3.type).toBe(_graphql.GraphQLString);
          } else {
            expect(tc.getType()._typeConfig.fields().input3.type).toBe(_graphql.GraphQLString);
          }
        });
        it('accept fieldConfig as function', () => {
          tc.setFields({
            input4: () => ({
              type: 'String'
            })
          }); // show provide unwrapped/unhoisted type for graphql
  
          if (_graphqlVersion.graphqlVersion >= 14) {
            expect(tc.getType()._fields().input4.type).toBe(_graphql.GraphQLString);
          } else {
            expect(tc.getType()._typeConfig.fields().input4.type).toBe(_graphql.GraphQLString);
          }
        });
      });
      it('addFields()', () => {
        tc.addFields({
          field3: {
            type: _graphql.GraphQLString
          },
          field4: {
            type: '[Int]'
          },
          field5: 'Boolean!'
        });
        expect(tc.getFieldType('field3')).toBe(_graphql.GraphQLString);
        expect(tc.getFieldType('field4')).toBeInstanceOf(_graphql.GraphQLList);
        expect(tc.getFieldType('field4').ofType).toBe(_graphql.GraphQLInt);
        expect(tc.getFieldType('field5')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(tc.getFieldType('field5').ofType).toBe(_graphql.GraphQLBoolean);
      });
      it('addNestedFields()', () => {
        tc.addNestedFields({
          'fieldNested1.f1': {
            type: _graphql.GraphQLString
          },
          fieldNested2: {
            type: '[Int]'
          },
          'fieldNested1.f2': 'Boolean!'
        });
        expect(tc.getFieldType('fieldNested1')).toBeInstanceOf(_graphql.GraphQLObjectType);
        const fieldTC = tc.getFieldTC('fieldNested1');
        expect(fieldTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
  
        if (fieldTC instanceof _ObjectTypeComposer.ObjectTypeComposer) {
          expect(fieldTC.getTypeName()).toBe('ReadableFieldNested1');
          expect(fieldTC.getFieldType('f1')).toBe(_graphql.GraphQLString);
          expect(fieldTC.getFieldType('f2')).toBeInstanceOf(_graphql.GraphQLNonNull);
          expect(fieldTC.getFieldType('f2').ofType).toBe(_graphql.GraphQLBoolean);
          expect(tc.getFieldType('fieldNested2')).toBeInstanceOf(_graphql.GraphQLList);
          expect(tc.getFieldType('fieldNested2').ofType).toBe(_graphql.GraphQLInt);
        }
      });
      describe('removeField()', () => {
        it('should remove one field', () => {
          tc.removeField('field1');
          expect(tc.getFieldNames()).toEqual(expect.arrayContaining(['field2']));
        });
        it('should remove list of fields', () => {
          tc.removeField(['field1', 'field2']);
          expect(tc.getFieldNames()).toEqual(expect.arrayContaining([]));
        });
      });
      describe('removeOtherFields()', () => {
        it('should remove one field', () => {
          tc.removeOtherFields('field1');
          expect(tc.getFieldNames()).not.toEqual(expect.arrayContaining(['field2']));
          expect(tc.getFieldNames()).toEqual(expect.arrayContaining(['field1']));
        });
        it('should remove list of fields', () => {
          tc.setField('field3', 'String');
          tc.removeOtherFields(['field1', 'field2']);
          expect(tc.getFieldNames()).toEqual(expect.arrayContaining(['field1', 'field2']));
          expect(tc.getFieldNames()).not.toEqual(expect.arrayContaining(['field3']));
        });
      });
      describe('reorderFields()', () => {
        it('should change fields order', () => {
          tc.setFields({
            f1: 'Int',
            f2: 'Int',
            f3: 'Int'
          });
          expect(tc.getFieldNames().join(',')).toBe('f1,f2,f3');
          tc.reorderFields(['f3', 'f2', 'f1']);
          expect(tc.getFieldNames().join(',')).toBe('f3,f2,f1');
        });
        it('should append not listed fields', () => {
          tc.setFields({
            f1: 'Int',
            f2: 'Int',
            f3: 'Int'
          });
          expect(tc.getFieldNames().join(',')).toBe('f1,f2,f3');
          tc.reorderFields(['f3']);
          expect(tc.getFieldNames().join(',')).toBe('f3,f1,f2');
        });
        it('should skip non existed fields', () => {
          tc.setFields({
            f1: 'Int',
            f2: 'Int',
            f3: 'Int'
          });
          expect(tc.getFieldNames().join(',')).toBe('f1,f2,f3');
          tc.reorderFields(['f22', 'f3', 'f55', 'f1', 'f2']);
          expect(tc.getFieldNames().join(',')).toBe('f3,f1,f2');
        });
      });
      describe('field arguments', () => {
        beforeEach(() => {
          tc.extendField('field1', {
            args: {
              arg1: 'Int',
              arg2: 'String'
            }
          });
        });
        it('getFieldArgs()', () => {
          const args = tc.getFieldArgs('field1');
          expect(Object.keys(args)).toEqual(['arg1', 'arg2']);
          expect(args.arg1.type).toBe(_graphql.GraphQLInt);
          expect(tc.getFieldArgType('field1', 'arg1')).toBe(_graphql.GraphQLInt);
          expect(() => tc.getFieldArgs('unexistedField')).toThrow();
        });
        it('hasFieldArg()', () => {
          expect(tc.hasFieldArg('field1', 'arg1')).toBeTruthy();
          expect(tc.hasFieldArg('field1', 'arg222')).toBeFalsy();
          expect(tc.hasFieldArg('unexistedField', 'arg1')).toBeFalsy();
        });
        it('getFieldArg()', () => {
          expect(tc.getFieldArg('field1', 'arg1')).toBeTruthy();
          expect(() => tc.getFieldArg('field1', 'arg222')).toThrow(/Cannot get arg.*Argument does not exist/);
          expect(tc.hasFieldArg('unexistedField', 'arg1')).toBeFalsy();
        });
      });
      describe('extendField()', () => {
        it('should extend existed fields', () => {
          tc.setField('field3', {
            type: _graphql.GraphQLString,
            projection: {
              field1: true,
              field2: true
            }
          });
          tc.extendField('field3', {
            description: 'this is field #3'
          });
          expect(tc.getFieldConfig('field3').type).toBe(_graphql.GraphQLString);
          expect(tc.getFieldConfig('field3').description).toBe('this is field #3');
          tc.extendField('field3', {
            type: 'Int'
          });
          expect(tc.getFieldType('field3')).toBe(_graphql.GraphQLInt);
        });
        it('should extend field extensions', () => {
          tc.setField('field3', {
            type: _graphql.GraphQLString,
            extensions: {
              first: true
            }
          });
          tc.extendField('field3', {
            description: 'this is field #3',
            extensions: {
              second: true
            }
          }); // $FlowFixMe
  
          expect(tc.getFieldConfig('field3').extensions).toEqual({
            first: true,
            second: true
          });
        });
        it('should work with fieldConfig as string', () => {
          tc.setField('field4', 'String');
          tc.extendField('field4', {
            description: 'this is field #4'
          });
          expect(tc.getFieldConfig('field4').type).toBe(_graphql.GraphQLString);
          expect(tc.getFieldConfig('field4').description).toBe('this is field #4');
        });
        it('should throw error if field does not exists', () => {
          expect(() => tc.extendField('unexisted', {
            description: '123'
          })).toThrow(/Cannot extend field.*Field does not exist/);
        });
      });
      it('isFieldNonNull()', () => {
        tc.setField('fieldNN', 'String');
        expect(tc.isFieldNonNull('fieldNN')).toBe(false);
        tc.setField('fieldNN', 'String!');
        expect(tc.isFieldNonNull('fieldNN')).toBe(true);
      });
      it('makeFieldNonNull()', () => {
        tc.setField('fieldNN', 'String');
        expect(tc.getFieldType('fieldNN')).toBe(_graphql.GraphQLString); // should wrap with GraphQLNonNull
  
        tc.makeFieldNonNull('fieldNN');
        expect(tc.getFieldType('fieldNN')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(tc.getFieldType('fieldNN').ofType).toBe(_graphql.GraphQLString); // should not wrap twice
  
        tc.makeFieldNonNull('fieldNN');
        expect(tc.getFieldType('fieldNN')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(tc.getFieldType('fieldNN').ofType).toBe(_graphql.GraphQLString);
      });
      it('makeFieldNullable()', () => {
        tc.setField('fieldNN', 'String!');
        expect(tc.getFieldType('fieldNN')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(tc.getFieldType('fieldNN').ofType).toBe(_graphql.GraphQLString); // should unwrap with GraphQLNonNull
  
        tc.makeFieldNullable('fieldNN');
        expect(tc.getFieldType('fieldNN')).toBe(_graphql.GraphQLString); // should work for already unwrapped type
  
        tc.makeFieldNullable('fieldNN');
        expect(tc.getFieldType('fieldNN')).toBe(_graphql.GraphQLString);
      });
    });
    describe('interfaces manipulation', () => {
      const iface = new _graphql.GraphQLInterfaceType({
        name: 'Node',
        description: '',
        fields: () => ({
          id: {
            type: _graphql.GraphQLInt
          }
        }),
        resolveType: () => {}
      });
      const iface2 = new _graphql.GraphQLInterfaceType({
        name: 'Node2',
        description: '',
        fields: () => ({
          id: {
            type: _graphql.GraphQLInt
          }
        }),
        resolveType: () => {}
      });
  
      const iftc = _InterfaceTypeComposer.InterfaceTypeComposer.create(`
        interface SimpleObject {
          id: Int
          name: String
        }
      `, _.schemaComposer);
  
      it('getInterfaces()', () => {
        if (_graphqlVersion.graphqlVersion >= 14) {
          tc.gqType._interfaces = [iface];
        } else {
          tc.gqType._typeConfig.interfaces = [iface];
        }
  
        expect(tc.getInterfaces()).toEqual(expect.arrayContaining([iface]));
      });
      it('hasInterface()', () => {
        if (_graphqlVersion.graphqlVersion >= 14) {
          tc.gqType._interfaces = [iface];
        } else {
          tc.gqType._typeConfig.interfaces = [iface];
        }
  
        expect(tc.hasInterface(iface)).toBe(true);
      });
      it('hasInterface() should work by name or ITC', () => {
        const MyIface = new _graphql.GraphQLInterfaceType({
          name: 'MyIface',
          description: '',
          fields: () => ({
            id: {
              type: _graphql.GraphQLInt
            }
          }),
          resolveType: () => {}
        });
        tc.addInterface(MyIface);
        expect(tc.hasInterface('MyIface123')).toBeFalsy();
        expect(tc.hasInterface('MyIface')).toBeTruthy();
        expect(tc.hasInterface(MyIface)).toBeTruthy();
        expect(tc.hasInterface(_InterfaceTypeComposer.InterfaceTypeComposer.create(MyIface, _.schemaComposer))).toBeTruthy();
        tc.addInterface(_InterfaceTypeComposer.InterfaceTypeComposer.create('MyIface123', _.schemaComposer));
        expect(tc.hasInterface('MyIface123')).toBeTruthy();
      });
      it('addInterface()', () => {
        tc.addInterface(iface);
        expect(tc.getInterfaces()).toEqual(expect.arrayContaining([iface]));
        expect(tc.hasInterface(iface)).toBe(true);
        tc.addInterface(iface2);
        expect(tc.getInterfaces()).toEqual(expect.arrayContaining([iface, iface2]));
        expect(tc.hasInterface(iface2)).toBe(true);
        tc.addInterface(iftc);
        expect(tc.hasInterface(iftc)).toBe(true);
      });
      it('removeInterface()', () => {
        tc.addInterface(iface);
        tc.addInterface(iface2);
        tc.addInterface(iftc);
        expect(tc.getInterfaces()).toEqual(expect.arrayContaining([iface, iface2, iftc]));
        tc.removeInterface(iface);
        tc.removeInterface(iftc);
        expect(tc.hasInterface(iface)).toBe(false);
        expect(tc.hasInterface(iftc)).toBe(false);
        expect(tc.hasInterface(iface2)).toBe(true);
      });
      it('check proper interface definition in GraphQLType', () => {
        tc.addInterface(iface);
        tc.addInterface(iface2);
        tc.addInterface(iftc);
        const gqType = tc.getType();
        const ifaces = gqType.getInterfaces();
        expect(ifaces[0]).toBeInstanceOf(_graphql.GraphQLInterfaceType);
        expect(ifaces[1]).toBeInstanceOf(_graphql.GraphQLInterfaceType);
        expect(ifaces[2]).toBeInstanceOf(_graphql.GraphQLInterfaceType);
        expect(ifaces[0].name).toBe('Node');
        expect(ifaces[1].name).toBe('Node2');
        expect(ifaces[2].name).toBe('SimpleObject');
      });
    });
    describe('create() [static method]', () => {
      it('should create TC by typeName as a string', () => {
        const myTC = _ObjectTypeComposer.ObjectTypeComposer.create('TypeStub', _.schemaComposer);
  
        expect(myTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(myTC.getType()).toBeInstanceOf(_graphql.GraphQLObjectType);
        expect(myTC.getFields()).toEqual({});
      });
      it('should create TC by type template string', () => {
        const myTC = _ObjectTypeComposer.ObjectTypeComposer.create(`
          type TestTypeTpl {
            f1: String
            # Description for some required Int field
            f2: Int!
          }
        `, _.schemaComposer);
  
        expect(myTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(myTC.getTypeName()).toBe('TestTypeTpl');
        expect(myTC.getFieldType('f1')).toBe(_graphql.GraphQLString);
        expect(myTC.getFieldType('f2')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(myTC.getFieldType('f2').ofType).toBe(_graphql.GraphQLInt);
      });
      it('should create TC by GraphQLObjectTypeConfig', () => {
        const myTC = _ObjectTypeComposer.ObjectTypeComposer.create({
          name: 'TestType',
          fields: {
            f1: {
              type: 'String'
            },
            f2: 'Int!'
          }
        }, _.schemaComposer);
  
        expect(myTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(myTC.getFieldType('f1')).toBe(_graphql.GraphQLString);
        expect(myTC.getFieldType('f2')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(myTC.getFieldType('f2').ofType).toBe(_graphql.GraphQLInt);
      });
      it('should create TC by GraphQLObjectTypeConfig with fields as Thunk', () => {
        const myTC = _ObjectTypeComposer.ObjectTypeComposer.create({
          name: 'TestType',
          fields: () => ({
            f1: {
              type: 'String'
            },
            f2: 'Int!'
          })
        }, _.schemaComposer);
  
        expect(myTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(myTC.getFieldType('f1')).toBe(_graphql.GraphQLString);
        expect(myTC.getFieldType('f2')).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(myTC.getFieldType('f2').ofType).toBe(_graphql.GraphQLInt);
      });
      it('should create TC by GraphQLObjectType', () => {
        const objType = new _graphql.GraphQLObjectType({
          name: 'TestTypeObj',
          fields: {
            f1: {
              type: _graphql.GraphQLString
            }
          }
        });
  
        const myTC = _ObjectTypeComposer.ObjectTypeComposer.create(objType, _.schemaComposer);
  
        expect(myTC).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(myTC.getType()).toBe(objType);
        expect(myTC.getFieldType('f1')).toBe(_graphql.GraphQLString);
      });
      it('should create type and store it in schemaComposer', () => {
        const SomeUserTC = _ObjectTypeComposer.ObjectTypeComposer.create('SomeUser', _.schemaComposer);
  
        expect(_.schemaComposer.getOTC('SomeUser')).toBe(SomeUserTC);
      });
      it('should create type and NOTE store root types in schemaComposer', () => {
        _ObjectTypeComposer.ObjectTypeComposer.create('Query', _.schemaComposer);
  
        expect(_.schemaComposer.has('Query')).toBeFalsy();
  
        _ObjectTypeComposer.ObjectTypeComposer.create('Mutation', _.schemaComposer);
  
        expect(_.schemaComposer.has('Query')).toBeFalsy();
  
        _ObjectTypeComposer.ObjectTypeComposer.create('Subscription', _.schemaComposer);
  
        expect(_.schemaComposer.has('Query')).toBeFalsy();
      });
      it('createTemp() should not store type in schemaComposer', () => {
        _ObjectTypeComposer.ObjectTypeComposer.createTemp('SomeUser');
  
        expect(_.schemaComposer.has('SomeUser')).toBeFalsy();
      });
    });
    describe('clone()', () => {
      it('should clone projection for fields', () => {
        tc.setField('field3', {
          type: _graphql.GraphQLString,
          projection: {
            field1: true,
            field2: true
          }
        });
        const tc2 = tc.clone('newObject');
        expect(tc2.getField('field3')).toEqual(expect.objectContaining({
          type: _graphql.GraphQLString,
          projection: {
            field1: true,
            field2: true
          }
        }));
      });
    });
    describe('get()', () => {
      it('should return type by path', () => {
        const myTC = new _ObjectTypeComposer.ObjectTypeComposer(new _graphql.GraphQLObjectType({
          name: 'Readable',
          fields: {
            field1: {
              type: _graphql.GraphQLString,
              args: {
                arg1: {
                  type: _graphql.GraphQLInt
                }
              }
            }
          }
        }), _.schemaComposer);
        expect(myTC.get('field1')).toBe(_graphql.GraphQLString);
        expect(myTC.get('field1.@arg1')).toBe(_graphql.GraphQLInt);
      });
    });
    describe('Resolvers manipulation', () => {
      it('addResolver() should accept Resolver instance', () => {
        const resolver = new _Resolver.Resolver({
          name: 'myResolver'
        }, _.schemaComposer);
        tc.addResolver(resolver);
        expect(tc.getResolver('myResolver')).toBe(resolver);
        expect(tc.hasResolver('myResolver')).toBe(true);
        expect(tc.hasResolver('myResolverXXX')).toBe(false);
      });
      it('addResolver() should accept Resolver options and create instance', () => {
        const resolverOpts = {
          name: 'myResolver2'
        };
        tc.addResolver(resolverOpts);
        expect(tc.getResolver('myResolver2')).toBeInstanceOf(_Resolver.Resolver);
        expect(tc.getResolver('myResolver2').name).toBe('myResolver2');
      });
      it('addResolver() should add stub resolve method', () => {
        const resolverOpts = {
          name: 'myResolver3'
        };
        tc.addResolver(resolverOpts);
        expect(tc.getResolver('myResolver3').resolve(undefined)).toEqual({});
      });
      it('removeResolver() should work', () => {
        const resolver = new _Resolver.Resolver({
          name: 'myResolver3'
        }, _.schemaComposer);
        tc.addResolver(resolver);
        expect(tc.hasResolver('myResolver3')).toBe(true);
        tc.removeResolver('myResolver3');
        expect(tc.hasResolver('myResolver3')).toBe(false);
        expect(() => tc.getResolver('myResolver3')).toThrowError(/does not have resolver with name 'myResolver3'/);
      });
      it('setResolver() should add resolver with specific name', () => {
        const resolver = new _Resolver.Resolver({
          name: 'myResolver4'
        }, _.schemaComposer);
        tc.setResolver('specName4', resolver);
        expect(tc.hasResolver('specName4')).toBe(true);
        expect(tc.hasResolver('myResolver4')).toBe(false);
      });
      it('getResolvers() should return Map', () => {
        expect(tc.getResolvers()).toBeInstanceOf(Map);
        tc.addResolver({
          name: 'myResolver5'
        });
        expect(Array.from(tc.getResolvers().keys())).toContain('myResolver5');
      });
      it('wrapResolverResolve() should wrap resolver resolve method',
      /*#__PURE__*/
      _asyncToGenerator(function* () {
        tc.addResolver({
          name: 'findById',
          resolve: () => '123'
        });
        expect((yield tc.getResolver('findById').resolve({}))).toBe('123');
        tc.wrapResolverResolve('findById', next =>
        /*#__PURE__*/
        function () {
          var _ref2 = _asyncToGenerator(function* (rp) {
            const prev = yield next(rp);
            return `${prev}456`;
          });
  
          return function (_x) {
            return _ref2.apply(this, arguments);
          };
        }());
        expect((yield tc.getResolver('findById').resolve({}))).toBe('123456');
      }));
      it('wrapResolver() should wrap resolver via callback',
      /*#__PURE__*/
      _asyncToGenerator(function* () {
        tc.addResolver({
          name: 'update',
          resolve: () => '123'
        });
        expect((yield tc.getResolver('update').resolve({}))).toBe('123');
        const prevResolver = tc.getResolver('update');
        tc.wrapResolver('update', resolver => {
          resolver.resolve = () => '456'; // eslint-disable-line
  
  
          return resolver;
        });
        expect((yield tc.getResolver('update').resolve({}))).toBe('456');
        expect(tc.getResolver('update')).not.toBe(prevResolver);
        expect(prevResolver.resolve(undefined)).toBe('123');
      }));
      it('wrapResolverAs() should wrap resolver via callback with new name',
      /*#__PURE__*/
      _asyncToGenerator(function* () {
        tc.addResolver({
          name: 'update',
          args: {
            a: 'Int',
            b: 'String'
          },
          resolve: () => '123'
        });
        expect((yield tc.getResolver('update').resolve({}))).toBe('123');
        tc.wrapResolverAs('updateExt', 'update', resolver => {
          resolver.resolve = () => '456'; // eslint-disable-line
  
  
          resolver.addArgs({
            c: 'Boolean'
          });
          return resolver;
        });
        expect((yield tc.getResolver('updateExt').resolve({}))).toBe('456');
        expect((yield tc.getResolver('update').resolve({}))).toBe('123');
        expect(tc.getResolver('update').getArgNames()).toEqual(['a', 'b']);
        expect(tc.getResolver('updateExt').getArgNames()).toEqual(['a', 'b', 'c']);
      }));
      it('getResolver() with middlewares',
      /*#__PURE__*/
      _asyncToGenerator(function* () {
        const log = [];
  
        const mw1 =
        /*#__PURE__*/
        function () {
          var _ref6 = _asyncToGenerator(function* (resolve, source, args, context, info) {
            log.push('m1.before');
            const res = yield resolve(source, args, context, info);
            log.push('m1.after');
            return res;
          });
  
          return function mw1(_x2, _x3, _x4, _x5, _x6) {
            return _ref6.apply(this, arguments);
          };
        }();
  
        const mw2 =
        /*#__PURE__*/
        function () {
          var _ref7 = _asyncToGenerator(function* (resolve, source, args, context, info) {
            log.push('m2.before');
            const res = yield resolve(source, args, context, info);
            log.push('m2.after');
            return res;
          });
  
          return function mw2(_x7, _x8, _x9, _x10, _x11) {
            return _ref7.apply(this, arguments);
          };
        }();
  
        tc.addResolver({
          name: 'update',
          resolve: () => {
            log.push('call update');
            return '123';
          }
        });
        expect((yield tc.getResolver('update', [mw1, mw2]).resolve({}))).toBe('123');
        expect(log).toEqual(['m1.before', 'm2.before', 'call update', 'm2.after', 'm1.after']);
      }));
    });
    describe('addRelation()', () => {
      let UserTC;
      let ArticleTC;
      beforeEach(() => {
        UserTC = _ObjectTypeComposer.ObjectTypeComposer.create(`
          type User {
            id: Int,
            name: String,
          }
        `, _.schemaComposer);
        UserTC.addResolver({
          name: 'findById',
          type: UserTC,
          resolve: () => null
        });
        ArticleTC = _ObjectTypeComposer.ObjectTypeComposer.create(`
          type Article {
            id: Int,
            userId: Int,
            title: String,
          }
        `, _.schemaComposer);
        ArticleTC.addResolver({
          name: 'findOne',
          type: ArticleTC,
          resolve: () => null
        });
      });
      describe('_relationWithResolverToFC()', () => {
        it('should return FieldConfig', () => {
          const fc = ArticleTC._relationWithResolverToFC({
            resolver: UserTC.getResolver('findById')
          });
  
          expect(fc.type.name).toBe('User');
        });
        it('should accept resolver as thunk and return FieldConfig', () => {
          const fc = ArticleTC._relationWithResolverToFC({
            resolver: () => UserTC.getResolver('findById')
          });
  
          expect(fc.type.name).toBe('User');
        });
        it('should throw error if provided incorrect Resolver instance', () => {
          expect(() => ArticleTC._relationWithResolverToFC({
            resolver: 'abc'
          })).toThrowError(/provide correct Resolver/);
        });
        it('should throw error if provided `type` property', () => {
          expect(() => ArticleTC._relationWithResolverToFC({
            resolver: UserTC.getResolver('findById'),
            type: _graphql.GraphQLInt
          })).toThrowError(/use `resolver` and `type`/);
        });
        it('should throw error if provided `resolve` property', () => {
          expect(() => ArticleTC._relationWithResolverToFC({
            resolver: UserTC.getResolver('findById'),
            resolve: () => {}
          })).toThrowError(/use `resolver` and `resolve`/);
        });
      });
      describe('thunk with Resolver', () => {
        it('should convert simple relation to fieldConfig', () => {
          ArticleTC.addRelation('user', {
            resolver: UserTC.getResolver('findById')
          });
          const fc = ArticleTC.getType().getFields().user;
          expect(fc.type.name).toBe('User');
        });
        it('should convert simple relation to fieldConfig with resolver thunk', () => {
          ArticleTC.addRelation('user', {
            resolver: () => UserTC.getResolver('findById')
          });
          const fc = ArticleTC.getType().getFields().user;
          expect(fc.type.name).toBe('User');
        });
        it('should convert unthunked simple relation to fieldConfig with resolver thunk', () => {
          ArticleTC.addRelation('user', {
            resolver: () => UserTC.getResolver('findById')
          });
          const fc = ArticleTC.getType().getFields().user;
          expect(fc.type.name).toBe('User');
        });
        it('should convert cross related relations to fieldConfigs', () => {
          ArticleTC.addRelation('user', {
            resolver: UserTC.getResolver('findById')
          });
          UserTC.addRelation('lastArticle', {
            resolver: ArticleTC.getResolver('findOne')
          });
          const fc1 = ArticleTC.getType().getFields().user;
          expect(fc1.type.name).toBe('User');
          const fc2 = UserTC.getType().getFields().lastArticle;
          expect(fc2.type.name).toBe('Article');
        });
      });
      describe('thunk with FieldConfig', () => {
        it('should create field via buildRelations()', () => {
          ArticleTC.addRelation('user', {
            type: UserTC,
            resolve: () => {}
          });
          const fc = ArticleTC.getType().getFields().user;
          expect(fc.type).toBeInstanceOf(_graphql.GraphQLObjectType);
          expect(fc.type.name).toBe('User');
        });
      });
    });
    describe('get type methods', () => {
      it('getTypePlural() should return wrapped type with GraphQLList', () => {
        expect(tc.getTypePlural()).toBeInstanceOf(_graphql.GraphQLList);
        expect(tc.getTypePlural().ofType).toBe(tc.getType());
      });
      it('getTypeNonNull() should return wrapped type with GraphQLNonNull', () => {
        expect(tc.getTypeNonNull()).toBeInstanceOf(_graphql.GraphQLNonNull);
        expect(tc.getTypeNonNull().ofType).toBe(tc.getType());
      });
    });
    it('should have chainable methods', () => {
      expect(tc.setFields({})).toBe(tc);
      expect(tc.setField('f1', {
        type: 'Int'
      })).toBe(tc);
      expect(tc.extendField('f1', {
        description: 'Ok'
      })).toBe(tc);
      expect(tc.deprecateFields('f1')).toBe(tc);
      expect(tc.addFields({})).toBe(tc);
      expect(tc.removeField('f1')).toBe(tc);
      expect(tc.removeOtherFields('f1')).toBe(tc);
      expect(tc.reorderFields(['f1'])).toBe(tc);
      expect(tc.addRelation('user', {})).toBe(tc);
      expect(tc.setInterfaces(['A', 'B'])).toBe(tc);
      expect(tc.addInterface('A')).toBe(tc);
      expect(tc.removeInterface('A')).toBe(tc);
      expect(tc.setResolver('myResolver', new _Resolver.Resolver({
        name: 'myResolver'
      }, _.schemaComposer))).toBe(tc);
      expect(tc.addResolver(new _Resolver.Resolver({
        name: 'myResolver'
      }, _.schemaComposer))).toBe(tc);
      expect(tc.removeResolver('myResolver')).toBe(tc);
      expect(tc.setTypeName('Type2')).toBe(tc);
      expect(tc.setDescription('Description')).toBe(tc);
      expect(tc.setRecordIdFn(() => ({}))).toBe(tc);
    });
    describe('deprecateFields()', () => {
      let tc1;
      beforeEach(() => {
        tc1 = _ObjectTypeComposer.ObjectTypeComposer.create({
          name: 'MyType',
          fields: {
            name: 'String',
            age: 'Int',
            dob: 'Date'
          }
        }, _.schemaComposer);
      });
      it('should accept string', () => {
        tc1.deprecateFields('name');
        expect(tc1.getFieldConfig('name').deprecationReason).toBe('deprecated');
        expect(tc1.getFieldConfig('age').deprecationReason).toBeUndefined();
        expect(tc1.getFieldConfig('dob').deprecationReason).toBeUndefined();
      });
      it('should accept array of string', () => {
        tc1.deprecateFields(['name', 'age']);
        expect(tc1.getFieldConfig('name').deprecationReason).toBe('deprecated');
        expect(tc1.getFieldConfig('age').deprecationReason).toBe('deprecated');
        expect(tc1.getFieldConfig('dob').deprecationReason).toBeUndefined();
      });
      it('should accept object with fields and reasons', () => {
        tc1.deprecateFields({
          age: 'dont use',
          dob: 'old field'
        });
        expect(tc1.getFieldConfig('name').deprecationReason).toBeUndefined();
        expect(tc1.getFieldConfig('age').deprecationReason).toBe('dont use');
        expect(tc1.getFieldConfig('dob').deprecationReason).toBe('old field');
      });
      it('should throw error on unexisted field', () => {
        expect(() => {
          tc1.deprecateFields('unexisted');
        }).toThrowError(/Cannot deprecate unexisted field/);
        expect(() => {
          tc1.deprecateFields(['unexisted']);
        }).toThrowError(/Cannot deprecate unexisted field/);
        expect(() => {
          tc1.deprecateFields({
            unexisted: 'Deprecate reason'
          });
        }).toThrowError(/Cannot deprecate unexisted field/);
      });
    });
    describe('getFieldTC()', () => {
      const myTC = _ObjectTypeComposer.ObjectTypeComposer.create('MyCustomType', _.schemaComposer);
  
      myTC.addFields({
        scalar: 'String',
        list: '[Int]',
        obj: _ObjectTypeComposer.ObjectTypeComposer.create(`type MyCustomObjType { name: String }`, _.schemaComposer),
        objArr: [_ObjectTypeComposer.ObjectTypeComposer.create(`type MyCustomObjType2 { name: String }`, _.schemaComposer)],
        iface: _InterfaceTypeComposer.InterfaceTypeComposer.create(`interface MyInterfaceType { field: String }`, _.schemaComposer),
        enum: _EnumTypeComposer.EnumTypeComposer.create(`enum MyEnumType { FOO BAR }`, _.schemaComposer),
        union: _UnionTypeComposer.UnionTypeComposer.create(`union MyUnionType = MyCustomObjType | MyCustomObjType2`, _.schemaComposer)
      });
      it('should return TypeComposer for object field', () => {
        const tco = myTC.getFieldTC('obj');
        expect(tco).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(tco.getTypeName()).toBe('MyCustomObjType');
      });
      it('should return TypeComposer for wrapped object field', () => {
        const tco = myTC.getFieldTC('objArr');
        expect(tco).toBeInstanceOf(_ObjectTypeComposer.ObjectTypeComposer);
        expect(tco.getTypeName()).toBe('MyCustomObjType2');
      });
      it('should return TypeComposer for scalar fields', () => {
        const tco = myTC.getFieldTC('scalar');
        expect(tco).toBeInstanceOf(_ScalarTypeComposer.ScalarTypeComposer);
        expect(tco.getTypeName()).toBe('String');
      });
      it('should return TypeComposer for scalar list fields', () => {
        const tco = myTC.getFieldTC('list');
        expect(tco).toBeInstanceOf(_ScalarTypeComposer.ScalarTypeComposer);
        expect(tco.getTypeName()).toBe('Int');
      });
      it('should return TypeComposer for enum fields', () => {
        const tco = myTC.getFieldTC('enum');
        expect(tco).toBeInstanceOf(_EnumTypeComposer.EnumTypeComposer);
        expect(tco.getTypeName()).toBe('MyEnumType');
      });
      it('should return TypeComposer for interface list fields', () => {
        const tco = myTC.getFieldTC('iface');
        expect(tco).toBeInstanceOf(_InterfaceTypeComposer.InterfaceTypeComposer);
        expect(tco.getTypeName()).toBe('MyInterfaceType');
      });
      it('should return TypeComposer for union list fields', () => {
        const tco = myTC.getFieldTC('union');
        expect(tco).toBeInstanceOf(_UnionTypeComposer.UnionTypeComposer);
        expect(tco.getTypeName()).toBe('MyUnionType');
      });
    });
    describe('check isTypeOf methods', () => {
      it('check methods setIstypeOf() getIstypeOf()', () => {
        const tc1 = _.schemaComposer.createObjectTC('type A { f: Int }');
  
        expect(tc1.getIsTypeOf()).toBeUndefined();
  
        const isTypeOf = () => true;
  
        tc1.setIsTypeOf(isTypeOf);
        expect(tc1.getIsTypeOf()).toBe(isTypeOf);
      });
      it('integration test',
      /*#__PURE__*/
      _asyncToGenerator(function* () {
        const tc1 = _.schemaComposer.createObjectTC('type A { a: Int }');
  
        tc1.setIsTypeOf(source => {
          return source && source.kind === 'A';
        });
  
        const tc2 = _.schemaComposer.createObjectTC('type B { b: Int }');
  
        tc2.setIsTypeOf(source => {
          return source && source.kind === 'B';
        });
  
        _.schemaComposer.createUnionTC('union MyUnion = A | B');
  
        _.schemaComposer.Query.addFields({
          check: {
            type: '[MyUnion]',
            resolve: () => [{
              kind: 'A',
              a: 1
            }, {
              kind: 'B',
              b: 2
            }, {
              kind: 'C',
              c: 3
            }]
          }
        });
  
        const res = yield (0, _graphql.graphql)(_.schemaComposer.buildSchema(), `
            query {
              check {
                __typename
                ... on A {
                  a
                }
                ... on B {
                  b
                }
              }
            }
          `);
        expect(res.data).toEqual({
          check: [{
            __typename: 'A',
            a: 1
          }, {
            __typename: 'B',
            b: 2
          }, null]
        });
      }));
    });
    describe('InputType convert methods', () => {
      it('getInputType()', () => {
        const input = tc.getInputType();
        expect(input).toBeInstanceOf(_graphql.GraphQLInputObjectType); // must return the same instance!
  
        expect(input).toBe(tc.getInputType());
      });
      it('hasInputTypeComposer()', () => {
        expect(tc.hasInputTypeComposer()).toBeFalsy();
        const input = tc.getInputType();
        expect(input).toBeInstanceOf(_graphql.GraphQLInputObjectType);
        expect(tc.hasInputTypeComposer()).toBeTruthy();
      });
      it('setInputTypeComposer()', () => {
        const itc1 = _InputTypeComposer.InputTypeComposer.createTemp(`Input`);
  
        tc.setInputTypeComposer(itc1);
        const itc2 = tc.getInputTypeComposer();
        expect(itc1).toBe(itc2);
      });
      it('getInputTypeComposer()', () => {
        const itc = tc.getInputTypeComposer();
        expect(itc).toBeInstanceOf(_InputTypeComposer.InputTypeComposer); // must return the same instance!
  
        expect(itc).toBe(tc.getInputTypeComposer());
      });
      it('getITC()', () => {
        expect(tc.getITC()).toBe(tc.getInputTypeComposer());
      });
      it('removeInputTypeComposer()', () => {
        const itc1 = tc.getInputTypeComposer();
        tc.removeInputTypeComposer();
        const itc2 = tc.getInputTypeComposer();
        expect(itc1).not.toBe(itc2);
      });
    });
  });