mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-10-30 23:47:55 +03:00 
			
		
		
		
	fix: run the tests in python 3.12 and 3.13 and remove snapshottest dependency (#1572)
				
					
				
			* actually run the tests in python 3.12 and 3.13 * remove snapshottest from the example tests so that the tests pass in 3.12 and 3.13 again * remove the section about snapshot testing from the testing docs because the snapshottest package doesn't work on Python 3.12 and above * fix assertion for badly formed JSON input on Python 3.13 * fix deprecation warning about datetime.utcfromtimestamp()
This commit is contained in:
		
							parent
							
								
									dc3b2e49c1
								
							
						
					
					
						commit
						48678afba4
					
				|  | @ -69,43 +69,3 @@ You can also add extra keyword arguments to the ``execute`` method, such as | ||||||
|                 'hey': 'hello Peter!' |                 '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 replicating the same response we expect from our GraphQL application can be a |  | ||||||
| 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 lets us write all these tests in a breeze, as it automatically creates the ``snapshots`` for us |  | ||||||
| the first time the test are 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 }''')) |  | ||||||
|  |  | ||||||
|  | @ -1,98 +0,0 @@ | ||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # snapshottest: v1 - https://goo.gl/zC4yUc |  | ||||||
| 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"}} |  | ||||||
| } |  | ||||||
|  | @ -8,19 +8,19 @@ setup() | ||||||
| client = Client(schema) | client = Client(schema) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_hero_name_query(snapshot): | def test_hero_name_query(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query HeroNameQuery { |         query HeroNameQuery { | ||||||
|           hero { |           hero { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == {"data": {"hero": {"name": "R2-D2"}}} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_hero_name_and_friends_query(snapshot): | def test_hero_name_and_friends_query(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query HeroNameAndFriendsQuery { |         query HeroNameAndFriendsQuery { | ||||||
|           hero { |           hero { | ||||||
|             id |             id | ||||||
|  | @ -30,12 +30,24 @@ def test_hero_name_and_friends_query(snapshot): | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": { | ||||||
|  |             "hero": { | ||||||
|  |                 "id": "2001", | ||||||
|  |                 "name": "R2-D2", | ||||||
|  |                 "friends": [ | ||||||
|  |                     {"name": "Luke Skywalker"}, | ||||||
|  |                     {"name": "Han Solo"}, | ||||||
|  |                     {"name": "Leia Organa"}, | ||||||
|  |                 ], | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_nested_query(snapshot): | def test_nested_query(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query NestedQuery { |         query NestedQuery { | ||||||
|           hero { |           hero { | ||||||
|             name |             name | ||||||
|  | @ -48,70 +60,113 @@ def test_nested_query(snapshot): | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "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"}, | ||||||
|  |                         ], | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_fetch_luke_query(snapshot): | def test_fetch_luke_query(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query FetchLukeQuery { |         query FetchLukeQuery { | ||||||
|           human(id: "1000") { |           human(id: "1000") { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |     """) | ||||||
|  |     assert result == {"data": {"human": {"name": "Luke Skywalker"}}} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_fetch_some_id_query(): | ||||||
|  |     result = client.execute( | ||||||
|         """ |         """ | ||||||
|     snapshot.assert_match(client.execute(query)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_fetch_some_id_query(snapshot): |  | ||||||
|     query = """ |  | ||||||
|         query FetchSomeIDQuery($someId: String!) { |         query FetchSomeIDQuery($someId: String!) { | ||||||
|           human(id: $someId) { |           human(id: $someId) { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |     """, | ||||||
|  |         variables={"someId": "1000"}, | ||||||
|  |     ) | ||||||
|  |     assert result == {"data": {"human": {"name": "Luke Skywalker"}}} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_fetch_some_id_query2(): | ||||||
|  |     result = client.execute( | ||||||
|         """ |         """ | ||||||
|     params = {"someId": "1000"} |  | ||||||
|     snapshot.assert_match(client.execute(query, variables=params)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_fetch_some_id_query2(snapshot): |  | ||||||
|     query = """ |  | ||||||
|         query FetchSomeIDQuery($someId: String!) { |         query FetchSomeIDQuery($someId: String!) { | ||||||
|           human(id: $someId) { |           human(id: $someId) { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |     """, | ||||||
|  |         variables={"someId": "1002"}, | ||||||
|  |     ) | ||||||
|  |     assert result == {"data": {"human": {"name": "Han Solo"}}} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_invalid_id_query(): | ||||||
|  |     result = client.execute( | ||||||
|         """ |         """ | ||||||
|     params = {"someId": "1002"} |  | ||||||
|     snapshot.assert_match(client.execute(query, variables=params)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_invalid_id_query(snapshot): |  | ||||||
|     query = """ |  | ||||||
|         query humanQuery($id: String!) { |         query humanQuery($id: String!) { | ||||||
|           human(id: $id) { |           human(id: $id) { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """, | ||||||
|     params = {"id": "not a valid id"} |         variables={"id": "not a valid id"}, | ||||||
|     snapshot.assert_match(client.execute(query, variables=params)) |     ) | ||||||
|  |     assert result == {"data": {"human": None}} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_fetch_luke_aliased(snapshot): | def test_fetch_luke_aliased(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query FetchLukeAliased { |         query FetchLukeAliased { | ||||||
|           luke: human(id: "1000") { |           luke: human(id: "1000") { | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == {"data": {"luke": {"name": "Luke Skywalker"}}} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_fetch_luke_and_leia_aliased(snapshot): | def test_fetch_luke_and_leia_aliased(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query FetchLukeAndLeiaAliased { |         query FetchLukeAndLeiaAliased { | ||||||
|           luke: human(id: "1000") { |           luke: human(id: "1000") { | ||||||
|             name |             name | ||||||
|  | @ -120,12 +175,14 @@ def test_fetch_luke_and_leia_aliased(snapshot): | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": {"luke": {"name": "Luke Skywalker"}, "leia": {"name": "Leia Organa"}} | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_duplicate_fields(snapshot): | def test_duplicate_fields(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query DuplicateFields { |         query DuplicateFields { | ||||||
|           luke: human(id: "1000") { |           luke: human(id: "1000") { | ||||||
|             name |             name | ||||||
|  | @ -136,12 +193,17 @@ def test_duplicate_fields(snapshot): | ||||||
|             homePlanet |             homePlanet | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": { | ||||||
|  |             "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, | ||||||
|  |             "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_use_fragment(snapshot): | def test_use_fragment(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query UseFragment { |         query UseFragment { | ||||||
|           luke: human(id: "1000") { |           luke: human(id: "1000") { | ||||||
|             ...HumanFragment |             ...HumanFragment | ||||||
|  | @ -154,29 +216,36 @@ def test_use_fragment(snapshot): | ||||||
|           name |           name | ||||||
|           homePlanet |           homePlanet | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": { | ||||||
|  |             "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, | ||||||
|  |             "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_check_type_of_r2(snapshot): | def test_check_type_of_r2(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query CheckTypeOfR2 { |         query CheckTypeOfR2 { | ||||||
|           hero { |           hero { | ||||||
|             __typename |             __typename | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == {"data": {"hero": {"__typename": "Droid", "name": "R2-D2"}}} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_check_type_of_luke(snapshot): | def test_check_type_of_luke(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query CheckTypeOfLuke { |         query CheckTypeOfLuke { | ||||||
|           hero(episode: EMPIRE) { |           hero(episode: EMPIRE) { | ||||||
|             __typename |             __typename | ||||||
|             name |             name | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": {"hero": {"__typename": "Human", "name": "Luke Skywalker"}} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | @ -1,24 +0,0 @@ | ||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # snapshottest: v1 - https://goo.gl/zC4yUc |  | ||||||
| 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"}} |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # snapshottest: v1 - https://goo.gl/zC4yUc |  | ||||||
| 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": "Millennium Falcon"}}, |  | ||||||
|                         {"node": {"id": "U2hpcDo1", "name": "Home One"}}, |  | ||||||
|                         {"node": {"id": "U2hpcDo5", "name": "Peter"}}, |  | ||||||
|                     ] |  | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,114 +0,0 @@ | ||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # snapshottest: v1 - https://goo.gl/zC4yUc |  | ||||||
| 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"}} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| snapshots["test_str_schema 1"] = '''type Query { |  | ||||||
|   rebels: Faction |  | ||||||
|   empire: Faction |  | ||||||
|   node( |  | ||||||
|     """The ID of the object""" |  | ||||||
|     id: ID! |  | ||||||
|   ): Node |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| """A faction in the Star Wars saga""" |  | ||||||
| type Faction implements Node { |  | ||||||
|   """The ID of the object""" |  | ||||||
|   id: ID! |  | ||||||
| 
 |  | ||||||
|   """The name of the faction.""" |  | ||||||
|   name: String |  | ||||||
| 
 |  | ||||||
|   """The ships used by the faction.""" |  | ||||||
|   ships(before: String, after: String, first: Int, last: Int): ShipConnection |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| """An object with an ID""" |  | ||||||
| interface Node { |  | ||||||
|   """The ID of the object""" |  | ||||||
|   id: ID! |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type ShipConnection { |  | ||||||
|   """Pagination data for this connection.""" |  | ||||||
|   pageInfo: PageInfo! |  | ||||||
| 
 |  | ||||||
|   """Contains the nodes in this connection.""" |  | ||||||
|   edges: [ShipEdge]! |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| """ |  | ||||||
| The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. |  | ||||||
| """ |  | ||||||
| type PageInfo { |  | ||||||
|   """When paginating forwards, are there more items?""" |  | ||||||
|   hasNextPage: Boolean! |  | ||||||
| 
 |  | ||||||
|   """When paginating backwards, are there more items?""" |  | ||||||
|   hasPreviousPage: Boolean! |  | ||||||
| 
 |  | ||||||
|   """When paginating backwards, the cursor to continue.""" |  | ||||||
|   startCursor: String |  | ||||||
| 
 |  | ||||||
|   """When paginating forwards, the cursor to continue.""" |  | ||||||
|   endCursor: String |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| """A Relay edge containing a `Ship` and its cursor.""" |  | ||||||
| type ShipEdge { |  | ||||||
|   """The item at the end of the edge""" |  | ||||||
|   node: Ship |  | ||||||
| 
 |  | ||||||
|   """A cursor for use in pagination""" |  | ||||||
|   cursor: String! |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| """A ship in the Star Wars saga""" |  | ||||||
| type Ship implements Node { |  | ||||||
|   """The ID of the object""" |  | ||||||
|   id: ID! |  | ||||||
| 
 |  | ||||||
|   """The name of the ship.""" |  | ||||||
|   name: String |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Mutation { |  | ||||||
|   introduceShip(input: IntroduceShipInput!): IntroduceShipPayload |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type IntroduceShipPayload { |  | ||||||
|   ship: Ship |  | ||||||
|   faction: Faction |  | ||||||
|   clientMutationId: String |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| input IntroduceShipInput { |  | ||||||
|   shipName: String! |  | ||||||
|   factionId: String! |  | ||||||
|   clientMutationId: String |  | ||||||
| }''' |  | ||||||
|  | @ -8,8 +8,8 @@ setup() | ||||||
| client = Client(schema) | client = Client(schema) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correct_fetch_first_ship_rebels(snapshot): | def test_correct_fetch_first_ship_rebels(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         query RebelsShipsQuery { |         query RebelsShipsQuery { | ||||||
|           rebels { |           rebels { | ||||||
|             name, |             name, | ||||||
|  | @ -29,5 +29,25 @@ def test_correct_fetch_first_ship_rebels(snapshot): | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "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"}, | ||||||
|  |                         } | ||||||
|  |                     ], | ||||||
|  |                 }, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | @ -8,8 +8,8 @@ setup() | ||||||
| client = Client(schema) | client = Client(schema) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_mutations(snapshot): | def test_mutations(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|         mutation MyMutation { |         mutation MyMutation { | ||||||
|           introduceShip(input:{clientMutationId:"abc", shipName: "Peter", factionId: "1"}) { |           introduceShip(input:{clientMutationId:"abc", shipName: "Peter", factionId: "1"}) { | ||||||
|             ship { |             ship { | ||||||
|  | @ -29,5 +29,24 @@ def test_mutations(snapshot): | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "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": "Millennium Falcon"}}, | ||||||
|  |                             {"node": {"id": "U2hpcDo1", "name": "Home One"}}, | ||||||
|  |                             {"node": {"id": "U2hpcDo5", "name": "Peter"}}, | ||||||
|  |                         ] | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | import textwrap | ||||||
|  | 
 | ||||||
| from graphene.test import Client | from graphene.test import Client | ||||||
| 
 | 
 | ||||||
| from ..data import setup | from ..data import setup | ||||||
|  | @ -8,24 +10,115 @@ setup() | ||||||
| client = Client(schema) | client = Client(schema) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_str_schema(snapshot): | def test_str_schema(): | ||||||
|     snapshot.assert_match(str(schema).strip()) |     assert str(schema).strip() == textwrap.dedent( | ||||||
|  |         '''\ | ||||||
|  |         type Query { | ||||||
|  |           rebels: Faction | ||||||
|  |           empire: Faction | ||||||
|  |           node( | ||||||
|  |             """The ID of the object""" | ||||||
|  |             id: ID! | ||||||
|  |           ): Node | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         """A faction in the Star Wars saga""" | ||||||
|  |         type Faction implements Node { | ||||||
|  |           """The ID of the object""" | ||||||
|  |           id: ID! | ||||||
|  | 
 | ||||||
|  |           """The name of the faction.""" | ||||||
|  |           name: String | ||||||
|  | 
 | ||||||
|  |           """The ships used by the faction.""" | ||||||
|  |           ships(before: String, after: String, first: Int, last: Int): ShipConnection | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         """An object with an ID""" | ||||||
|  |         interface Node { | ||||||
|  |           """The ID of the object""" | ||||||
|  |           id: ID! | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         type ShipConnection { | ||||||
|  |           """Pagination data for this connection.""" | ||||||
|  |           pageInfo: PageInfo! | ||||||
|  | 
 | ||||||
|  |           """Contains the nodes in this connection.""" | ||||||
|  |           edges: [ShipEdge]! | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         """ | ||||||
|  |         The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. | ||||||
|  |         """ | ||||||
|  |         type PageInfo { | ||||||
|  |           """When paginating forwards, are there more items?""" | ||||||
|  |           hasNextPage: Boolean! | ||||||
|  | 
 | ||||||
|  |           """When paginating backwards, are there more items?""" | ||||||
|  |           hasPreviousPage: Boolean! | ||||||
|  | 
 | ||||||
|  |           """When paginating backwards, the cursor to continue.""" | ||||||
|  |           startCursor: String | ||||||
|  | 
 | ||||||
|  |           """When paginating forwards, the cursor to continue.""" | ||||||
|  |           endCursor: String | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         """A Relay edge containing a `Ship` and its cursor.""" | ||||||
|  |         type ShipEdge { | ||||||
|  |           """The item at the end of the edge""" | ||||||
|  |           node: Ship | ||||||
|  | 
 | ||||||
|  |           """A cursor for use in pagination""" | ||||||
|  |           cursor: String! | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         """A ship in the Star Wars saga""" | ||||||
|  |         type Ship implements Node { | ||||||
|  |           """The ID of the object""" | ||||||
|  |           id: ID! | ||||||
|  | 
 | ||||||
|  |           """The name of the ship.""" | ||||||
|  |           name: String | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         type Mutation { | ||||||
|  |           introduceShip(input: IntroduceShipInput!): IntroduceShipPayload | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         type IntroduceShipPayload { | ||||||
|  |           ship: Ship | ||||||
|  |           faction: Faction | ||||||
|  |           clientMutationId: String | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         input IntroduceShipInput { | ||||||
|  |           shipName: String! | ||||||
|  |           factionId: String! | ||||||
|  |           clientMutationId: String | ||||||
|  |         }''' | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correctly_fetches_id_name_rebels(snapshot): | def test_correctly_fetches_id_name_rebels(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|       query RebelsQuery { |       query RebelsQuery { | ||||||
|         rebels { |         rebels { | ||||||
|           id |           id | ||||||
|           name |           name | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": { | ||||||
|  |             "rebels": {"id": "RmFjdGlvbjox", "name": "Alliance to Restore the Republic"} | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correctly_refetches_rebels(snapshot): | def test_correctly_refetches_rebels(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|       query RebelsRefetchQuery { |       query RebelsRefetchQuery { | ||||||
|         node(id: "RmFjdGlvbjox") { |         node(id: "RmFjdGlvbjox") { | ||||||
|           id |           id | ||||||
|  | @ -34,24 +127,30 @@ def test_correctly_refetches_rebels(snapshot): | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": { | ||||||
|  |             "node": {"id": "RmFjdGlvbjox", "name": "Alliance to Restore the Republic"} | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correctly_fetches_id_name_empire(snapshot): | def test_correctly_fetches_id_name_empire(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|       query EmpireQuery { |       query EmpireQuery { | ||||||
|         empire { |         empire { | ||||||
|           id |           id | ||||||
|           name |           name | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": {"empire": {"id": "RmFjdGlvbjoy", "name": "Galactic Empire"}} | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correctly_refetches_empire(snapshot): | def test_correctly_refetches_empire(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|       query EmpireRefetchQuery { |       query EmpireRefetchQuery { | ||||||
|         node(id: "RmFjdGlvbjoy") { |         node(id: "RmFjdGlvbjoy") { | ||||||
|           id |           id | ||||||
|  | @ -60,12 +159,14 @@ def test_correctly_refetches_empire(snapshot): | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == { | ||||||
|  |         "data": {"node": {"id": "RmFjdGlvbjoy", "name": "Galactic Empire"}} | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_correctly_refetches_xwing(snapshot): | def test_correctly_refetches_xwing(): | ||||||
|     query = """ |     result = client.execute(""" | ||||||
|       query XWingRefetchQuery { |       query XWingRefetchQuery { | ||||||
|         node(id: "U2hpcDox") { |         node(id: "U2hpcDox") { | ||||||
|           id |           id | ||||||
|  | @ -74,5 +175,5 @@ def test_correctly_refetches_xwing(snapshot): | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     """ |     """) | ||||||
|     snapshot.assert_match(client.execute(query)) |     assert result == {"data": {"node": {"id": "U2hpcDox", "name": "X-Wing"}}} | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| # https://github.com/graphql-python/graphene/issues/1293 | # https://github.com/graphql-python/graphene/issues/1293 | ||||||
| 
 | 
 | ||||||
| import datetime | from datetime import datetime, timezone | ||||||
| 
 | 
 | ||||||
| import graphene | import graphene | ||||||
| from graphql.utilities import print_schema | from graphql.utilities import print_schema | ||||||
|  | @ -9,11 +9,11 @@ from graphql.utilities import print_schema | ||||||
| class Filters(graphene.InputObjectType): | class Filters(graphene.InputObjectType): | ||||||
|     datetime_after = graphene.DateTime( |     datetime_after = graphene.DateTime( | ||||||
|         required=False, |         required=False, | ||||||
|         default_value=datetime.datetime.utcfromtimestamp(1434549820776 / 1000), |         default_value=datetime.fromtimestamp(1434549820.776, timezone.utc), | ||||||
|     ) |     ) | ||||||
|     datetime_before = graphene.DateTime( |     datetime_before = graphene.DateTime( | ||||||
|         required=False, |         required=False, | ||||||
|         default_value=datetime.datetime.utcfromtimestamp(1444549820776 / 1000), |         default_value=datetime.fromtimestamp(1444549820.776, timezone.utc), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,35 +51,30 @@ def test_jsonstring_invalid_query(): | ||||||
|     Test that if an invalid type is provided we get an error |     Test that if an invalid type is provided we get an error | ||||||
|     """ |     """ | ||||||
|     result = schema.execute("{ json(input: 1) }") |     result = schema.execute("{ json(input: 1) }") | ||||||
|     assert result.errors |     assert result.errors == [ | ||||||
|     assert len(result.errors) == 1 |         {"message": "Expected value of type 'JSONString', found 1."}, | ||||||
|     assert result.errors[0].message == "Expected value of type 'JSONString', found 1." |     ] | ||||||
| 
 | 
 | ||||||
|     result = schema.execute("{ json(input: {}) }") |     result = schema.execute("{ json(input: {}) }") | ||||||
|     assert result.errors |     assert result.errors == [ | ||||||
|     assert len(result.errors) == 1 |         {"message": "Expected value of type 'JSONString', found {}."}, | ||||||
|     assert result.errors[0].message == "Expected value of type 'JSONString', found {}." |     ] | ||||||
| 
 | 
 | ||||||
|     result = schema.execute('{ json(input: "a") }') |     result = schema.execute('{ json(input: "a") }') | ||||||
|     assert result.errors |     assert result.errors == [ | ||||||
|     assert len(result.errors) == 1 |         { | ||||||
|     assert result.errors[0].message == ( |             "message": "Expected value of type 'JSONString', found \"a\"; " | ||||||
|         "Expected value of type 'JSONString', found \"a\"; " |             "Badly formed JSONString: Expecting value: line 1 column 1 (char 0)", | ||||||
|         "Badly formed JSONString: Expecting value: line 1 column 1 (char 0)" |         }, | ||||||
|     ) |     ] | ||||||
| 
 | 
 | ||||||
|     result = schema.execute("""{ json(input: "{\\'key\\': 0}") }""") |     result = schema.execute("""{ json(input: "{\\'key\\': 0}") }""") | ||||||
|     assert result.errors |     assert result.errors == [ | ||||||
|     assert len(result.errors) == 1 |         {"message": "Syntax Error: Invalid character escape sequence: '\\''."}, | ||||||
|     assert ( |     ] | ||||||
|         result.errors[0].message |  | ||||||
|         == "Syntax Error: Invalid character escape sequence: '\\''." |  | ||||||
|     ) |  | ||||||
| 
 | 
 | ||||||
|     result = schema.execute("""{ json(input: "{\\"key\\": 0,}") }""") |     result = schema.execute("""{ json(input: "{\\"key\\": 0,}") }""") | ||||||
|     assert result.errors |  | ||||||
|     assert len(result.errors) == 1 |     assert len(result.errors) == 1 | ||||||
|     assert result.errors[0].message == ( |     assert result.errors[0].message.startswith( | ||||||
|         'Expected value of type \'JSONString\', found "{\\"key\\": 0,}"; ' |         'Expected value of type \'JSONString\', found "{\\"key\\": 0,}"; Badly formed JSONString:' | ||||||
|         "Badly formed JSONString: Expecting property name enclosed in double quotes: line 1 column 11 (char 10)" |  | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -50,7 +50,6 @@ tests_require = [ | ||||||
|     "pytest-cov>=5,<6", |     "pytest-cov>=5,<6", | ||||||
|     "pytest-mock>=3,<4", |     "pytest-mock>=3,<4", | ||||||
|     "pytest-asyncio>=0.16,<2", |     "pytest-asyncio>=0.16,<2", | ||||||
|     "snapshottest>=0.6,<1", |  | ||||||
|     "coveralls>=3.3,<5", |     "coveralls>=3.3,<5", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								tox.ini
									
									
									
									
									
								
							|  | @ -5,10 +5,8 @@ skipsdist = true | ||||||
| [testenv] | [testenv] | ||||||
| deps = | deps = | ||||||
|     .[test] |     .[test] | ||||||
| setenv = |  | ||||||
|      PYTHONPATH = .:{envdir} |  | ||||||
| commands = | commands = | ||||||
|     py{38,39,310,311,12,13}: pytest --cov=graphene graphene --cov-report=term --cov-report=xml examples {posargs} |     pytest --cov=graphene graphene --cov-report=term --cov-report=xml examples {posargs} | ||||||
| 
 | 
 | ||||||
| [testenv:pre-commit] | [testenv:pre-commit] | ||||||
| basepython = python3.10 | basepython = python3.10 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user