def test_nodes_can_be_fetched_directly(): graph = create_graph({ 42: "Leave it to Psmith", 43: "The Gentleman's Guide to Vice and Virtue", 44: "Catch-22", }) result = graph.resolve( Query( g.key( "books", Query.fields.books_connection( Query.fields.books_connection.params.first(2), g.key( "nodes", BooksConnection.fields.nodes( g.key("title", Book.fields.title()), )), g.key( "page_info", BooksConnection.fields.page_info( g.key("has_next_page", PageInfo.fields.has_next_page()), )), )), )) assert_that( result.books, has_attrs(nodes=contains_exactly( has_attrs(title="Leave it to Psmith"), has_attrs(title="The Gentleman's Guide to Vice and Virtue"), ), ))
def test_object_builder_getters_access_value_directly(self): User = g.ObjectType("User", fields=( g.field("name", type=g.String), g.field("email_address", type=g.String), )) object_builder = g.create_object_builder( User( g.key("n", User.fields.name()), g.key("e", User.fields.email_address()), )) @object_builder.getter(User.fields.name) def resolve_name(user): return user["name"] @object_builder.getter(User.fields.email_address) def resolve_email_address(user): return user["emailAddress"] result = object_builder({ "name": "Bob", "emailAddress": "*****@*****.**" }) assert_that(result, has_attrs( n="Bob", e="*****@*****.**", ))
def test_fragment_can_be_spread_into_nullable_type(): User = g.ObjectType("User", fields=lambda: ( g.field("name", type=g.String), )) Root = g.ObjectType( "Root", fields=lambda: ( g.field("user", type=g.NullableType(User)), ), ) graphql_query = """ query { user { ... on User { name } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("user", Root.fields.user( g.key("name", User.fields.name()), )), ), ))
def test_named_fragments_are_expanded(): Root = g.ObjectType( "Root", ( g.field("value", type=g.Int), ), ) graphql_query = """ query { one: value ...Two three: value ...Four } fragment Two on Root { two: value } fragment Four on Root { four: value } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.value()), g.key("two", Root.fields.value()), g.key("three", Root.fields.value()), g.key("four", Root.fields.value()), ), ))
def test_fragments_are_recursively_merged(): Root = g.ObjectType( "Root", fields=lambda: ( g.field("value", type=g.Int), ), ) graphql_query = """ query { ... on Root { ... on Root { one: value } } ... on Root { ... on Root { two: value } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.value()), g.key("two", Root.fields.value()), ), ))
def test_object_builder_creates_object_using_field_resolvers(self): User = g.ObjectType("User", fields=(g.field("name", type=g.String, params=(g.param( "truncate", type=g.Int, default=None), )), )) object_builder = g.create_object_builder( User( g.key("name", User.fields.name()), g.key("initial", User.fields.name(User.fields.name.params.truncate(1))), )) @object_builder.field(User.fields.name) def resolve_name(field_query): if field_query.args.truncate is None: return lambda user: user["name"] else: return lambda user: user["name"][:field_query.args.truncate] result = object_builder({"name": "Bob"}) assert_that(result, has_attrs( name="Bob", initial="B", ))
def test_can_request_fields_of_list(): Root = g.ObjectType( "Root", fields=lambda: ( g.field("one", type=g.ListType(One)), ), ) One = g.ObjectType( "One", fields=lambda: ( g.field("two", type=g.Int), ), ) graphql_query = """ query { one { two } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( g.key("two", One.fields.two()), )), ), ))
def test_when_merging_fragments_then_nested_object_fields_can_overlap(): Root = g.ObjectType( "Root", fields=lambda: (g.field("user", type=User), ), ) User = g.ObjectType( "User", fields=lambda: (g.field("address", type=Address), ), ) Address = g.ObjectType( "Address", fields=lambda: ( g.field("first_line", type=g.String), g.field("city", type=g.String), g.field("postcode", type=g.String), ), ) graphql_query = """ query { ... on Root { user { address { firstLine city } } } ... on Root { user { address { city postcode } } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that( object_query, is_query( Root( g.key( "user", Root.fields.user( g.key( "address", User.fields.address( g.key("firstLine", Address.fields.first_line()), g.key("city", Address.fields.city()), g.key("postcode", Address.fields.postcode()), )), )), ), ))
def resolve_author(graph, query): assert_that( query, is_query( g.ListType(Author)( g.key("name", Author.fields.name()), g.key("books_written", Author.fields.books_written()), ))) return [ g.Object(dict(name="<author 1>", books_written=1)), g.Object(dict(name="<author 2>", books_written=2)), ]
def resolve_reader(graph, query): assert_that( query, is_query( g.ListType(Reader)( g.key("name", Reader.fields.name()), g.key("books_read", Reader.fields.books_read()), ))) return [ g.Object(dict(name="<reader 3>", books_read=3)), g.Object(dict(name="<reader 4>", books_read=4)), ]
def test_can_recursively_resolve(): Root = g.ObjectType( "Root", fields=lambda: [ g.field("books", type=g.ListType(Book)), ], ) Book = g.ObjectType( "Book", fields=lambda: [ g.field("title", type=g.String), ], ) @g.resolver(Root) def resolve_root(graph, query): return query.create_object(iterables.to_dict( (field_query.key, graph.resolve(field_query.type_query)) for field_query in query.field_queries )) @g.resolver(g.ListType(Book)) def resolve_book(graph, query): books = [ dict(title="Leave it to Psmith"), dict(title="Pericles, Prince of Tyre"), ] return [ query.element_query.create_object(iterables.to_dict( (field_query.key, book[field_query.field.name]) for field_query in query.element_query.field_queries )) for book in books ] resolvers = [resolve_root, resolve_book] query = Root( g.key("books", Root.fields.books( g.key("title", Book.fields.title()), )), ) result = g.create_graph(resolvers).resolve(query) assert_that(result, has_attrs( books=contains_exactly( has_attrs(title="Leave it to Psmith"), has_attrs(title="Pericles, Prince of Tyre"), ), ))
def test_graphql_arg_values_from_variables_are_converted(graph_type, graphql_type, variable_value, arg_value): if callable(arg_value): arg_value = arg_value(graph_type) Root = g.ObjectType( "Root", fields=( g.field("one", type=g.Int, params=[ g.param("arg", type=graph_type), ]), ), ) graphql_query = """ query ($var: %s) { one(arg: $var) } """ % (graphql_type, ) object_query = _document_text_to_graph_query(graphql_query, query_type=Root, variables={"var": variable_value}) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( Root.fields.one.params.arg(arg_value), )), ), ))
def test_literal_graphql_arg_values_are_converted(arg_type, arg_string, arg_value): if callable(arg_value): arg_value = arg_value(arg_type) Root = g.ObjectType( "Root", fields=( g.field("one", type=g.Int, params=[ g.param("arg", type=arg_type), ]), ), ) graphql_query = """ query { one(arg: %s) } """ % (arg_string, ) object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( Root.fields.one.params.arg(arg_value), )), ), ))
def test_graphql_field_args_are_read(): Root = g.ObjectType( "Root", fields=( g.field("one", type=g.Int, params=[ g.param("arg0", type=g.String), g.param("arg1", type=g.String), ]), ), ) graphql_query = """ query { one(arg0: "one", arg1: "two") } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( Root.fields.one.params.arg0("one"), Root.fields.one.params.arg1("two"), )), ), ))
def test_directives_can_use_variables(self): Root = g.ObjectType( "Root", ( g.field("one", type=g.Int), ), ) graphql_query = """ query ($t: Boolean!, $f: Boolean!) { includedField: one @include(if: $t) excludedField: one @include(if: $f) } """ object_query = _document_text_to_graph_query( graphql_query, query_type=Root, variables={"t": True, "f": False}, ) assert_that(object_query, is_query( Root( g.key("includedField", Root.fields.one()), ), ))
def test_directives_can_be_used_on_fragment_spreads(self): Root = g.ObjectType( "Root", ( g.field("one", type=g.Int), ), ) graphql_query = """ query { ... IncludedFragment @include(if: true) ... ExcludedFragment @include(if: false) } fragment IncludedFragment on Root { includedField: one } fragment ExcludedFragment on Root { excludedField: one } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("includedField", Root.fields.one()), ), ))
def test_when_null_variable_is_missing_then_variable_is_null(): Root = g.ObjectType( "Root", fields=( g.field("one", type=g.Int, params=[ g.param("arg", type=g.NullableType(g.Int)), ]), ), ) graphql_query = """ query ($var: Int) { one(arg: $var) } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root, variables={}) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( Root.fields.one.params.arg(None), )), ), ))
def test_simple_mutation_is_converted_to_object_query(): QueryRoot = g.ObjectType( "Query", ( g.field("query_value", type=g.Int), ), ) MutationRoot = g.ObjectType( "Mutation", ( g.field("mutation_value", type=g.Int), ), ) graphql_query = """ mutation { mutationValue } """ object_query = _document_text_to_graph_query(graphql_query, query_type=QueryRoot, mutation_type=MutationRoot) assert_that(object_query, is_query( MutationRoot( g.key("mutationValue", MutationRoot.fields.mutation_value()), ), ))
def test_graphql_field_args_are_converted_to_snake_case(): Root = g.ObjectType( "Root", fields=( g.field("one", type=g.Int, params=[ g.param("arg_zero", type=g.String), ]), ), ) graphql_query = """ query { one(argZero: "one") } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( Root.fields.one.params.arg_zero("one"), )), ), ))
def test_graphql_query_args_are_read(): Root = g.ObjectType( "Root", fields=(g.field("one", type=g.Int, params=[ g.param("arg", type=g.Int), ]), ), ) graphql_query = """ query ($value: Int!) { one(arg: $value) } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root, variables={"value": 42}) assert_that( object_query, is_query( Root( g.key("one", Root.fields.one(Root.fields.one.params.arg(42), )), ), ))
def test_can_get_scalar_from_root(): Root = g.ObjectType( "Root", fields=[ g.field("one", type=g.Int), g.field("two", type=g.Int), ], ) @g.resolver(Root) def resolve_root(graph, query): values = dict( one=1, two=2, ) return query.create_object( iterables.to_dict((field_query.key, values[field_query.field.name]) for field_query in query.fields)) resolvers = [resolve_root] query = Root(g.key("value", Root.fields.one()), ) result = g.create_graph(resolvers).resolve(query) assert_that(result, has_attrs(value=1))
def test_when_type_is_object_then_typename_field_is_resolved(self): User = g.ObjectType("User", fields=(g.field("name", type=g.String), )) object_builder = g.create_object_builder( User(g.key("type", schema.typename_field()), )) result = object_builder({}) assert_that(result, has_attrs(type="User", ))
def test_when_merging_fragments_then_scalar_fields_can_overlap(): Root = g.ObjectType( "Root", fields=lambda: (g.field("user", type=User), ), ) User = g.ObjectType( "User", fields=( g.field("name", type=g.String), g.field("address", type=g.String), g.field("role", type=g.String), ), ) graphql_query = """ query { ... on Root { user { name address } } ... on Root { user { name role } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that( object_query, is_query( Root( g.key( "user", Root.fields.user( g.key("name", User.fields.name()), g.key("address", User.fields.address()), g.key("role", User.fields.role()), )), ), ))
def test_when_there_are_no_edges_then_connection_is_empty(): graph = create_graph({}) result = graph.resolve( Query( g.key( "books", Query.fields.books_connection( Query.fields.books_connection.params.first(2), g.key( "edges", BooksConnection.fields.edges( g.key( "node", BookEdge.fields.node( g.key("title", Book.fields.title()), )), )), g.key( "page_info", BooksConnection.fields.page_info( g.key("end_cursor", PageInfo.fields.end_cursor()), g.key("has_next_page", PageInfo.fields.has_next_page()), )), )), )) assert_that( result.books, has_attrs( edges=contains_exactly(), page_info=has_attrs(end_cursor=None, has_next_page=False), ))
def test_fragments_can_be_on_more_specific_type(): Animal = g.InterfaceType( "Animal", fields=( g.field("name", type=g.String), ), ) Cat = g.ObjectType( "Cat", fields=( g.field("name", type=g.String), g.field("whisker_count", type=g.Int), ), interfaces=(Animal, ), ) Root = g.ObjectType( "Root", ( g.field("animal", type=Animal), ), ) graphql_query = """ query { animal { name ... on Cat { whiskerCount } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root, types=(Cat, )) assert_that(object_query, is_query( Root( g.key("animal", Root.fields.animal( g.key("name", Animal.fields.name()), g.key("whiskerCount", Cat.fields.whisker_count()), )), ), ))
def fetch(*, after): return graph.resolve( Query( g.key( "books", Query.fields.books_connection( Query.fields.books_connection.params.first(2), Query.fields.books_connection.params.after(after), g.key( "edges", BooksConnection.fields.edges( g.key( "node", BookEdge.fields.node( g.key("title", Book.fields.title()), )), )), g.key( "page_info", BooksConnection.fields.page_info( g.key("end_cursor", PageInfo.fields.end_cursor()), g.key("has_next_page", PageInfo.fields.has_next_page()), )), )), ))
def test_fields_can_be_nested(): Root = g.ObjectType( "Root", fields=lambda: ( g.field("one", type=One), ), ) One = g.ObjectType( "One", fields=lambda: ( g.field("two", type=Two), ), ) Two = g.ObjectType( "Two", fields=lambda: ( g.field("three", type=g.Int), ), ) graphql_query = """ query { one { two { three } } } """ object_query = _document_text_to_graph_query(graphql_query, query_type=Root) assert_that(object_query, is_query( Root( g.key("one", Root.fields.one( g.key("two", One.fields.two( g.key("three", Two.fields.three()), )), )), ), ))
def test_when_first_is_negative_then_error_is_raised(): graph = create_graph({}) query = Query( g.key( "books", Query.fields.books_connection( Query.fields.books_connection.params.first(-1), g.key( "page_info", BooksConnection.fields.page_info( g.key("has_next_page", PageInfo.fields.has_next_page()), )), )), ) error = pytest.raises(g.GraphError, lambda: graph.resolve(query)) assert_that(str(error.value), equal_to("first must be non-negative integer, was -1"))
def fetch(*, after): return graph.resolve( Query( g.key( "books", Query.fields.books_connection( Query.fields.books_connection.params.first(2), Query.fields.books_connection.params.after(after), g.key( "edges", BooksConnection.fields.edges( g.key("cursor", BookEdge.fields.cursor()), g.key( "node", BookEdge.fields.node( g.key("title", Book.fields.title()), )), )), )), ))
def test_when_type_is_interface_then_typename_field_is_unresolved(self): User = g.InterfaceType("User", fields=(g.field("name", type=g.String), )) object_builder = g.create_object_builder( User(g.key("type", schema.typename_field()), )) error = pytest.raises(g.GraphError, lambda: object_builder({})) assert_that(str(error.value), equal_to("Resolver missing for field type_name"))