func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMissingAnInterfaceArgument(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) expectedError := `AnotherInterface.field expects argument "input" but AnotherObject.field does not provide it.` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWithASupersetNullableInterfaceFieldType(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithFieldType(anotherObject) expectedError := `AnotherInterface.field expects type "String!" but AnotherObject.field provides type "String".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWithSubsetNonNullInterfaceFieldType(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, }) _, err := schemaWithFieldType(anotherObject) if err != nil { t.Fatalf(`unexpected error: %v for type "%v"`, err, anotherObject) } }
func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithInterfacesAsFunctionReturningAnArray(t *testing.T) { anotherInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, })) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefiningResolveTypeWithImplementingTypeDefiningIsTypeOf(t *testing.T) { anotherInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, })) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWithASubtypedInterfaceField_Interface(t *testing.T) { var anotherInterface *graphql.Interface anotherInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: (graphql.FieldsThunk)(func() graphql.Fields { return graphql.Fields{ "field": &graphql.Field{ Type: anotherInterface, }, } }), }) var anotherObject *graphql.Object anotherObject = graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: (graphql.FieldsThunk)(func() graphql.Fields { return graphql.Fields{ "field": &graphql.Field{ Type: anotherObject, }, } }), }) _, err := schemaWithFieldType(anotherObject) if err != nil { t.Fatalf(`unexpected error: %v for type "%v"`, err, anotherObject) } }
func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveSameNamedObjectsImplementingAnInterface(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) FirstBadObject := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{ anotherInterface, }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) SecondBadObject := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{ anotherInterface, }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "iface": &graphql.Field{ Type: anotherInterface, }, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, Types: []graphql.Type{FirstBadObject, SecondBadObject}, }) expectedError := `Schema must contain unique named types but contains multiple types named "BadObject".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestTypeSystem_ObjectsCanOnlyImplementInterfaces_AcceptsAnObjectImplementingAnInterface(t *testing.T) { anotherInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithObjectImplementingType(anotherInterfaceType) if err != nil { t.Fatalf(`unexpected error: %v"`, err) } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWithADifferentlyTypeInterfaceField(t *testing.T) { typeA := graphql.NewObject(graphql.ObjectConfig{ Name: "A", Fields: graphql.Fields{ "foo": &graphql.Field{ Type: graphql.String, }, }, }) typeB := graphql.NewObject(graphql.ObjectConfig{ Name: "B", Fields: graphql.Fields{ "foo": &graphql.Field{ Type: graphql.String, }, }, }) anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: typeA, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: typeB, }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) expectedError := `AnotherInterface.field expects type "A" but AnotherObject.field provides type "B".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMap(t *testing.T) { someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.Int, }, }, }) someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.Int, }, }, Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someInterface} }), IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "iface": &graphql.Field{ Type: someInterface, }, }, }), Types: []graphql.Type{someSubType}, }) if err != nil { t.Fatalf("unexpected error, got: %v", err) } if schema.Type("SomeSubtype") != someSubType { t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.Type("SomeSubtype")) } }
func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) { badInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "BadInterface", Fields: graphql.Fields{ "badField": &graphql.Field{ Type: ttype, }, }, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "f": &graphql.Field{ Type: badInterfaceType, }, }, }), }) }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, "anotherInput": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String), }, }, }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) expectedError := `AnotherObject.field(anotherInput:) is of required type "String!" but is not also provided by the interface AnotherInterface.field.` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
/* Given a function to map from an ID to an underlying object, and a function to map from an underlying object to the concrete GraphQLObjectType it corresponds to, constructs a `Node` interface that objects can implement, and a field config for a `node` root field. If the typeResolver is omitted, object resolution on the interface will be handled with the `isTypeOf` method on object types, as with any GraphQL interface without a provided `resolveType` method. */ func NewNodeDefinitions(config NodeDefinitionsConfig) *NodeDefinitions { nodeInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Node", Description: "An object with an ID", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), Description: "The id of the object", }, }, ResolveType: config.TypeResolve, }) nodeField := &graphql.Field{ Name: "Node", Description: "Fetches an object given its ID", Type: nodeInterface, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.ID), Description: "The ID of an object", }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if config.IDFetcher == nil { return nil, nil } id := "" if iid, ok := p.Args["id"]; ok { id = fmt.Sprintf("%v", iid) } return config.IDFetcher(id, p.Info, p.Context) }, } return &NodeDefinitions{ NodeInterface: nodeInterface, NodeField: nodeField, } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhichImpementsAnInterfaceFieldAlongWithAdditionalOptionalArguments(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, "anotherInput": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) if err != nil { t.Fatalf(`unexpected error: %v for type "%v"`, err, anotherObject) } }
"id": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) var objectType = graphql.NewObject(graphql.ObjectConfig{ Name: "Object", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, }) var interfaceType = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Interface", }) var unionType = graphql.NewUnion(graphql.UnionConfig{ Name: "Union", Types: []*graphql.Object{ objectType, }, }) var enumType = graphql.NewEnum(graphql.EnumConfig{ Name: "Enum", Values: graphql.EnumValueConfigMap{ "foo": &graphql.EnumValueConfig{}, }, }) var inputObjectType = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "InputObject",
type testCat2 struct { Name string `json:"name"` Meows bool `json:"meows"` } type testPerson struct { Name string `json:"name"` Pets []testPet `json:"pets"` Friends []testNamedType `json:"friends"` } var namedType = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, }, }) var dogType = graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", Interfaces: []*graphql.Interface{ namedType, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, "barks": &graphql.Field{ Type: graphql.Boolean, },
func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { var encounteredContextValue string var encounteredSchema graphql.Schema var encounteredRootValue string var personType2 *graphql.Object namedType2 := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { encounteredSchema = p.Info.Schema encounteredContextValue, _ = p.Context.Value("authToken").(string) encounteredRootValue = p.Info.RootValue.(*testPerson).Name return personType2 }, }) personType2 = graphql.NewObject(graphql.ObjectConfig{ Name: "Person", Interfaces: []*graphql.Interface{ namedType2, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, "friends": &graphql.Field{ Type: graphql.NewList(namedType2), }, }, }) schema2, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: personType2, }) john2 := &testPerson{ Name: "John", Friends: []testNamedType{ liz, }, } doc := `{ name, friends { name } }` expected := &graphql.Result{ Data: map[string]interface{}{ "name": "John", "friends": []interface{}{ map[string]interface{}{ "name": "Liz", }, }, }, } // parse query ast := testutil.TestParse(t, doc) // create context ctx := context.Background() ctx = context.WithValue(ctx, "authToken", "contextStringValue123") // execute ep := graphql.ExecuteParams{ Schema: schema2, AST: ast, Root: john2, Context: ctx, } result := testutil.TestExecute(t, ep) if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } if !reflect.DeepEqual("contextStringValue123", encounteredContextValue) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff("contextStringValue123", encounteredContextValue)) } if !reflect.DeepEqual("John", encounteredRootValue) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff("John", encounteredRootValue)) } if !reflect.DeepEqual(schema2, encounteredSchema) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(schema2, encounteredSchema)) } }
func init() { someBoxInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeBox", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return stringBoxObject }, Fields: graphql.FieldsThunk(func() graphql.Fields { return graphql.Fields{ "deepBox": &graphql.Field{ Type: someBoxInterface, }, "unrelatedField": &graphql.Field{ Type: graphql.String, }, } }), }) stringBoxObject = graphql.NewObject(graphql.ObjectConfig{ Name: "StringBox", Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someBoxInterface} }), Fields: graphql.FieldsThunk(func() graphql.Fields { return graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.String, }, "deepBox": &graphql.Field{ Type: stringBoxObject, }, "unrelatedField": &graphql.Field{ Type: graphql.String, }, "listStringBox": &graphql.Field{ Type: graphql.NewList(stringBoxObject), }, "stringBox": &graphql.Field{ Type: stringBoxObject, }, "intBox": &graphql.Field{ Type: intBoxObject, }, } }), }) intBoxObject = graphql.NewObject(graphql.ObjectConfig{ Name: "IntBox", Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someBoxInterface} }), Fields: graphql.FieldsThunk(func() graphql.Fields { return graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.Int, }, "deepBox": &graphql.Field{ Type: someBoxInterface, }, "unrelatedField": &graphql.Field{ Type: graphql.String, }, "listStringBox": &graphql.Field{ Type: graphql.NewList(stringBoxObject), }, "stringBox": &graphql.Field{ Type: stringBoxObject, }, "intBox": &graphql.Field{ Type: intBoxObject, }, } }), }) var nonNullStringBox1Interface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "NonNullStringBox1", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return stringBoxObject }, Fields: graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, }) NonNullStringBox1Impl := graphql.NewObject(graphql.ObjectConfig{ Name: "NonNullStringBox1Impl", Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someBoxInterface, nonNullStringBox1Interface} }), Fields: graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, "unrelatedField": &graphql.Field{ Type: graphql.String, }, "deepBox": &graphql.Field{ Type: someBoxInterface, }, }, }) var nonNullStringBox2Interface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "NonNullStringBox2", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return stringBoxObject }, Fields: graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, }) NonNullStringBox2Impl := graphql.NewObject(graphql.ObjectConfig{ Name: "NonNullStringBox2Impl", Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someBoxInterface, nonNullStringBox2Interface} }), Fields: graphql.Fields{ "scalar": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, "unrelatedField": &graphql.Field{ Type: graphql.String, }, "deepBox": &graphql.Field{ Type: someBoxInterface, }, }, }) var connectionObject = graphql.NewObject(graphql.ObjectConfig{ Name: "Connection", Fields: graphql.Fields{ "edges": &graphql.Field{ Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{ Name: "Edge", Fields: graphql.Fields{ "node": &graphql.Field{ Type: graphql.NewObject(graphql.ObjectConfig{ Name: "Node", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.ID, }, "name": &graphql.Field{ Type: graphql.String, }, }, }), }, }, })), }, }, }) var err error schema, err = graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ "someBox": &graphql.Field{ Type: someBoxInterface, }, "connection": &graphql.Field{ Type: connectionObject, }, }, }), Types: []graphql.Type{ intBoxObject, stringBoxObject, NonNullStringBox1Impl, NonNullStringBox2Impl, }, }) if err != nil { panic(err) } }
}) var someUnionType = graphql.NewUnion(graphql.UnionConfig{ Name: "SomeUnion", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Types: []*graphql.Object{ someObjectType, }, }) var someInterfaceType = graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "f": &graphql.Field{ Type: graphql.String, }, }, }) var someEnumType = graphql.NewEnum(graphql.EnumConfig{ Name: "SomeEnum", Values: graphql.EnumValueConfigMap{ "ONLY": &graphql.EnumValueConfig{}, }, }) var someInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "SomeInputObject", Fields: graphql.InputObjectConfigFieldMap{ "f": &graphql.InputObjectFieldConfig{
func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { var dogType *graphql.Object var catType *graphql.Object var humanType *graphql.Object petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { if _, ok := p.Value.(*testCat); ok { return catType } if _, ok := p.Value.(*testDog); ok { return dogType } if _, ok := p.Value.(*testHuman); ok { return humanType } return nil }, }) humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, }, }) dogType = graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", Interfaces: []*graphql.Interface{ petType, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, "woofs": &graphql.Field{ Type: graphql.Boolean, }, }, }) catType = graphql.NewObject(graphql.ObjectConfig{ Name: "Cat", Interfaces: []*graphql.Interface{ petType, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, "meows": &graphql.Field{ Type: graphql.Boolean, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, &testHuman{"Jon"}, }, nil }, }, }, }), Types: []graphql.Type{catType, dogType}, }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } query := `{ pets { name ... on Dog { woofs } ... on Cat { meows } } }` expected := &graphql.Result{ Data: map[string]interface{}{ "pets": []interface{}{ map[string]interface{}{ "name": "Odie", "woofs": bool(true), }, map[string]interface{}{ "name": "Garfield", "meows": bool(false), }, nil, }, }, Errors: []gqlerrors.FormattedError{ { Message: `Runtime Object type "Human" is not a possible type for "Pet".`, Locations: []location.SourceLocation{}, }, }, } result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) if len(result.Errors) == 0 { t.Fatalf("wrong result, expected errors: %v, got: %v", len(expected.Errors), len(result.Errors)) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func init() { Luke = StarWarsChar{ ID: "1000", Name: "Luke Skywalker", AppearsIn: []int{4, 5, 6}, HomePlanet: "Tatooine", } Vader = StarWarsChar{ ID: "1001", Name: "Darth Vader", AppearsIn: []int{4, 5, 6}, HomePlanet: "Tatooine", } Han = StarWarsChar{ ID: "1002", Name: "Han Solo", AppearsIn: []int{4, 5, 6}, } Leia = StarWarsChar{ ID: "1003", Name: "Leia Organa", AppearsIn: []int{4, 5, 6}, HomePlanet: "Alderaa", } Tarkin = StarWarsChar{ ID: "1004", Name: "Wilhuff Tarkin", AppearsIn: []int{4}, } Threepio = StarWarsChar{ ID: "2000", Name: "C-3PO", AppearsIn: []int{4, 5, 6}, PrimaryFunction: "Protocol", } Artoo = StarWarsChar{ ID: "2001", Name: "R2-D2", AppearsIn: []int{4, 5, 6}, PrimaryFunction: "Astromech", } Luke.Friends = append(Luke.Friends, []StarWarsChar{Han, Leia, Threepio, Artoo}...) Vader.Friends = append(Luke.Friends, []StarWarsChar{Tarkin}...) Han.Friends = append(Han.Friends, []StarWarsChar{Luke, Leia, Artoo}...) Leia.Friends = append(Leia.Friends, []StarWarsChar{Luke, Han, Threepio, Artoo}...) Tarkin.Friends = append(Tarkin.Friends, []StarWarsChar{Vader}...) Threepio.Friends = append(Threepio.Friends, []StarWarsChar{Luke, Han, Leia, Artoo}...) Artoo.Friends = append(Artoo.Friends, []StarWarsChar{Luke, Han, Leia}...) HumanData = map[int]StarWarsChar{ 1000: Luke, 1001: Vader, 1002: Han, 1003: Leia, 1004: Tarkin, } DroidData = map[int]StarWarsChar{ 2000: Threepio, 2001: Artoo, } episodeEnum := graphql.NewEnum(graphql.EnumConfig{ Name: "Episode", Description: "One of the films in the Star Wars Trilogy", Values: graphql.EnumValueConfigMap{ "NEWHOPE": &graphql.EnumValueConfig{ Value: 4, Description: "Released in 1977.", }, "EMPIRE": &graphql.EnumValueConfig{ Value: 5, Description: "Released in 1980.", }, "JEDI": &graphql.EnumValueConfig{ Value: 6, Description: "Released in 1983.", }, }, }) characterInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Character", Description: "A character in the Star Wars Trilogy", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the character.", }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the character.", }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", }, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { if character, ok := p.Value.(StarWarsChar); ok { id, _ := strconv.Atoi(character.ID) human := GetHuman(id) if human.ID != "" { return humanType } } return droidType }, }) characterInterface.AddFieldConfig("friends", &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the character, or an empty list if they have none.", }) humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Description: "A humanoid creature in the Star Wars universe.", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.ID, nil } return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.Name, nil } return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.Friends, nil } return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.AppearsIn, nil } return nil, nil }, }, "homePlanet": &graphql.Field{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.HomePlanet, nil } return nil, nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) droidType = graphql.NewObject(graphql.ObjectConfig{ Name: "Droid", Description: "A mechanical creature in the Star Wars universe.", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.ID, nil } return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Name, nil } return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { friends := []map[string]interface{}{} for _, friend := range droid.Friends { friends = append(friends, map[string]interface{}{ "name": friend.Name, "id": friend.ID, }) } return droid.Friends, nil } return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.AppearsIn, nil } return nil, nil }, }, "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.PrimaryFunction, nil } return nil, nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "hero": &graphql.Field{ Type: characterInterface, Args: graphql.FieldConfigArgument{ "episode": &graphql.ArgumentConfig{ Description: "If omitted, returns the hero of the whole saga. If " + "provided, returns the hero of that particular episode.", Type: episodeEnum, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetHero(p.Args["episode"]), nil }, }, "human": &graphql.Field{ Type: humanType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the human", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetHuman(p.Args["id"].(int)), nil }, }, "droid": &graphql.Field{ Type: droidType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the droid", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetDroid(p.Args["id"].(int)), nil }, }, }, }) StarWarsSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) }
func init() { var beingInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Being", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var petInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var canineInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Canine", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var dogCommandEnum = graphql.NewEnum(graphql.EnumConfig{ Name: "DogCommand", Values: graphql.EnumValueConfigMap{ "SIT": &graphql.EnumValueConfig{ Value: 0, }, "HEEL": &graphql.EnumValueConfig{ Value: 1, }, "DOWN": &graphql.EnumValueConfig{ Value: 2, }, }, }) var dogType = graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "nickname": &graphql.Field{ Type: graphql.String, }, "barkVolume": &graphql.Field{ Type: graphql.Int, }, "barks": &graphql.Field{ Type: graphql.Boolean, }, "doesKnowCommand": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "dogCommand": &graphql.ArgumentConfig{ Type: dogCommandEnum, }, }, }, "isHousetrained": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "atOtherHomes": &graphql.ArgumentConfig{ Type: graphql.Boolean, DefaultValue: true, }, }, }, "isAtLocation": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "x": &graphql.ArgumentConfig{ Type: graphql.Int, }, "y": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, }, }, Interfaces: []*graphql.Interface{ beingInterface, petInterface, canineInterface, }, }) var furColorEnum = graphql.NewEnum(graphql.EnumConfig{ Name: "FurColor", Values: graphql.EnumValueConfigMap{ "BROWN": &graphql.EnumValueConfig{ Value: 0, }, "BLACK": &graphql.EnumValueConfig{ Value: 1, }, "TAN": &graphql.EnumValueConfig{ Value: 2, }, "SPOTTED": &graphql.EnumValueConfig{ Value: 3, }, }, }) var catType = graphql.NewObject(graphql.ObjectConfig{ Name: "Cat", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "nickname": &graphql.Field{ Type: graphql.String, }, "meowVolume": &graphql.Field{ Type: graphql.Int, }, "meows": &graphql.Field{ Type: graphql.Boolean, }, "furColor": &graphql.Field{ Type: furColorEnum, }, }, Interfaces: []*graphql.Interface{ beingInterface, petInterface, }, }) var catOrDogUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "CatOrDog", Types: []*graphql.Object{ dogType, catType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var intelligentInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Intelligent", Fields: graphql.Fields{ "iq": &graphql.Field{ Type: graphql.Int, }, }, }) var humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Interfaces: []*graphql.Interface{ beingInterface, intelligentInterface, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "pets": &graphql.Field{ Type: graphql.NewList(petInterface), }, "iq": &graphql.Field{ Type: graphql.Int, }, }, }) humanType.AddFieldConfig("relatives", &graphql.Field{ Type: graphql.NewList(humanType), }) var alienType = graphql.NewObject(graphql.ObjectConfig{ Name: "Alien", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Interfaces: []*graphql.Interface{ beingInterface, intelligentInterface, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "iq": &graphql.Field{ Type: graphql.Int, }, "numEyes": &graphql.Field{ Type: graphql.Int, }, }, }) var dogOrHumanUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "DogOrHuman", Types: []*graphql.Object{ dogType, humanType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var humanOrAlienUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "HumanOrAlien", Types: []*graphql.Object{ alienType, humanType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var complexInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "ComplexInput", Fields: graphql.InputObjectConfigFieldMap{ "requiredField": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.Boolean), }, "intField": &graphql.InputObjectFieldConfig{ Type: graphql.Int, }, "stringField": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, "booleanField": &graphql.InputObjectFieldConfig{ Type: graphql.Boolean, }, "stringListField": &graphql.InputObjectFieldConfig{ Type: graphql.NewList(graphql.String), }, }, }) var complicatedArgs = graphql.NewObject(graphql.ObjectConfig{ Name: "ComplicatedArgs", // TODO List // TODO Coercion // TODO NotNulls Fields: graphql.Fields{ "intArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "intArg": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, }, "nonNullIntArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "nonNullIntArg": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, }, }, "stringArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "stringArg": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, "booleanArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "booleanArg": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "enumArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "enumArg": &graphql.ArgumentConfig{ Type: furColorEnum, }, }, }, "floatArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "floatArg": &graphql.ArgumentConfig{ Type: graphql.Float, }, }, }, "idArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "idArg": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, }, "stringListArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "stringListArg": &graphql.ArgumentConfig{ Type: graphql.NewList(graphql.String), }, }, }, "complexArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "complexArg": &graphql.ArgumentConfig{ Type: complexInputObject, }, }, }, "multipleReqs": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "req1": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "req2": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, }, }, "multipleOpts": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "opt1": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, "opt2": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, }, }, "multipleOptAndReq": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "req1": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "req2": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "opt1": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, "opt2": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, }, }, }, }) queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ "human": &graphql.Field{ Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, Type: humanType, }, "alien": &graphql.Field{ Type: alienType, }, "dog": &graphql.Field{ Type: dogType, }, "cat": &graphql.Field{ Type: catType, }, "pet": &graphql.Field{ Type: petInterface, }, "catOrDog": &graphql.Field{ Type: catOrDogUnion, }, "dogOrHuman": &graphql.Field{ Type: dogOrHumanUnion, }, "humanOrAlien": &graphql.Field{ Type: humanOrAlienUnion, }, "complicatedArgs": &graphql.Field{ Type: complicatedArgs, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryRoot, Directives: []*graphql.Directive{ graphql.NewDirective(graphql.DirectiveConfig{ Name: "operationOnly", Locations: []string{graphql.DirectiveLocationQuery}, }), graphql.IncludeDirective, graphql.SkipDirective, }, Types: []graphql.Type{ catType, dogType, humanType, alienType, }, }) if err != nil { panic(err) } TestSchema = &schema }
func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, }, }) // ie declare that Dog belongs to Pet interface dogType := graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", Interfaces: []*graphql.Interface{ petType, }, IsTypeOf: func(p graphql.IsTypeOfParams) bool { _, ok := p.Value.(*testDog) return ok }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { return dog.Name, nil } return nil, nil }, }, "woofs": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { return dog.Woofs, nil } return nil, nil }, }, }, }) // ie declare that Cat belongs to Pet interface catType := graphql.NewObject(graphql.ObjectConfig{ Name: "Cat", Interfaces: []*graphql.Interface{ petType, }, IsTypeOf: func(p graphql.IsTypeOfParams) bool { _, ok := p.Value.(*testCat) return ok }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { return cat.Name, nil } return nil, nil }, }, "meows": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { return cat.Meows, nil } return nil, nil }, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, }, nil }, }, }, }), Types: []graphql.Type{catType, dogType}, }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } query := `{ pets { name ... on Dog { woofs } ... on Cat { meows } } }` expected := &graphql.Result{ Data: map[string]interface{}{ "pets": []interface{}{ map[string]interface{}{ "name": "Odie", "woofs": bool(true), }, map[string]interface{}{ "name": "Garfield", "meows": bool(false), }, }, }, Errors: nil, } result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) if len(result.Errors) != 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }