Skip to content

Commit

Permalink
simplify schema in defer tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Cito committed Apr 7, 2024
1 parent d73b874 commit a8cffbf
Showing 1 changed file with 83 additions and 86 deletions.
169 changes: 83 additions & 86 deletions tests/execution/test_defer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,29 @@
GraphQLString,
)


def resolve_null_sync(_obj, _info) -> None:
"""A resolver returning a null value synchronously."""
return


async def resolve_null_async(_obj, _info) -> None:
"""A resolver returning a null value asynchronously."""
return


friend_type = GraphQLObjectType(
"Friend",
{
"id": GraphQLField(GraphQLID),
"name": GraphQLField(GraphQLString),
"asyncNonNullErrorField": GraphQLField(
GraphQLNonNull(GraphQLString), resolve=resolve_null_async
),
"nonNullName": GraphQLField(GraphQLNonNull(GraphQLString)),
},
)

hero_type = GraphQLObjectType(
"Hero",
{
"id": GraphQLField(GraphQLID),
"name": GraphQLField(GraphQLString),
"nonNullName": GraphQLField(GraphQLNonNull(GraphQLString)),
"friends": GraphQLField(GraphQLList(friend_type)),
},
)

query = GraphQLObjectType("Query", {"hero": GraphQLField(hero_type)})

schema = GraphQLSchema(query)


class Friend(NamedTuple):
id: int
Expand All @@ -58,57 +59,44 @@ class Friend(NamedTuple):

friends = [Friend(2, "Han"), Friend(3, "Leia"), Friend(4, "C-3PO")]

hero = {"id": 1, "name": "Luke", "friends": friends}

async def resolve_slow(_obj, _info) -> str:
"""Simulate a slow async resolver returning a value."""
await sleep(0)
return "slow"

class Resolvers:
"""Various resolver functions for testing."""

async def resolve_bad(_obj, _info) -> str:
"""Simulate a bad async resolver raising an error."""
raise RuntimeError("bad")
@staticmethod
def null(_info) -> None:
"""A resolver returning a null value synchronously."""
return

@staticmethod
async def null_async(_info) -> None:
"""A resolver returning a null value asynchronously."""
return

async def resolve_friends_async(_obj, _info) -> AsyncGenerator[Friend, None]:
"""A slow async generator yielding the first friend."""
await sleep(0)
yield friends[0]
@staticmethod
async def slow(_info) -> str:
"""Simulate a slow async resolver returning a value."""
await sleep(0)
return "slow"

@staticmethod
def bad(_info) -> str:
"""Simulate a bad resolver raising an error."""
raise RuntimeError("bad")

hero_type = GraphQLObjectType(
"Hero",
{
"id": GraphQLField(GraphQLID),
"name": GraphQLField(GraphQLString),
"slowField": GraphQLField(GraphQLString, resolve=resolve_slow),
"errorField": GraphQLField(GraphQLString, resolve=resolve_bad),
"nonNullErrorField": GraphQLField(
GraphQLNonNull(GraphQLString), resolve=resolve_null_sync
),
"asyncNonNullErrorField": GraphQLField(
GraphQLNonNull(GraphQLString), resolve=resolve_null_async
),
"friends": GraphQLField(
GraphQLList(friend_type), resolve=lambda _obj, _info: friends
),
"asyncFriends": GraphQLField(
GraphQLList(friend_type), resolve=resolve_friends_async
),
},
)

hero = Friend(1, "Luke")

query = GraphQLObjectType(
"Query", {"hero": GraphQLField(hero_type, resolve=lambda _obj, _info: hero)}
)

schema = GraphQLSchema(query)
@staticmethod
async def friends(_info) -> AsyncGenerator[Friend, None]:
"""A slow async generator yielding the first friend."""
await sleep(0)
yield friends[0]


async def complete(document: DocumentNode, root_value: Any = None) -> Any:
result = experimental_execute_incrementally(schema, document, root_value)
result = experimental_execute_incrementally(
schema, document, root_value or {"hero": hero}
)
if is_awaitable(result):
result = await result

Expand Down Expand Up @@ -485,24 +473,24 @@ async def can_defer_fragments_with_errors_on_the_top_level_query_field():
}
fragment QueryFragment on Query {
hero {
errorField
name
}
}
"""
)
result = await complete(document)
result = await complete(document, {"hero": {**hero, "name": Resolvers.bad}})

assert result == [
{"data": {}, "hasNext": True},
{
"incremental": [
{
"data": {"hero": {"errorField": None}},
"data": {"hero": {"name": None}},
"errors": [
{
"message": "bad",
"locations": [{"column": 17, "line": 7}],
"path": ["hero", "errorField"],
"path": ["hero", "name"],
}
],
"path": [],
Expand Down Expand Up @@ -666,24 +654,24 @@ async def handles_errors_thrown_in_deferred_fragments():
}
}
fragment NameFragment on Hero {
errorField
name
}
"""
)
result = await complete(document)
result = await complete(document, {"hero": {**hero, "name": Resolvers.bad}})

