def may_extend_mutations_and_subscriptions(): mutation_schema = build_schema(""" type Query { queryField: String } type Mutation { mutationField: String } type Subscription { subscriptionField: String } """) ast = parse(""" extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """) original_print = print_schema(mutation_schema) extended_schema = extend_schema(mutation_schema, ast) assert extended_schema != mutation_schema assert print_schema(mutation_schema) == original_print assert print_schema(extended_schema) == dedent(""" type Mutation { mutationField: String newMutationField: Int } type Query { queryField: String newQueryField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """)
def extends_objects_by_adding_new_fields(): schema = build_schema( ''' type Query { someObject: SomeObject } type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! """Old field description.""" oldField: String } interface SomeInterface { self: SomeInterface } interface AnotherInterface { self: SomeObject } ''' ) extension_sdl = dedent( ''' extend type SomeObject { """New field description.""" newField(arg: Boolean): String } ''' ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent( ''' type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! """Old field description.""" oldField: String """New field description.""" newField(arg: Boolean): String } ''' )
def adds_schema_definition_missing_in_the_original_schema(): schema = build_schema(""" directive @foo on SCHEMA type Foo """) assert schema.query_type is None extension_sdl = dedent(""" schema @foo { query: Foo } """) extended_schema = extend_schema(schema, parse(extension_sdl)) query_type = assert_object_type(extended_schema.query_type) assert query_type.name == "Foo" expect_ast_node(extended_schema, extension_sdl)
def adds_schema_definition_missing_in_the_original_schema(): schema = build_schema(""" directive @foo on SCHEMA type Foo """) assert schema.query_type is None extension_sdl = dedent(""" schema @foo { query: Foo } """) schema = extend_schema(schema, parse(extension_sdl)) query_type = schema.query_type assert query_type assert query_type.name == "Foo" assert print_ast_node(schema) == extension_sdl.rstrip()
def rejects_a_union_type_with_empty_types(): schema = build_schema(""" type Query { test: BadUnion } union BadUnion """) schema = extend_schema(schema, parse(""" directive @test on UNION extend union BadUnion @test """)) assert validate_schema(schema) == [{ 'message': 'Union type BadUnion must define one or more' ' member types.', 'locations': [(6, 13), (4, 13)]}]
def rejects_an_input_object_type_with_missing_fields(): schema = build_schema(""" type Query { field(arg: SomeInputObject): String } input SomeInputObject """) schema = extend_schema(schema, parse(""" directive @test on INPUT_OBJECT extend input SomeInputObject @test """)) assert validate_schema(schema) == [{ 'message': 'Input Object type SomeInputObject' ' must define one or more fields.', 'locations': [(6, 13), (4, 13)]}]
def may_extend_mutations_and_subscriptions(): mutationSchema = GraphQLSchema( query=GraphQLObjectType( name='Query', fields=lambda: { 'queryField': GraphQLField(GraphQLString)}), mutation=GraphQLObjectType( name='Mutation', fields=lambda: { 'mutationField': GraphQLField(GraphQLString)}), subscription=GraphQLObjectType( name='Subscription', fields=lambda: { 'subscriptionField': GraphQLField(GraphQLString)})) ast = parse(""" extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """) original_print = print_schema(mutationSchema) extended_schema = extend_schema(mutationSchema, ast) assert extended_schema != mutationSchema assert print_schema(mutationSchema) == original_print assert print_schema(extended_schema) == dedent(""" type Mutation { mutationField: String newMutationField: Int } type Query { queryField: String newQueryField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """)
def adds_schema_definition_missing_in_the_original_schema(): schema = build_schema(""" directive @foo on SCHEMA type Foo """) assert schema.query_type is None extension_sdl = dedent(""" schema @foo { query: Foo } """) extended_schema = extend_schema(schema, parse(extension_sdl)) query_type = extended_schema.query_type assert isinstance(query_type, GraphQLObjectType) assert query_type.name == "Foo" assert print_ast_node(extended_schema) + "\n" == extension_sdl
def may_extend_directives_with_new_directive(): schema = build_schema( """ type Query { foo: String } """ ) extension_sdl = dedent( ''' """New directive.""" directive @new(enable: Boolean!, tag: String) repeatable on QUERY | FIELD ''' ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == extension_sdl
def rejects_an_enum_type_without_values(): schema = build_schema(""" type Query { field: SomeEnum } enum SomeEnum """) schema = extend_schema(schema, parse(""" directive @test on ENUM extend enum SomeEnum @test """)) assert validate_schema(schema) == [{ 'message': 'Enum type SomeEnum must define one or more values.', 'locations': [(6, 13), (4, 13)]}]
def adds_multiple_new_root_types_via_schema_extension(): schema = build_schema("type Query") extend_ast = parse(""" extend schema { mutation: Mutation subscription: Subscription } type Mutation type Subscription """) extended_schema = extend_schema(schema, extend_ast) mutation_type = assert_object_type(extended_schema.mutation_type) assert mutation_type.name == "Mutation" subscription_type = assert_object_type( extended_schema.subscription_type) assert subscription_type.name == "Subscription"
def adds_new_root_types_via_schema_extension(): schema = build_schema( """ type Query type MutationRoot """ ) extension_sdl = dedent( """ extend schema { mutation: MutationRoot } """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) mutation_type = assert_object_type(extended_schema.mutation_type) assert mutation_type.name == "MutationRoot" assert print_extension_nodes(extended_schema) == extension_sdl
def extends_objects_by_adding_implemented_new_interfaces(): schema = build_schema( """ type Query { someObject: SomeObject } type SomeObject implements OldInterface { oldField: String } interface OldInterface { oldField: String } """ ) extend_ast = parse( """ extend type SomeObject implements NewInterface { newField: String } interface NewInterface { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent( """ type SomeObject implements OldInterface & NewInterface { oldField: String newField: String } interface NewInterface { newField: String } """ )
def rejects_object_implementing_extended_interface_due_to_type_mismatch(): schema = build_schema(""" type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """) extended_schema = extend_schema(schema, parse(""" extend interface AnotherInterface { newInterfaceField: NewInterface } interface NewInterface { newField: String } interface MismatchingInterface { newField: String } extend type AnotherObject { newInterfaceField: MismatchingInterface } # Required to prevent unused interface errors type DummyObject implements NewInterface & MismatchingInterface { newField: String } """)) assert validate_schema(extended_schema) == [{ 'message': 'Interface field AnotherInterface.newInterfaceField' ' expects type NewInterface' ' but AnotherObject.newInterfaceField' ' is type MismatchingInterface.', 'locations': [(3, 34), (15, 34)]}]
def builds_types_with_deprecated_fields_and_values(): schema = GraphQLSchema() extend_ast = parse(""" type SomeObject { deprecatedField: String @deprecated(reason: "not used anymore") } enum SomeEnum { DEPRECATED_VALUE @deprecated(reason: "do not use") } """) extended_schema = extend_schema(schema, extend_ast) some_type = assert_object_type(extended_schema.get_type("SomeObject")) deprecated_field = some_type.fields["deprecatedField"] assert deprecated_field.deprecation_reason == "not used anymore" some_enum = assert_enum_type(extended_schema.get_type("SomeEnum")) deprecated_enum = some_enum.values["DEPRECATED_VALUE"] assert deprecated_enum.deprecation_reason == "do not use"
def rejects_an_object_implementing_same_interface_twice_due_to_extension(): schema = build_schema(""" type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """) extended_schema = extend_schema(schema, parse( 'extend type AnotherObject implements AnotherInterface')) assert validate_schema(extended_schema) == [{ 'message': 'Type AnotherObject can only implement' ' AnotherInterface once.', 'locations': [(10, 43), (1, 38)]}]
def rejects_a_union_type_with_duplicated_member_type(): schema = build_schema( """ type Query { test: BadUnion } type TypeA { field: String } type TypeB { field: String } union BadUnion = | TypeA | TypeB | TypeA """ ) assert validate_schema(schema) == [ { "message": "Union type BadUnion can only include type TypeA once.", "locations": [(15, 17), (17, 17)], } ] schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) assert validate_schema(schema) == [ { "message": "Union type BadUnion can only include type TypeA once.", "locations": [(15, 17), (17, 17)], }, { "message": "Union type BadUnion can only include type TypeB once.", "locations": [(16, 17), (1, 25)], }, ]
def extends_unions_by_adding_new_types(): schema = build_schema(""" type Query { someUnion: SomeUnion } union SomeUnion = Foo | Biz type Foo { foo: String } type Biz { biz: String } type Bar { bar: String } """) extend_ast = parse(""" extend union SomeUnion = Bar """) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent(""" union SomeUnion = Foo | Biz | Bar """)
def rejects_a_union_type_with_empty_types(): schema = build_schema(""" type Query { test: BadUnion } union BadUnion """) schema = extend_schema( schema, parse(""" directive @test on UNION extend union BadUnion @test """), ) assert validate_schema(schema) == [{ "message": "Union type BadUnion must define one or more" " member types.", "locations": [(6, 13), (4, 17)], }]
def applies_multiple_schema_extensions(): schema = build_schema("type Query") extend_ast = parse(""" extend schema { mutation: Mutation } type Mutation extend schema { subscription: Subscription } type Subscription """) extended_schema = extend_schema(schema, extend_ast) mutation_type = extended_schema.mutation_type assert isinstance(mutation_type, GraphQLObjectType) assert mutation_type.name == "Mutation" subscription_type = extended_schema.subscription_type assert isinstance(subscription_type, GraphQLObjectType) assert subscription_type.name == "Subscription"
def extends_objects_by_adding_new_fields_with_arguments(): schema = build_schema( """ type SomeObject type Query { someObject: SomeObject } """ ) extend_ast = parse( """ input NewInputObj { field1: Int field2: [Float] field3: String! } extend type SomeObject { newField(arg1: String, arg2: NewInputObj!): String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent( """ type SomeObject { newField(arg1: String, arg2: NewInputObj!): String } input NewInputObj { field1: Int field2: [Float] field3: String! } """ )
def extends_objects_by_adding_new_fields_with_existing_types(): schema = build_schema(""" type Query { someObject: SomeObject } type SomeObject enum SomeEnum { VALUE } """) extend_ast = parse(""" extend type SomeObject { newField(arg1: SomeEnum!): SomeEnum } """) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent(""" type SomeObject { newField(arg1: SomeEnum!): SomeEnum } """)
def rejects_object_implementing_extended_interface_due_to_missing_args(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse( """ extend interface AnotherInterface { newField(test: Boolean): String } extend type AnotherObject { newField: String } """ ), ) assert validate_schema(extended_schema) == [ { "message": "Interface field argument" " AnotherInterface.newField(test:) expected" " but AnotherObject.newField does not provide it.", "locations": [(3, 28), (7, 19)], } ]
def extends_scalars_by_adding_specified_by_directive(): schema = build_schema(""" type Query { foo: Foo } scalar Foo directive @foo on SCALAR """) extension_sdl = dedent(""" extend scalar Foo @foo extend scalar Foo @specifiedBy(url: "https://example.com/foo_spec") """) extended_schema = extend_schema(schema, parse(extension_sdl)) foo = assert_scalar_type(extended_schema.get_type("Foo")) assert foo.specified_by_url == "https://example.com/foo_spec" assert validate_schema(extended_schema) == [] assert print_extension_nodes(foo) == extension_sdl
def extends_scalars_by_adding_new_directives(): schema = build_schema(""" type Query { someScalar(arg: SomeScalar): SomeScalar } directive @foo(arg: SomeScalar) on SCALAR input FooInput { foo: SomeScalar } scalar SomeScalar """) extension_sdl = dedent(""" extend scalar SomeScalar @foo """) extended_schema = extend_schema(schema, parse(extension_sdl)) some_scalar = assert_scalar_type( extended_schema.get_type("SomeScalar")) assert validate_schema(extended_schema) == [] expect_extension_ast_nodes(some_scalar, extension_sdl)
def rejects_object_implementing_extended_interface_due_to_missing_field(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse( """ extend interface AnotherInterface { newField: String } extend type AnotherObject { differentNewField: String } """ ), ) assert validate_schema(extended_schema) == [ { "message": "Interface field AnotherInterface.newField expected" " but AnotherObject does not provide it.", "locations": [(3, 19), (10, 13), (6, 17)], } ]
def adds_new_unused_types(): schema = build_schema( """ type Query { dummy: String } """ ) extension_sdl = dedent( """ type DummyUnionMember { someField: String } enum UnusedEnum { SOME_VALUE } input UnusedInput { someField: String } interface UnusedInterface { someField: String } type UnusedObject { someField: String } union UnusedUnion = DummyUnionMember """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == extension_sdl
def extends_scalars_by_adding_new_directives(): schema = build_schema(""" type Query { someScalar(arg: SomeScalar): SomeScalar } directive @foo(arg: SomeScalar) on SCALAR input FooInput { foo: SomeScalar } scalar SomeScalar """) extension_sdl = dedent(""" extend scalar SomeScalar @foo """) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] some_scalar = extended_schema.get_type("SomeScalar") assert isinstance(some_scalar, GraphQLScalarType) assert print_extension_nodes(some_scalar) == extension_sdl
def extends_enums_by_adding_new_values(): schema = build_schema( ''' type Query { someEnum(arg: SomeEnum): SomeEnum } directive @foo(arg: SomeEnum) on SCHEMA enum SomeEnum { """Old value description.""" OLD_VALUE } ''' ) extend_ast = parse( ''' extend enum SomeEnum { """New value description.""" NEW_VALUE } ''' ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent( ''' enum SomeEnum { """Old value description.""" OLD_VALUE """New value description.""" NEW_VALUE } ''' )
def extends_inputs_by_adding_new_fields(): schema = build_schema( ''' type Query { someInput(arg: SomeInput): String } directive @foo(arg: SomeInput) on SCHEMA input SomeInput { """Old field description.""" oldField: String } ''' ) extend_ast = parse( ''' extend input SomeInput { """New field description.""" newField: String } ''' ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert print_schema_changes(schema, extended_schema) == dedent( ''' input SomeInput { """Old field description.""" oldField: String """New field description.""" newField: String } ''' )