How to mock info.context in Django / Graphene tests

3.5k views Asked by At

Problem

I'm trying to test a graphql query. The query requires that the user associated with the request (info.context.user) is a super user (.is_superuser). Otherwise it throws an exception. I'm trying to test that the query works properly but am unsure how to ensure that info.context.user.is_superuser resolves to true in the test. Please help!

schema.py

class Query(graphene.ObjectType):
    gardens = graphene.List(GardenType)
    
    def resolve_gardens(self, info):
        user = info.context.user
        if not (user.is_superuser or user.is_staff):
            raise Exception("You must be staff or a superuser to view all gardens")
        return Garden.objects.all()

tests.py

from graphene_django.utils.testing import GraphQLTestCase, graphql_query
from users.models import CustomUser

class TestGraphQLQueries(GraphQLTestCase):
    """
    Test that GraphQL queries related to gardens work and throw errors appropriately
    """

    def test_gardens_query(self):
        response = self.query(
            """
            query {
                gardens {
                    id
                    name
                    owner {
                        id
                        email
                    }
                }
            }
            """
        )

        self.assertResponseNoErrors(response)

Error Thrown


gardens/tests.py:93: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../env/lib/python3.6/site-packages/graphene_django/utils/testing.py:114: in assertResponseNoErrors
    self.assertNotIn("errors", list(content.keys()))
E   AssertionError: 'errors' unexpectedly found in ['errors', 'data']
-------------------------- Captured log call ---------------------------
ERROR    graphql.execution.utils:utils.py:155 Traceback (most recent call last):
  File "/home/dthompson/Code/personal/gardenbuilder-backend/env/lib/python3.6/site-packages/promise/promise.py", line 489, in _resolve_from_executor
    executor(resolve, reject)
  File "/home/dthompson/Code/personal/gardenbuilder-backend/env/lib/python3.6/site-packages/promise/promise.py", line 756, in executor
    return resolve(f(*args, **kwargs))
  File "/home/dthompson/Code/personal/gardenbuilder-backend/env/lib/python3.6/site-packages/graphql/execution/middleware.py", line 75, in make_it_promise
    return next(*args, **kwargs)
  File "/home/dthompson/Code/personal/gardenbuilder-backend/src/gardens/schema.py", line 43, in resolve_gardens
    raise Exception("You must be a superuser to view all gardens")
graphql.error.located_error.GraphQLLocatedError: You must be a superuser to view all gardens
======================= short test summary info ========================
FAILED gardens/tests.py::TestGraphQLQueries::test_gardens_query - Ass...
2

There are 2 answers

0
flying_duck On

You cannot pass in context value directly into self.query method.

What you need to do is create a test client, and then provide the test context value to use for the test.


from graphene.test import Client
from snapshottest import TestCase

from users.models import CustomUser
from .schema import schema

class SuperUser:
    is_superuser = True

class TestContext:
    user = SuperUser()

class TestGraphQLQueries(TestCase):
    """
    Test that GraphQL queries related to gardens work and throw errors appropriately
    """

    context_value = TestContext()

    def test_gardens_query(self):
        client = Client(schema, context_value=self.context_value)
        query = (
            """
            query {
                gardens {
                    id
                    name
                    owner {
                        id
                        email
                    }
                }
            }
            """
        )
        
        self.assertMatchSnapshot(client.execute(query))
0
Mark Chackerian On

You can set a graphene request's user in the same way as setting it for Django, by using RequestFactory. As per my answer in Testing Graphene-Django the pattern is

from django.test import RequestFactory, TestCase
from graphene.test import Client


user = ... (fetch your test superuser)
api_query = """
        query {
            gardens {
                id
                name
                owner {
                    id
                    email
                }
            }
        }
        """
request_factory = RequestFactory()
context_value = request_factory.get('/api/')  # or use reverse() on your API endpoint
context_value.user = user
client = Client(schema)
executed = client.execute(api_query, context_value=context_value)
output_data = executed.get('data')