mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-11 12:16:58 +03:00
Merge pull request #449 from graphql-python/features/test-client-and-snapshot-testing
First version of the Graphene test client and snapshots 💪
This commit is contained in:
commit
5f71ac7d41
|
@ -10,6 +10,7 @@ Contents:
|
||||||
types/index
|
types/index
|
||||||
execution/index
|
execution/index
|
||||||
relay/index
|
relay/index
|
||||||
|
testing/index
|
||||||
|
|
||||||
Integrations
|
Integrations
|
||||||
-----
|
-----
|
||||||
|
|
111
docs/testing/index.rst
Normal file
111
docs/testing/index.rst
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
===================
|
||||||
|
Testing in Graphene
|
||||||
|
===================
|
||||||
|
|
||||||
|
|
||||||
|
Automated testing is an extremely useful bug-killing tool for the modern developer. You can use a collection of tests – a test suite – to solve, or avoid, a number of problems:
|
||||||
|
|
||||||
|
- When you’re writing new code, you can use tests to validate your code works as expected.
|
||||||
|
- When you’re refactoring or modifying old code, you can use tests to ensure your changes haven’t affected your application’s behavior unexpectedly.
|
||||||
|
|
||||||
|
Testing a GraphQL application is a complex task, because a GraphQL application is made of several layers of logic – schema definition, schema validation, permissions and field resolution.
|
||||||
|
|
||||||
|
With Graphene test-execution framework and assorted utilities, you can simulate GraphQL requests, execute mutations, inspect your application’s output and generally verify your code is doing what it should be doing.
|
||||||
|
|
||||||
|
|
||||||
|
Testing tools
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Graphene provides a small set of tools that come in handy when writing tests.
|
||||||
|
|
||||||
|
|
||||||
|
Test Client
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
The test client is a Python class that acts as a dummy GraphQL client, allowing you to test your views and interact with your Graphene-powered application programmatically.
|
||||||
|
|
||||||
|
Some of the things you can do with the test client are:
|
||||||
|
|
||||||
|
- Simulate Queries and Mutations and observe the response.
|
||||||
|
- Test that a given query request is rendered by a given Django template, with a template context that contains certain values.
|
||||||
|
|
||||||
|
|
||||||
|
Overview and a quick example
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To use the test client, instantiate ``graphene.test.Client`` and retrieve GraphQL responses:
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from graphene.test import Client
|
||||||
|
|
||||||
|
def test_hey():
|
||||||
|
client = Client(my_schema)
|
||||||
|
executed = client.execute('''{ hey }''')
|
||||||
|
assert executed == {
|
||||||
|
'data': {
|
||||||
|
'hey': 'hello!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Execute parameters
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
You can also add extra keyword arguments to the ``execute`` method, such as
|
||||||
|
``context_value``, ``root_value``, ``variable_values``, ...:
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from graphene.test import Client
|
||||||
|
|
||||||
|
def test_hey():
|
||||||
|
client = Client(my_schema)
|
||||||
|
executed = client.execute('''{ hey }''', context_value={'user': 'Peter'})
|
||||||
|
assert executed == {
|
||||||
|
'data': {
|
||||||
|
'hey': 'hello Peter!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Snapshot testing
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
As our APIs evolve, we need to know when our changes introduce any breaking changes that might break
|
||||||
|
some of the clients of our GraphQL app.
|
||||||
|
|
||||||
|
However, writing tests and replicate the same response we expect from our GraphQL application can be
|
||||||
|
tedious and repetitive task, and sometimes it's easier to skip this process.
|
||||||
|
|
||||||
|
Because of that, we recommend the usage of `SnapshotTest <https://github.com/syrusakbary/snapshottest/>`_.
|
||||||
|
|
||||||
|
SnapshotTest let us write all this tests in a breeze, as creates automatically the ``snapshots`` for us
|
||||||
|
the first time the test is executed.
|
||||||
|
|
||||||
|
|
||||||
|
Here is a simple example on how our tests will look if we use ``pytest``:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
def test_hey(snapshot):
|
||||||
|
client = Client(my_schema)
|
||||||
|
# This will create a snapshot dir and a snapshot file
|
||||||
|
# the first time the test is executed, with the response
|
||||||
|
# of the execution.
|
||||||
|
snapshot.assert_match(client.execute('''{ hey }'''))
|
||||||
|
|
||||||
|
|
||||||
|
If we are using ``unittest``:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from snapshottest import TestCase
|
||||||
|
|
||||||
|
class APITestCase(TestCase):
|
||||||
|
def test_api_me(self):
|
||||||
|
"""Testing the API for /me"""
|
||||||
|
client = Client(my_schema)
|
||||||
|
self.assertMatchSnapshot(client.execute('''{ hey }'''))
|
0
examples/starwars/tests/snapshots/__init__.py
Normal file
0
examples/starwars/tests/snapshots/__init__.py
Normal file
202
examples/starwars/tests/snapshots/snap_test_query.py
Normal file
202
examples/starwars/tests/snapshots/snap_test_query.py
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# snapshottest: v1 - https://goo.gl/zC4yUc
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from snapshottest import Snapshot
|
||||||
|
|
||||||
|
|
||||||
|
snapshots = Snapshot()
|
||||||
|
|
||||||
|
snapshots['test_hero_name_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'hero': {
|
||||||
|
'name': 'R2-D2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_hero_name_and_friends_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'hero': {
|
||||||
|
'id': '2001',
|
||||||
|
'name': 'R2-D2',
|
||||||
|
'friends': [
|
||||||
|
{
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Han Solo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Leia Organa'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_nested_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'hero': {
|
||||||
|
'name': 'R2-D2',
|
||||||
|
'friends': [
|
||||||
|
{
|
||||||
|
'name': 'Luke Skywalker',
|
||||||
|
'appearsIn': [
|
||||||
|
'NEWHOPE',
|
||||||
|
'EMPIRE',
|
||||||
|
'JEDI'
|
||||||
|
],
|
||||||
|
'friends': [
|
||||||
|
{
|
||||||
|
'name': 'Han Solo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Leia Organa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'C-3PO'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'R2-D2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Han Solo',
|
||||||
|
'appearsIn': [
|
||||||
|
'NEWHOPE',
|
||||||
|
'EMPIRE',
|
||||||
|
'JEDI'
|
||||||
|
],
|
||||||
|
'friends': [
|
||||||
|
{
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Leia Organa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'R2-D2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Leia Organa',
|
||||||
|
'appearsIn': [
|
||||||
|
'NEWHOPE',
|
||||||
|
'EMPIRE',
|
||||||
|
'JEDI'
|
||||||
|
],
|
||||||
|
'friends': [
|
||||||
|
{
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Han Solo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'C-3PO'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'R2-D2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_fetch_luke_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'human': {
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_fetch_some_id_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'human': {
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_fetch_some_id_query2 1'] = {
|
||||||
|
'data': {
|
||||||
|
'human': {
|
||||||
|
'name': 'Han Solo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_invalid_id_query 1'] = {
|
||||||
|
'data': {
|
||||||
|
'human': None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_fetch_luke_aliased 1'] = {
|
||||||
|
'data': {
|
||||||
|
'luke': {
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_fetch_luke_and_leia_aliased 1'] = {
|
||||||
|
'data': {
|
||||||
|
'luke': {
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
},
|
||||||
|
'leia': {
|
||||||
|
'name': 'Leia Organa'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_duplicate_fields 1'] = {
|
||||||
|
'data': {
|
||||||
|
'luke': {
|
||||||
|
'name': 'Luke Skywalker',
|
||||||
|
'homePlanet': 'Tatooine'
|
||||||
|
},
|
||||||
|
'leia': {
|
||||||
|
'name': 'Leia Organa',
|
||||||
|
'homePlanet': 'Alderaan'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_use_fragment 1'] = {
|
||||||
|
'data': {
|
||||||
|
'luke': {
|
||||||
|
'name': 'Luke Skywalker',
|
||||||
|
'homePlanet': 'Tatooine'
|
||||||
|
},
|
||||||
|
'leia': {
|
||||||
|
'name': 'Leia Organa',
|
||||||
|
'homePlanet': 'Alderaan'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_check_type_of_r2 1'] = {
|
||||||
|
'data': {
|
||||||
|
'hero': {
|
||||||
|
'__typename': 'Droid',
|
||||||
|
'name': 'R2-D2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_check_type_of_luke 1'] = {
|
||||||
|
'data': {
|
||||||
|
'hero': {
|
||||||
|
'__typename': 'Human',
|
||||||
|
'name': 'Luke Skywalker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
|
from graphene.test import Client
|
||||||
from ..data import setup
|
from ..data import setup
|
||||||
from ..schema import schema
|
from ..schema import schema
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
|
client = Client(schema)
|
||||||
|
|
||||||
def test_hero_name_query():
|
def test_hero_name_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query HeroNameQuery {
|
query HeroNameQuery {
|
||||||
hero {
|
hero {
|
||||||
|
@ -13,17 +14,11 @@ def test_hero_name_query():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'hero': {
|
|
||||||
'name': 'R2-D2'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_hero_name_and_friends_query():
|
|
||||||
|
def test_hero_name_and_friends_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query HeroNameAndFriendsQuery {
|
query HeroNameAndFriendsQuery {
|
||||||
hero {
|
hero {
|
||||||
|
@ -35,23 +30,10 @@ def test_hero_name_and_friends_query():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'hero': {
|
|
||||||
'id': '2001',
|
|
||||||
'name': 'R2-D2',
|
|
||||||
'friends': [
|
|
||||||
{'name': 'Luke Skywalker'},
|
|
||||||
{'name': 'Han Solo'},
|
|
||||||
{'name': 'Leia Organa'},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_nested_query():
|
def test_nested_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query NestedQuery {
|
query NestedQuery {
|
||||||
hero {
|
hero {
|
||||||
|
@ -66,70 +48,10 @@ def test_nested_query():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'hero': {
|
|
||||||
'name': 'R2-D2',
|
|
||||||
'friends': [
|
|
||||||
{
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
|
||||||
'friends': [
|
|
||||||
{
|
|
||||||
'name': 'Han Solo',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'C-3PO',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'R2-D2',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Han Solo',
|
|
||||||
'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
|
||||||
'friends': [
|
|
||||||
{
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'R2-D2',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
|
||||||
'friends': [
|
|
||||||
{
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Han Solo',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'C-3PO',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'R2-D2',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_luke_query():
|
def test_fetch_luke_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query FetchLukeQuery {
|
query FetchLukeQuery {
|
||||||
human(id: "1000") {
|
human(id: "1000") {
|
||||||
|
@ -137,17 +59,10 @@ def test_fetch_luke_query():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'human': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_some_id_query():
|
def test_fetch_some_id_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query FetchSomeIDQuery($someId: String!) {
|
query FetchSomeIDQuery($someId: String!) {
|
||||||
human(id: $someId) {
|
human(id: $someId) {
|
||||||
|
@ -158,17 +73,10 @@ def test_fetch_some_id_query():
|
||||||
params = {
|
params = {
|
||||||
'someId': '1000',
|
'someId': '1000',
|
||||||
}
|
}
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query, variable_values=params))
|
||||||
'human': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query, None, variable_values=params)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_some_id_query2():
|
def test_fetch_some_id_query2(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query FetchSomeIDQuery($someId: String!) {
|
query FetchSomeIDQuery($someId: String!) {
|
||||||
human(id: $someId) {
|
human(id: $someId) {
|
||||||
|
@ -179,17 +87,10 @@ def test_fetch_some_id_query2():
|
||||||
params = {
|
params = {
|
||||||
'someId': '1002',
|
'someId': '1002',
|
||||||
}
|
}
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query, variable_values=params))
|
||||||
'human': {
|
|
||||||
'name': 'Han Solo',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query, None, variable_values=params)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_id_query():
|
def test_invalid_id_query(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query humanQuery($id: String!) {
|
query humanQuery($id: String!) {
|
||||||
human(id: $id) {
|
human(id: $id) {
|
||||||
|
@ -200,15 +101,10 @@ def test_invalid_id_query():
|
||||||
params = {
|
params = {
|
||||||
'id': 'not a valid id',
|
'id': 'not a valid id',
|
||||||
}
|
}
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query, variable_values=params))
|
||||||
'human': None
|
|
||||||
}
|
|
||||||
result = schema.execute(query, None, variable_values=params)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_luke_aliased():
|
def test_fetch_luke_aliased(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query FetchLukeAliased {
|
query FetchLukeAliased {
|
||||||
luke: human(id: "1000") {
|
luke: human(id: "1000") {
|
||||||
|
@ -216,17 +112,10 @@ def test_fetch_luke_aliased():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'luke': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_luke_and_leia_aliased():
|
def test_fetch_luke_and_leia_aliased(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query FetchLukeAndLeiaAliased {
|
query FetchLukeAndLeiaAliased {
|
||||||
luke: human(id: "1000") {
|
luke: human(id: "1000") {
|
||||||
|
@ -237,20 +126,10 @@ def test_fetch_luke_and_leia_aliased():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'luke': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
},
|
|
||||||
'leia': {
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_duplicate_fields():
|
def test_duplicate_fields(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query DuplicateFields {
|
query DuplicateFields {
|
||||||
luke: human(id: "1000") {
|
luke: human(id: "1000") {
|
||||||
|
@ -263,22 +142,10 @@ def test_duplicate_fields():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'luke': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
'homePlanet': 'Tatooine',
|
|
||||||
},
|
|
||||||
'leia': {
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
'homePlanet': 'Alderaan',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_use_fragment():
|
def test_use_fragment(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query UseFragment {
|
query UseFragment {
|
||||||
luke: human(id: "1000") {
|
luke: human(id: "1000") {
|
||||||
|
@ -293,22 +160,10 @@ def test_use_fragment():
|
||||||
homePlanet
|
homePlanet
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'luke': {
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
'homePlanet': 'Tatooine',
|
|
||||||
},
|
|
||||||
'leia': {
|
|
||||||
'name': 'Leia Organa',
|
|
||||||
'homePlanet': 'Alderaan',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_check_type_of_r2():
|
def test_check_type_of_r2(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query CheckTypeOfR2 {
|
query CheckTypeOfR2 {
|
||||||
hero {
|
hero {
|
||||||
|
@ -317,18 +172,10 @@ def test_check_type_of_r2():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'hero': {
|
|
||||||
'__typename': 'Droid',
|
|
||||||
'name': 'R2-D2',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_check_type_of_luke():
|
def test_check_type_of_luke(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query CheckTypeOfLuke {
|
query CheckTypeOfLuke {
|
||||||
hero(episode: EMPIRE) {
|
hero(episode: EMPIRE) {
|
||||||
|
@ -337,12 +184,4 @@ def test_check_type_of_luke():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'hero': {
|
|
||||||
'__typename': 'Human',
|
|
||||||
'name': 'Luke Skywalker',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
0
examples/starwars_relay/tests/snapshots/__init__.py
Normal file
0
examples/starwars_relay/tests/snapshots/__init__.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# snapshottest: v1 - https://goo.gl/zC4yUc
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from snapshottest import Snapshot
|
||||||
|
|
||||||
|
|
||||||
|
snapshots = Snapshot()
|
||||||
|
|
||||||
|
snapshots['test_correct_fetch_first_ship_rebels 1'] = {
|
||||||
|
'data': {
|
||||||
|
'rebels': {
|
||||||
|
'name': 'Alliance to Restore the Republic',
|
||||||
|
'ships': {
|
||||||
|
'pageInfo': {
|
||||||
|
'startCursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
||||||
|
'endCursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
||||||
|
'hasNextPage': True,
|
||||||
|
'hasPreviousPage': False
|
||||||
|
},
|
||||||
|
'edges': [
|
||||||
|
{
|
||||||
|
'cursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
||||||
|
'node': {
|
||||||
|
'name': 'X-Wing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# snapshottest: v1 - https://goo.gl/zC4yUc
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from snapshottest import Snapshot
|
||||||
|
|
||||||
|
|
||||||
|
snapshots = Snapshot()
|
||||||
|
|
||||||
|
snapshots['test_mutations 1'] = {
|
||||||
|
'data': {
|
||||||
|
'introduceShip': {
|
||||||
|
'ship': {
|
||||||
|
'id': 'U2hpcDo5',
|
||||||
|
'name': 'Peter'
|
||||||
|
},
|
||||||
|
'faction': {
|
||||||
|
'name': 'Alliance to Restore the Republic',
|
||||||
|
'ships': {
|
||||||
|
'edges': [
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDox',
|
||||||
|
'name': 'X-Wing'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDoy',
|
||||||
|
'name': 'Y-Wing'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDoz',
|
||||||
|
'name': 'A-Wing'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDo0',
|
||||||
|
'name': 'Millenium Falcon'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDo1',
|
||||||
|
'name': 'Home One'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDo5',
|
||||||
|
'name': 'Peter'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# snapshottest: v1 - https://goo.gl/zC4yUc
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from snapshottest import Snapshot
|
||||||
|
|
||||||
|
|
||||||
|
snapshots = Snapshot()
|
||||||
|
|
||||||
|
snapshots['test_correctly_fetches_id_name_rebels 1'] = {
|
||||||
|
'data': {
|
||||||
|
'rebels': {
|
||||||
|
'id': 'RmFjdGlvbjox',
|
||||||
|
'name': 'Alliance to Restore the Republic'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_correctly_refetches_rebels 1'] = {
|
||||||
|
'data': {
|
||||||
|
'node': {
|
||||||
|
'id': 'RmFjdGlvbjox',
|
||||||
|
'name': 'Alliance to Restore the Republic'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_correctly_fetches_id_name_empire 1'] = {
|
||||||
|
'data': {
|
||||||
|
'empire': {
|
||||||
|
'id': 'RmFjdGlvbjoy',
|
||||||
|
'name': 'Galactic Empire'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_correctly_refetches_empire 1'] = {
|
||||||
|
'data': {
|
||||||
|
'node': {
|
||||||
|
'id': 'RmFjdGlvbjoy',
|
||||||
|
'name': 'Galactic Empire'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshots['test_correctly_refetches_xwing 1'] = {
|
||||||
|
'data': {
|
||||||
|
'node': {
|
||||||
|
'id': 'U2hpcDox',
|
||||||
|
'name': 'X-Wing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,13 @@
|
||||||
|
from graphene.test import Client
|
||||||
from ..data import setup
|
from ..data import setup
|
||||||
from ..schema import schema
|
from ..schema import schema
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
|
client = Client(schema)
|
||||||
|
|
||||||
def test_correct_fetch_first_ship_rebels():
|
|
||||||
|
def test_correct_fetch_first_ship_rebels(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query RebelsShipsQuery {
|
query RebelsShipsQuery {
|
||||||
rebels {
|
rebels {
|
||||||
|
@ -26,27 +29,4 @@ def test_correct_fetch_first_ship_rebels():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'rebels': {
|
|
||||||
'name': 'Alliance to Restore the Republic',
|
|
||||||
'ships': {
|
|
||||||
'pageInfo': {
|
|
||||||
'startCursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
|
||||||
'endCursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
|
||||||
'hasNextPage': True,
|
|
||||||
'hasPreviousPage': False
|
|
||||||
},
|
|
||||||
'edges': [
|
|
||||||
{
|
|
||||||
'cursor': 'YXJyYXljb25uZWN0aW9uOjA=',
|
|
||||||
'node': {
|
|
||||||
'name': 'X-Wing'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
from graphene.test import Client
|
||||||
from ..data import setup
|
from ..data import setup
|
||||||
from ..schema import schema
|
from ..schema import schema
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
|
client = Client(schema)
|
||||||
|
|
||||||
def test_mutations():
|
|
||||||
|
def test_mutations(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
mutation MyMutation {
|
mutation MyMutation {
|
||||||
introduceShip(input:{clientMutationId:"abc", shipName: "Peter", factionId: "1"}) {
|
introduceShip(input:{clientMutationId:"abc", shipName: "Peter", factionId: "1"}) {
|
||||||
|
@ -26,51 +29,4 @@ def test_mutations():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'introduceShip': {
|
|
||||||
'ship': {
|
|
||||||
'id': 'U2hpcDo5',
|
|
||||||
'name': 'Peter'
|
|
||||||
},
|
|
||||||
'faction': {
|
|
||||||
'name': 'Alliance to Restore the Republic',
|
|
||||||
'ships': {
|
|
||||||
'edges': [{
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDox',
|
|
||||||
'name': 'X-Wing'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDoy',
|
|
||||||
'name': 'Y-Wing'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDoz',
|
|
||||||
'name': 'A-Wing'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDo0',
|
|
||||||
'name': 'Millenium Falcon'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDo1',
|
|
||||||
'name': 'Home One'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDo5',
|
|
||||||
'name': 'Peter'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
# raise result.errors[0].original_error, None, result.errors[0].stack
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
from graphene.test import Client
|
||||||
from ..data import setup
|
from ..data import setup
|
||||||
from ..schema import schema
|
from ..schema import schema
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
|
client = Client(schema)
|
||||||
|
|
||||||
|
|
||||||
def test_str_schema():
|
def test_str_schema():
|
||||||
assert str(schema) == '''schema {
|
assert str(schema) == '''schema {
|
||||||
|
@ -66,7 +69,7 @@ type ShipEdge {
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def test_correctly_fetches_id_name_rebels():
|
def test_correctly_fetches_id_name_rebels(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query RebelsQuery {
|
query RebelsQuery {
|
||||||
rebels {
|
rebels {
|
||||||
|
@ -75,18 +78,10 @@ def test_correctly_fetches_id_name_rebels():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'rebels': {
|
|
||||||
'id': 'RmFjdGlvbjox',
|
|
||||||
'name': 'Alliance to Restore the Republic'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_correctly_refetches_rebels():
|
def test_correctly_refetches_rebels(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query RebelsRefetchQuery {
|
query RebelsRefetchQuery {
|
||||||
node(id: "RmFjdGlvbjox") {
|
node(id: "RmFjdGlvbjox") {
|
||||||
|
@ -97,18 +92,10 @@ def test_correctly_refetches_rebels():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'node': {
|
|
||||||
'id': 'RmFjdGlvbjox',
|
|
||||||
'name': 'Alliance to Restore the Republic'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_correctly_fetches_id_name_empire():
|
def test_correctly_fetches_id_name_empire(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query EmpireQuery {
|
query EmpireQuery {
|
||||||
empire {
|
empire {
|
||||||
|
@ -117,18 +104,10 @@ def test_correctly_fetches_id_name_empire():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'empire': {
|
|
||||||
'id': 'RmFjdGlvbjoy',
|
|
||||||
'name': 'Galactic Empire'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_correctly_refetches_empire():
|
def test_correctly_refetches_empire(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query EmpireRefetchQuery {
|
query EmpireRefetchQuery {
|
||||||
node(id: "RmFjdGlvbjoy") {
|
node(id: "RmFjdGlvbjoy") {
|
||||||
|
@ -139,18 +118,10 @@ def test_correctly_refetches_empire():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'node': {
|
|
||||||
'id': 'RmFjdGlvbjoy',
|
|
||||||
'name': 'Galactic Empire'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_correctly_refetches_xwing():
|
def test_correctly_refetches_xwing(snapshot):
|
||||||
query = '''
|
query = '''
|
||||||
query XWingRefetchQuery {
|
query XWingRefetchQuery {
|
||||||
node(id: "U2hpcDox") {
|
node(id: "U2hpcDox") {
|
||||||
|
@ -161,12 +132,4 @@ def test_correctly_refetches_xwing():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
expected = {
|
snapshot.assert_match(client.execute(query))
|
||||||
'node': {
|
|
||||||
'id': 'U2hpcDox',
|
|
||||||
'name': 'X-Wing'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = schema.execute(query)
|
|
||||||
assert not result.errors
|
|
||||||
assert result.data == expected
|
|
||||||
|
|
39
graphene/test/__init__.py
Normal file
39
graphene/test/__init__.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import six
|
||||||
|
from graphql.error import format_error as format_graphql_error
|
||||||
|
from graphql.error import GraphQLError
|
||||||
|
|
||||||
|
from graphene.types.schema import Schema
|
||||||
|
|
||||||
|
|
||||||
|
def default_format_error(error):
|
||||||
|
if isinstance(error, GraphQLError):
|
||||||
|
return format_graphql_error(error)
|
||||||
|
|
||||||
|
return {'message': six.text_type(error)}
|
||||||
|
|
||||||
|
|
||||||
|
def format_execution_result(execution_result, format_error):
|
||||||
|
if execution_result:
|
||||||
|
response = {}
|
||||||
|
|
||||||
|
if execution_result.errors:
|
||||||
|
response['errors'] = [format_error(e) for e in execution_result.errors]
|
||||||
|
|
||||||
|
if not execution_result.invalid:
|
||||||
|
response['data'] = execution_result.data
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class Client(object):
|
||||||
|
def __init__(self, schema, format_error=None, **execute_options):
|
||||||
|
assert isinstance(schema, Schema)
|
||||||
|
self.schema = schema
|
||||||
|
self.execute_options = execute_options
|
||||||
|
self.format_error = format_error or default_format_error
|
||||||
|
|
||||||
|
def execute(self, *args, **kwargs):
|
||||||
|
return format_execution_result(
|
||||||
|
self.schema.execute(*args, **dict(self.execute_options, **kwargs)),
|
||||||
|
self.format_error
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user