diff --git a/graphene/types/tests/test_schema.py b/graphene/types/tests/test_schema.py index d3fa774f..54c48b4f 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -1,6 +1,6 @@ from graphql.type import GraphQLObjectType, GraphQLSchema from graphql import GraphQLError -from pytest import raises, fixture +from pytest import mark, raises, fixture from graphene.tests.utils import dedent @@ -74,10 +74,13 @@ def test_schema_requires_query_type(): class TestUnforgivingExecutionContext: @fixture def schema(self): - class MyQuery(ObjectType): + class ErrorFieldsMixin: sanity_field = String() expected_error_field = String() - unexpected_error_field = String() + unexpected_value_error_field = String() + unexpected_type_error_field = String() + unexpected_attribute_error_field = String() + unexpected_key_error_field = String() @staticmethod def resolve_sanity_field(obj, info): @@ -88,9 +91,36 @@ class TestUnforgivingExecutionContext: raise GraphQLError("expected error") @staticmethod - def resolve_unexpected_error_field(obj, info): + def resolve_unexpected_value_error_field(obj, info): raise ValueError("unexpected error") + @staticmethod + def resolve_unexpected_type_error_field(obj, info): + raise TypeError("unexpected error") + + @staticmethod + def resolve_unexpected_attribute_error_field(obj, info): + raise AttributeError("unexpected error") + + @staticmethod + def resolve_unexpected_key_error_field(obj, info): + return {}["fails"] + + class NestedObject(ErrorFieldsMixin, ObjectType): + pass + + class MyQuery(ErrorFieldsMixin, ObjectType): + nested_object = Field(NestedObject) + nested_object_error = Field(NestedObject) + + @staticmethod + def resolve_nested_object(obj, info): + return object() + + @staticmethod + def resolve_nested_object_error(obj, info): + raise TypeError() + schema = Schema(query=MyQuery) return schema @@ -103,6 +133,15 @@ class TestUnforgivingExecutionContext: assert not result.errors assert result.data == {"sanityField": "not an error"} + def test_nested_sanity_check(self, schema): + # this should pass with no errors (sanity check) + result = schema.execute( + r"query { nestedObject { sanityField } }", + execution_context_class=UnforgivingExecutionContext, + ) + assert not result.errors + assert result.data == {"nestedObject": {"sanityField": "not an error"}} + def test_graphql_error(self, schema): result = schema.execute( "query { expectedErrorField }", @@ -112,10 +151,33 @@ class TestUnforgivingExecutionContext: assert result.errors[0].message == "expected error" assert result.data == {"expectedErrorField": None} - def test_unexpected_error(self, schema): - with raises(ValueError): + def test_nested_graphql_error(self, schema): + result = schema.execute( + r"query { nestedObject { expectedErrorField } }", + execution_context_class=UnforgivingExecutionContext, + ) + assert len(result.errors) == 1 + assert result.errors[0].message == "expected error" + assert result.data == {"nestedObject": {"expectedErrorField": None}} + + @mark.parametrize( + "field,exception", + [ + ("unexpectedValueErrorField", ValueError), + ("unexpectedTypeErrorField", TypeError), + ("unexpectedAttributeErrorField", AttributeError), + ("unexpectedKeyErrorField", KeyError), + ("nestedObject { unexpectedValueErrorField }", ValueError), + ("nestedObject { unexpectedTypeErrorField }", TypeError), + ("nestedObject { unexpectedAttributeErrorField }", AttributeError), + ("nestedObject { unexpectedKeyErrorField }", KeyError), + ("nestedObjectError { __typename }", TypeError), + ], + ) + def test_unexpected_error(self, field, exception, schema): + with raises(exception): # no result, but the exception should be propagated schema.execute( - "query { unexpectedErrorField }", + f"query {{ {field} }}", execution_context_class=UnforgivingExecutionContext, )