def test_raises_the_inline_operation_if_no_operation_is_provided(): doc = 'query Example { a } query OtherExample { a }' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', { 'a': GraphQLField(GraphQLString) }) with raises(GraphQLError) as excinfo: execute(GraphQLSchema(Type), Data(), ast) assert 'Must provide operation name if query contains multiple operations' in str(excinfo.value)
def test_raises_the_inline_operation_if_no_operation_is_provided(): doc = 'query Example { a } query OtherExample { a }' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', {'a': GraphQLField(GraphQLString)}) with raises(GraphQLError) as excinfo: execute(GraphQLSchema(Type), Data(), ast) assert 'Must provide operation name if query contains multiple operations' in str( excinfo.value)
def test_nulls_a_complex_tree_of_nullable_fields_that_returns_null(): doc = ''' query Q { nest { sync #promise nest { sync #promise } #promiseNest { # sync # promise #} } #promiseNest { # sync # promise # nest { # sync # promise # } # promiseNest { # sync # promise # } #} } ''' ast = parse(doc) result = execute(schema, NullingData(), ast, 'Q', {}) assert not result.errors assert result.data == {'nest': {'sync': None, 'nest': {'sync': None}}}
def test_correctly_threads_arguments(): doc = ''' query Example { b(numArg: 123, stringArg: "foo") } ''' def resolver(_, args, *_args): assert args['numArg'] == 123 assert args['stringArg'] == 'foo' resolver.got_here = True resolver.got_here = False doc_ast = parse(doc) Type = GraphQLObjectType( 'Type', { 'b': GraphQLField(GraphQLString, args={ 'numArg': GraphQLArgument(GraphQLInt), 'stringArg': GraphQLArgument(GraphQLString), }, resolver=resolver), }) result = execute(GraphQLSchema(Type), None, doc_ast, 'Example', {}) assert not result.errors assert resolver.got_here
def test_evaluates_mutations_serially(): doc = '''mutation M { first: immediatelyChangeTheNumber(newNumber: 1) { theNumber }, second: promiseToChangeTheNumber(newNumber: 2) { theNumber }, third: immediatelyChangeTheNumber(newNumber: 3) { theNumber } fourth: promiseToChangeTheNumber(newNumber: 4) { theNumber }, fifth: immediatelyChangeTheNumber(newNumber: 5) { theNumber } }''' ast = parse(doc) result = execute(schema, Root(6), ast, 'M') assert not result.errors assert result.data == \ { 'first': {'theNumber': 1}, 'second': {'theNumber': 2}, 'third': {'theNumber': 3}, 'fourth': {'theNumber': 4}, 'fifth': {'theNumber': 5}, }
def test_executes_union_types_with_inline_fragment(): # This is the valid version of the query in the above test. ast = parse(''' { __typename name pets { __typename ... on Dog { name barks } ... on Cat { name meows } } } ''') result = execute(schema, john, ast) assert not result.errors assert result.data == { '__typename': 'Person', 'name': 'John', 'pets': [ {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ] }
def test_supports_the_type_root_field(): TestType = GraphQLObjectType("TestType", {"testField": GraphQLField(GraphQLString)}) schema = GraphQLSchema(TestType) request = '{ __type(name: "TestType") { name } }' result = execute(schema, object(), parse(request)) assert not result.errors assert result.data == {"__type": {"name": "TestType"}}
def test_executes_interface_types_with_inline_fragment(): # This is the valid version of the query in the above test. ast = parse(''' { __typename name friends { __typename name ... on Dog { barks } ... on Cat { meows } } } ''') result = execute(schema, john, ast) assert not result.errors assert result.data == { '__typename': 'Person', 'name': 'John', 'friends': [ {'__typename': 'Person', 'name': 'Liz'}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ] }
def test_correctly_threads_arguments(): doc = ''' query Example { b(numArg: 123, stringArg: "foo") } ''' def resolver(_, args, *_args): assert args['numArg'] == 123 assert args['stringArg'] == 'foo' resolver.got_here = True resolver.got_here = False doc_ast = parse(doc) Type = GraphQLObjectType('Type', { 'b': GraphQLField( GraphQLString, args={ 'numArg': GraphQLArgument(GraphQLInt), 'stringArg': GraphQLArgument(GraphQLString), }, resolver=resolver), }) result = execute(GraphQLSchema(Type), None, doc_ast, 'Example', {}) assert not result.errors assert resolver.got_here
def test_supports_the_type_root_field(): TestType = GraphQLObjectType('TestType', {'testField': GraphQLField(GraphQLString)}) schema = GraphQLSchema(TestType) request = '{ __type(name: "TestType") { name } }' result = execute(schema, object(), parse(request)) assert not result.errors assert result.data == {'__type': {'name': 'TestType'}}
def test_does_not_include_illegal_fields_in_output(): doc = 'mutation M { thisIsIllegalDontIncludeMe }' ast = parse(doc) Q = GraphQLObjectType('Q', {'a': GraphQLField(GraphQLString)}) M = GraphQLObjectType('M', {'c': GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Q, M), None, ast) assert not result.errors assert result.data == {}
def test_supports_the_type_root_field(): TestType = GraphQLObjectType('TestType', { 'testField': GraphQLField(GraphQLString) }) schema = GraphQLSchema(TestType) request = '{ __type(name: "TestType") { name } }' result = execute(schema, object(), parse(request)) assert not result.errors assert result.data == {'__type': {'name': 'TestType'}}
def test_nulls_the_top_level_if_sync_non_nullable_field_returns_null(): doc = ''' query Q { nonNullSync } ''' ast = parse(doc) result = execute(schema, NullingData(), ast) assert result.data is None assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == 'Cannot return null for non-nullable type.'
def test_nulls_the_top_level_if_sync_non_nullable_field_throws(): doc = ''' query Q { nonNullSync } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast) assert result.data is None assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == non_null_sync_error.message
def test_nulls_a_nullable_field_that_returns_null(): doc = ''' query Q { sync } ''' ast = parse(doc) result = execute(schema, NullingData(), ast, 'Q', {}) assert not result.errors assert result.data == {'sync': None}
def test_uses_the_only_operation_if_no_operation_is_provided(): doc = 'query Example { a }' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', {'a': GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), Data(), ast) assert not result.errors assert result.data == {'a': 'b'}
def test_uses_the_only_operation_if_no_operation_is_provided(): doc = 'query Example { a }' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', { 'a': GraphQLField(GraphQLString) }) result = execute(GraphQLSchema(Type), Data(), ast) assert not result.errors assert result.data == {'a': 'b'}
def test_nulls_the_top_level_if_sync_non_nullable_field_returns_null(): doc = ''' query Q { nonNullSync } ''' ast = parse(doc) result = execute(schema, NullingData(), ast) assert result.data is None assert len(result.errors) == 1 # TODO: check error location assert result.errors[0][ 'message'] == 'Cannot return null for non-nullable type.'
def test_does_not_include_illegal_fields_in_output(): doc = 'mutation M { thisIsIllegalDontIncludeMe }' ast = parse(doc) Q = GraphQLObjectType('Q', { 'a': GraphQLField(GraphQLString) }) M = GraphQLObjectType('M', { 'c': GraphQLField(GraphQLString) }) result = execute(GraphQLSchema(Q, M), None, ast) assert not result.errors assert result.data == {}
def test_nulls_a_nullable_field_that_throws_sync(): doc = ''' query Q { sync } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == sync_error.message assert result.data == {'sync': None}
def test_nulls_a_nullable_field_that_returns_null(): doc = ''' query Q { sync } ''' ast = parse(doc) result = execute(schema, NullingData(), ast, 'Q', {}) assert not result.errors assert result.data == { 'sync': None }
def test_uses_the_mutation_schema_for_queries(): doc = 'query Q { a } mutation M { c }' class Data(object): a = 'b' c = 'd' ast = parse(doc) Q = GraphQLObjectType('Q', {'a': GraphQLField(GraphQLString)}) M = GraphQLObjectType('M', {'c': GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Q, M), Data(), ast, 'M') assert not result.errors assert result.data == {'c': 'd'}
def test_nulls_a_nullable_field_that_throws_sync(): doc = ''' query Q { sync } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == sync_error.message assert result.data == { 'sync': None }
def test_nulls_a_sync_returned_object_that_contains_a_non_nullable_field_that_throws( ): doc = ''' query Q { nest { nonNullSync, } } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == non_null_sync_error.message assert result.data == {'nest': None}
def test_uses_the_mutation_schema_for_queries(): doc = 'query Q { a } mutation M { c }' class Data(object): a = 'b' c = 'd' ast = parse(doc) Q = GraphQLObjectType('Q', { 'a': GraphQLField(GraphQLString) }) M = GraphQLObjectType('M', { 'c': GraphQLField(GraphQLString) }) result = execute(GraphQLSchema(Q, M), Data(), ast, 'M') assert not result.errors assert result.data == {'c': 'd'}
def test_nulls_a_sync_returned_object_that_contains_a_non_nullable_field_that_throws(): doc = ''' query Q { nest { nonNullSync, } } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 1 # TODO: check error location assert result.errors[0]['message'] == non_null_sync_error.message assert result.data == { 'nest': None }
def test_allows_fragment_conditions_to_be_abstract_types(): ast = parse(''' { __typename name pets { ...PetFields } friends { ...FriendFields } } fragment PetFields on Pet { __typename ... on Dog { name barks } ... on Cat { name meows } } fragment FriendFields on Named { __typename name ... on Dog { barks } ... on Cat { meows } } ''') result = execute(schema, john, ast) assert not result.errors assert result.data == { '__typename': 'Person', 'name': 'John', 'pets': [ {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ], 'friends': [ {'__typename': 'Person', 'name': 'Liz'}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ] }
def test_nulls_a_complex_tree_of_nullable_fields_that_throw(): doc = ''' query Q { nest { sync #promise nest { sync #promise } #promiseNest { # sync # promise #} } #promiseNest { # sync # promise # nest { # sync # promise # } # promiseNest { # sync # promise # } #} } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 2 # TODO: check error location assert result.errors[0]['message'] == sync_error.message assert result.errors[1]['message'] == sync_error.message assert result.data == { 'nest': { 'sync': None, 'nest': { 'sync': None } } }
def test_threads_context_correctly(): doc = 'query Example { a }' class Data(object): context_thing = 'thing' ast = parse(doc) def resolver(context, *_): assert context.context_thing == 'thing' resolver.got_here = True resolver.got_here = False Type = GraphQLObjectType( 'Type', {'a': GraphQLField(GraphQLString, resolver=resolver)}) result = execute(GraphQLSchema(Type), Data(), ast, 'Example', {}) assert not result.errors assert resolver.got_here
def test_avoids_recursion(): doc = ''' query Q { a ...Frag ...Frag } fragment Frag on Type { a, ...Frag } ''' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', { 'a': GraphQLField(GraphQLString) }) result = execute(GraphQLSchema(Type), Data(), ast, 'Q') assert not result.errors assert result.data == {'a': 'b'}
def test_threads_context_correctly(): doc = 'query Example { a }' class Data(object): context_thing = 'thing' ast = parse(doc) def resolver(context, *_): assert context.context_thing == 'thing' resolver.got_here = True resolver.got_here = False Type = GraphQLObjectType('Type', { 'a': GraphQLField(GraphQLString, resolver=resolver) }) result = execute(GraphQLSchema(Type), Data(), ast, 'Example', {}) assert not result.errors assert resolver.got_here
def test_avoids_recursion(): doc = ''' query Q { a ...Frag ...Frag } fragment Frag on Type { a, ...Frag } ''' class Data(object): a = 'b' ast = parse(doc) Type = GraphQLObjectType('Type', {'a': GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), Data(), ast, 'Q') assert not result.errors assert result.data == {'a': 'b'}
def test_nulls_a_complex_tree_of_nullable_fields_that_returns_null(): doc = ''' query Q { nest { sync #promise nest { sync #promise } #promiseNest { # sync # promise #} } #promiseNest { # sync # promise # nest { # sync # promise # } # promiseNest { # sync # promise # } #} } ''' ast = parse(doc) result = execute(schema, NullingData(), ast, 'Q', {}) assert not result.errors assert result.data == { 'nest': { 'sync': None, 'nest': { 'sync': None } } }
def test_merges_parallel_fragments(): ast = parse(''' { a, ...FragOne, ...FragTwo } fragment FragOne on Type { b deep { b, deeper: deep { b } } } fragment FragTwo on Type { c deep { c, deeper: deep { c } } } ''') Type = GraphQLObjectType('Type', lambda: { 'a': GraphQLField(GraphQLString, resolver=lambda *_: 'Apple'), 'b': GraphQLField(GraphQLString, resolver=lambda *_: 'Banana'), 'c': GraphQLField(GraphQLString, resolver=lambda *_: 'Cherry'), 'deep': GraphQLField(Type, resolver=lambda *_: {}), }) schema = GraphQLSchema(query=Type) result = execute(schema, None, ast) assert not result.errors assert result.data == \ { 'a': 'Apple', 'b': 'Banana', 'c': 'Cherry', 'deep': { 'b': 'Banana', 'c': 'Cherry', 'deeper': { 'b': 'Banana', 'c': 'Cherry' } } }
def test_merges_parallel_fragments(): ast = parse(''' { a, ...FragOne, ...FragTwo } fragment FragOne on Type { b deep { b, deeper: deep { b } } } fragment FragTwo on Type { c deep { c, deeper: deep { c } } } ''') Type = GraphQLObjectType( 'Type', lambda: { 'a': GraphQLField(GraphQLString, resolver=lambda *_: 'Apple'), 'b': GraphQLField(GraphQLString, resolver=lambda *_: 'Banana'), 'c': GraphQLField(GraphQLString, resolver=lambda *_: 'Cherry'), 'deep': GraphQLField(Type, resolver=lambda *_: {}), }) schema = GraphQLSchema(query=Type) result = execute(schema, None, ast) assert not result.errors assert result.data == \ { 'a': 'Apple', 'b': 'Banana', 'c': 'Cherry', 'deep': { 'b': 'Banana', 'c': 'Cherry', 'deeper': { 'b': 'Banana', 'c': 'Cherry' } } }
def test_nulls_a_complex_tree_of_nullable_fields_that_throw(): doc = ''' query Q { nest { sync #promise nest { sync #promise } #promiseNest { # sync # promise #} } #promiseNest { # sync # promise # nest { # sync # promise # } # promiseNest { # sync # promise # } #} } ''' ast = parse(doc) result = execute(schema, ThrowingData(), ast, 'Q', {}) assert len(result.errors) == 2 # TODO: check error location assert result.errors[0]['message'] == sync_error.message assert result.errors[1]['message'] == sync_error.message assert result.data == {'nest': {'sync': None, 'nest': {'sync': None}}}
def test_nulls_out_error_subtrees(): doc = '''{ ok, error }''' class Data(object): def ok(self): return 'ok' def error(self): raise Exception('Error getting error') doc_ast = parse(doc) Type = GraphQLObjectType('Type', { 'ok': GraphQLField(GraphQLString), 'error': GraphQLField(GraphQLString), }) result = execute(GraphQLSchema(Type), Data(), doc_ast) assert result.data == {'ok': 'ok', 'error': None} assert len(result.errors) == 1 assert result.errors[0].message == 'Error getting error'
def test_nulls_out_error_subtrees(): doc = '''{ ok, error }''' class Data(object): def ok(self): return 'ok' def error(self): raise Exception('Error getting error') doc_ast = parse(doc) Type = GraphQLObjectType('Type', { 'ok': GraphQLField(GraphQLString), 'error': GraphQLField(GraphQLString), }) result = execute(GraphQLSchema(Type), Data(), doc_ast) assert result.data == {'ok': 'ok', 'error': None} assert len(result.errors) == 1 assert result.errors[0]['message'] == 'Error getting error'
def evaluates_mutations_correctly_in_the_presense_of_a_failed_mutation(): doc = '''mutation M { first: immediatelyChangeTheNumber(newNumber: 1) { theNumber }, second: promiseToChangeTheNumber(newNumber: 2) { theNumber }, third: failToChangeTheNumber(newNumber: 3) { theNumber } fourth: promiseToChangeTheNumber(newNumber: 4) { theNumber }, fifth: immediatelyChangeTheNumber(newNumber: 5) { theNumber } sixth: promiseAndFailToChangeTheNumber(newNumber: 6) { theNumber } }''' ast = parse(doc) result = execute(schema, Root(6), ast, 'M') assert result.data == \ { 'first': {'theNumber': 1}, 'second': {'theNumber': 2}, 'third': None, 'fourth': {'theNumber': 4}, 'fifth': {'theNumber': 5}, 'sixth': None, } assert len(result.errors) == 2 # TODO: check error location assert result.errors[0].message == 'Cannot change the number' assert result.errors[1].message == 'Cannot change the number'
def test_executes_using_interface_types(): # NOTE: This is an *invalid* query, but it should be an *executable* query. ast = parse(''' { __typename name friends { __typename name barks meows } } ''') result = execute(schema, john, ast) assert not result.errors assert result.data == { '__typename': 'Person', 'name': 'John', 'friends': [ {'__typename': 'Person', 'name': 'Liz'}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ] }
def test_executes_using_union_types(): # NOTE: This is an *invalid* query, but it should be an *executable* query. ast = parse(''' { __typename name pets { __typename name barks meows } } ''') result = execute(schema, john, ast) assert not result.errors assert result.data == { '__typename': 'Person', 'name': 'John', 'pets': [ {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, {'__typename': 'Dog', 'name': 'Odie', 'barks': True} ] }
def test_executes_arbitary_code(): class Data(object): a = 'Apple' b = 'Banana' c = 'Cookie' d = 'Donut' e = 'Egg' f = 'Fish' def pic(self, size=50): return 'Pic of size: {}'.format(size) def deep(self): return DeepData() def promise(self): # FIXME: promise is unsupported return Data() class DeepData(object): a = 'Already Been Done' b = 'Boring' c = ['Contrived', None, 'Confusing'] def deeper(self): return [Data(), None, Data()] doc = ''' query Example($size: Int) { a, b, x: c ...c f ...on DataType { pic(size: $size) promise { a } } deep { a b c deeper { a b } } } fragment c on DataType { d e } ''' ast = parse(doc) expected = { 'a': 'Apple', 'b': 'Banana', 'x': 'Cookie', 'd': 'Donut', 'e': 'Egg', 'f': 'Fish', 'pic': 'Pic of size: 100', 'promise': { 'a': 'Apple' }, 'deep': { 'a': 'Already Been Done', 'b': 'Boring', 'c': [ 'Contrived', None, 'Confusing' ], 'deeper': [ { 'a': 'Apple', 'b': 'Banana' }, None, { 'a': 'Apple', 'b': 'Banana' } ] } } DataType = GraphQLObjectType('DataType', lambda: { 'a': GraphQLField(GraphQLString), 'b': GraphQLField(GraphQLString), 'c': GraphQLField(GraphQLString), 'd': GraphQLField(GraphQLString), 'e': GraphQLField(GraphQLString), 'f': GraphQLField(GraphQLString), 'pic': GraphQLField( args={'size': GraphQLArgument(GraphQLInt)}, type=GraphQLString, resolver=lambda obj, args, *_: obj.pic(args['size']), ), 'deep': GraphQLField(DeepDataType), 'promise': GraphQLField(DataType), }) DeepDataType = GraphQLObjectType('DeepDataType', { 'a': GraphQLField(GraphQLString), 'b': GraphQLField(GraphQLString), 'c': GraphQLField(GraphQLList(GraphQLString)), 'deeper': GraphQLField(GraphQLList(DataType)), }) schema = GraphQLSchema(query=DataType) result = execute(schema, Data(), ast, 'Example', {'size': 100}) assert not result.errors assert result.data == expected
def test_executes_using_a_schema(): BlogImage = GraphQLObjectType( 'BlogImage', { 'url': GraphQLField(GraphQLString), 'width': GraphQLField(GraphQLInt), 'height': GraphQLField(GraphQLInt), }) BlogAuthor = GraphQLObjectType( 'Author', lambda: { 'id': GraphQLField(GraphQLString), 'name': GraphQLField(GraphQLString), 'pic': GraphQLField(BlogImage, args={ 'width': GraphQLArgument(GraphQLInt), 'height': GraphQLArgument(GraphQLInt), }, resolver=lambda obj, args, *_: obj.pic( args['width'], args['height'])), 'recentArticle': GraphQLField(BlogArticle), }) BlogArticle = GraphQLObjectType( 'Article', { 'id': GraphQLField(GraphQLNonNull(GraphQLString)), 'isPublished': GraphQLField(GraphQLBoolean), 'author': GraphQLField(BlogAuthor), 'title': GraphQLField(GraphQLString), 'body': GraphQLField(GraphQLString), 'keywords': GraphQLField(GraphQLList(GraphQLString)), }) BlogQuery = GraphQLObjectType( 'Query', { 'article': GraphQLField(BlogArticle, args={'id': GraphQLArgument(GraphQLID)}, resolver=lambda obj, args, *_: Article(args['id'])), 'feed': GraphQLField(GraphQLList(BlogArticle), resolver=lambda *_: map(Article, range(1, 10 + 1))), }) BlogSchema = GraphQLSchema(BlogQuery) class Article(object): def __init__(self, id): self.id = id self.isPublished = True self.author = Author() self.title = 'My Article {}'.format(id) self.body = 'This is a post' self.hidden = 'This data is not exposed in the schema' self.keywords = ['foo', 'bar', 1, True, None] class Author(object): id = 123 name = 'John Smith' def pic(self, width, height): return Pic(123, width, height) @property def recentArticle(self): return Article(1) class Pic(object): def __init__(self, uid, width, height): self.url = 'cdn://{}'.format(uid) self.width = str(width) self.height = str(height) request = ''' { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } ''' # Note: this is intentionally not validating to ensure appropriate # behavior occurs when executing an invalid query. result = execute(BlogSchema, None, parse(request)) assert not result.errors assert result.data == \ { "feed": [ { "id": "1", "title": "My Article 1" }, { "id": "2", "title": "My Article 2" }, { "id": "3", "title": "My Article 3" }, { "id": "4", "title": "My Article 4" }, { "id": "5", "title": "My Article 5" }, { "id": "6", "title": "My Article 6" }, { "id": "7", "title": "My Article 7" }, { "id": "8", "title": "My Article 8" }, { "id": "9", "title": "My Article 9" }, { "id": "10", "title": "My Article 10" } ], "article": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "pic": { "url": "cdn://123", "width": 640, "height": 480 }, "recentArticle": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "keywords": [ "foo", "bar", "1", "true", None ] } } } }
def test_executes_using_a_schema(): BlogImage = GraphQLObjectType('BlogImage', { 'url': GraphQLField(GraphQLString), 'width': GraphQLField(GraphQLInt), 'height': GraphQLField(GraphQLInt), }) BlogAuthor = GraphQLObjectType('Author', lambda: { 'id': GraphQLField(GraphQLString), 'name': GraphQLField(GraphQLString), 'pic': GraphQLField(BlogImage, args={ 'width': GraphQLArgument(GraphQLInt), 'height': GraphQLArgument(GraphQLInt), }, resolver=lambda obj, args, *_: obj.pic(args['width'], args['height']) ), 'recentArticle': GraphQLField(BlogArticle), }) BlogArticle = GraphQLObjectType('Article', { 'id': GraphQLField(GraphQLNonNull(GraphQLString)), 'isPublished': GraphQLField(GraphQLBoolean), 'author': GraphQLField(BlogAuthor), 'title': GraphQLField(GraphQLString), 'body': GraphQLField(GraphQLString), 'keywords': GraphQLField(GraphQLList(GraphQLString)), }) BlogQuery = GraphQLObjectType('Query', { 'article': GraphQLField( BlogArticle, args={'id': GraphQLArgument(GraphQLID)}, resolver=lambda obj, args, *_: Article(args['id'])), 'feed': GraphQLField( GraphQLList(BlogArticle), resolver=lambda *_: map(Article, range(1, 10 + 1))), }) BlogSchema = GraphQLSchema(BlogQuery) class Article(object): def __init__(self, id): self.id = id self.isPublished = True self.author = Author() self.title = 'My Article {}'.format(id) self.body = 'This is a post' self.hidden = 'This data is not exposed in the schema' self.keywords = ['foo', 'bar', 1, True, None] class Author(object): id = 123 name = 'John Smith' def pic(self, width, height): return Pic(123, width, height) @property def recentArticle(self): return Article(1) class Pic(object): def __init__(self, uid, width, height): self.url = 'cdn://{}'.format(uid) self.width = str(width) self.height = str(height) request = ''' { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } ''' # Note: this is intentionally not validating to ensure appropriate # behavior occurs when executing an invalid query. result = execute(BlogSchema, None, parse(request)) assert not result.errors assert result.data == \ { "feed": [ { "id": "1", "title": "My Article 1" }, { "id": "2", "title": "My Article 2" }, { "id": "3", "title": "My Article 3" }, { "id": "4", "title": "My Article 4" }, { "id": "5", "title": "My Article 5" }, { "id": "6", "title": "My Article 6" }, { "id": "7", "title": "My Article 7" }, { "id": "8", "title": "My Article 8" }, { "id": "9", "title": "My Article 9" }, { "id": "10", "title": "My Article 10" } ], "article": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "pic": { "url": "cdn://123", "width": 640, "height": 480 }, "recentArticle": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "keywords": [ "foo", "bar", "1", "true", None ] } } } }
def test_executes_arbitary_code(): class Data(object): a = 'Apple' b = 'Banana' c = 'Cookie' d = 'Donut' e = 'Egg' f = 'Fish' def pic(self, size=50): return 'Pic of size: {}'.format(size) def deep(self): return DeepData() def promise(self): # FIXME: promise is unsupported return Data() class DeepData(object): a = 'Already Been Done' b = 'Boring' c = ['Contrived', None, 'Confusing'] def deeper(self): return [Data(), None, Data()] doc = ''' query Example($size: Int) { a, b, x: c ...c f ...on DataType { pic(size: $size) promise { a } } deep { a b c deeper { a b } } } fragment c on DataType { d e } ''' ast = parse(doc) expected = { 'a': 'Apple', 'b': 'Banana', 'x': 'Cookie', 'd': 'Donut', 'e': 'Egg', 'f': 'Fish', 'pic': 'Pic of size: 100', 'promise': { 'a': 'Apple' }, 'deep': { 'a': 'Already Been Done', 'b': 'Boring', 'c': ['Contrived', None, 'Confusing'], 'deeper': [{ 'a': 'Apple', 'b': 'Banana' }, None, { 'a': 'Apple', 'b': 'Banana' }] } } DataType = GraphQLObjectType( 'DataType', lambda: { 'a': GraphQLField(GraphQLString), 'b': GraphQLField(GraphQLString), 'c': GraphQLField(GraphQLString), 'd': GraphQLField(GraphQLString), 'e': GraphQLField(GraphQLString), 'f': GraphQLField(GraphQLString), 'pic': GraphQLField( args={'size': GraphQLArgument(GraphQLInt)}, type=GraphQLString, resolver=lambda obj, args, *_: obj.pic(args['size']), ), 'deep': GraphQLField(DeepDataType), 'promise': GraphQLField(DataType), }) DeepDataType = GraphQLObjectType( 'DeepDataType', { 'a': GraphQLField(GraphQLString), 'b': GraphQLField(GraphQLString), 'c': GraphQLField(GraphQLList(GraphQLString)), 'deeper': GraphQLField(GraphQLList(DataType)), }) schema = GraphQLSchema(query=DataType) result = execute(schema, Data(), ast, 'Example', {'size': 100}) assert not result.errors assert result.data == expected