assert result == [
{"data": {"hero": {"id": "1"}}, "hasNext": True},
{
"incremental": [
{
"data": {"errorField": None},
"data": {"name": None},
"path": ["hero"],
"errors": [
{
"message": "bad",
"locations": [{"line": 9, "column": 15}],
"path": ["hero", "errorField"],
"path": ["hero", "name"],
}
],
},
Expand All @@ -703,11 +691,13 @@ async def handles_non_nullable_errors_thrown_in_deferred_fragments():
}
}
fragment NameFragment on Hero {
nonNullErrorField
nonNullName
}
"""
)
result = await complete(document)
result = await complete(
document, {"hero": {**hero, "nonNullName": Resolvers.null}}
)

assert result == [
{"data": {"hero": {"id": "1"}}, "hasNext": True},
Expand All @@ -719,9 +709,9 @@ async def handles_non_nullable_errors_thrown_in_deferred_fragments():
"errors": [
{
"message": "Cannot return null for non-nullable field"
" Hero.nonNullErrorField.",
" Hero.nonNullName.",
"locations": [{"line": 9, "column": 15}],
"path": ["hero", "nonNullErrorField"],
"path": ["hero", "nonNullName"],
}
],
},
Expand All @@ -736,7 +726,7 @@ async def handles_non_nullable_errors_thrown_outside_deferred_fragments():
"""
query HeroNameQuery {
hero {
nonNullErrorField
nonNullName
...NameFragment @defer
}
}
Expand All @@ -745,16 +735,18 @@ async def handles_non_nullable_errors_thrown_outside_deferred_fragments():
}
"""
)
result = await complete(document)
result = await complete(
document, {"hero": {**hero, "nonNullName": Resolvers.null}}
)

assert result == {
"data": {"hero": None},
"errors": [
{
"message": "Cannot return null for non-nullable field"
" Hero.nonNullErrorField.",
" Hero.nonNullName.",
"locations": [{"line": 4, "column": 17}],
"path": ["hero", "nonNullErrorField"],
"path": ["hero", "nonNullName"],
}
],
}
Expand All @@ -770,11 +762,13 @@ async def handles_async_non_nullable_errors_thrown_in_deferred_fragments():
}
}
fragment NameFragment on Hero {
asyncNonNullErrorField
nonNullName
}
"""
)
result = await complete(document)
result = await complete(
document, {"hero": {**hero, "nonNullName": Resolvers.null_async}}
)

assert result == [
{"data": {"hero": {"id": "1"}}, "hasNext": True},
Expand All @@ -786,9 +780,9 @@ async def handles_async_non_nullable_errors_thrown_in_deferred_fragments():
"errors": [
{
"message": "Cannot return null for non-nullable field"
" Hero.asyncNonNullErrorField.",
" Hero.nonNullName.",
"locations": [{"line": 9, "column": 15}],
"path": ["hero", "asyncNonNullErrorField"],
"path": ["hero", "nonNullName"],
}
],
},
Expand All @@ -808,7 +802,7 @@ async def returns_payloads_in_correct_order():
}
}
fragment NameFragment on Hero {
slowField
name
friends {
...NestedFragment @defer
}
Expand All @@ -818,14 +812,14 @@ async def returns_payloads_in_correct_order():
}
"""
)
result = await complete(document)
result = await complete(document, {"hero": {**hero, "name": Resolvers.slow}})

assert result == [
{"data": {"hero": {"id": "1"}}, "hasNext": True},
{
"incremental": [
{
"data": {"slowField": "slow", "friends": [{}, {}, {}]},
"data": {"name": "slow", "friends": [{}, {}, {}]},
"path": ["hero"],
}
],
Expand Down Expand Up @@ -909,8 +903,8 @@ async def filters_deferred_payloads_when_list_item_from_async_iterable_nulled():
"""
query {
hero {
asyncFriends {
asyncNonNullErrorField
friends {
nonNullName
...NameFragment @defer
}
}
Expand All @@ -921,16 +915,18 @@ async def filters_deferred_payloads_when_list_item_from_async_iterable_nulled():
"""
)

result = await complete(document)
result = await complete(
document, {"hero": {**hero, "friends": Resolvers.friends}}
)

assert result == {
"data": {"hero": {"asyncFriends": [None]}},
"data": {"hero": {"friends": [None]}},
"errors": [
{
"message": "Cannot return null for non-nullable field"
" Friend.asyncNonNullErrorField.",
" Friend.nonNullName.",
"locations": [{"line": 5, "column": 19}],
"path": ["hero", "asyncFriends", 0, "asyncNonNullErrorField"],
"path": ["hero", "friends", 0, "nonNullName"],
}
],
}
Expand Down Expand Up @@ -958,14 +954,15 @@ async def original_execute_function_throws_error_if_deferred_and_not_all_is_sync
document = parse(
"""
query Deferred {
hero { slowField }
hero { name }
... @defer { hero { id } }
}
"""
)

root_value = {"hero": {**hero, "name": Resolvers.slow}}
with pytest.raises(GraphQLError) as exc_info:
await execute(schema, document, {}) # type: ignore
await execute(schema, document, root_value) # type: ignore

assert str(exc_info.value) == (
"Executing this GraphQL operation would unexpectedly produce"
Expand Down

0 comments on commit a8cffbf

Please sign in to comment.