19724 add the v2 to graphql testing

This commit is contained in:
Arthur
2025-10-21 10:16:16 -07:00
parent 810d1c2418
commit af55da008b
+67 -10
View File
@@ -515,10 +515,15 @@ class APIViewTestCases:
base_name = self.model._meta.verbose_name.lower().replace(' ', '_') base_name = self.model._meta.verbose_name.lower().replace(' ', '_')
return getattr(self, 'graphql_base_name', base_name) return getattr(self, 'graphql_base_name', base_name)
def _build_query_with_filter(self, name, filter_string): def _build_query_with_filter(self, name, filter_string, api_version='v2'):
""" """
Called by either _build_query or _build_filtered_query - construct the actual Called by either _build_query or _build_filtered_query - construct the actual
query given a name and filter string query given a name and filter string
Args:
name: The query field name (e.g., 'device_list')
filter_string: Filter parameters string (e.g., '(filters: {id: "1"})')
api_version: 'v1' or 'v2' to determine response format
""" """
type_class = get_graphql_type_for_model(self.model) type_class = get_graphql_type_for_model(self.model)
@@ -564,7 +569,8 @@ class APIViewTestCases:
# Check if this is a list query (ends with '_list') # Check if this is a list query (ends with '_list')
if name.endswith('_list'): if name.endswith('_list'):
# Wrap fields in 'results' for paginated queries if api_version == 'v2':
# v2: Wrap fields in 'results' for paginated queries
query = f""" query = f"""
{{ {{
{name}{filter_string} {{ {name}{filter_string} {{
@@ -574,6 +580,15 @@ class APIViewTestCases:
}} }}
}} }}
""" """
else:
# v1: Return direct array (no 'results' wrapper)
query = f"""
{{
{name}{filter_string} {{
{fields_string}
}}
}}
"""
else: else:
# Single object query (no pagination) # Single object query (no pagination)
query = f""" query = f"""
@@ -586,9 +601,14 @@ class APIViewTestCases:
return query return query
def _build_filtered_query(self, name, **filters): def _build_filtered_query(self, name, api_version='v2', **filters):
""" """
Create a filtered query: i.e. device_list(filters: {name: {i_contains: "akron"}}){. Create a filtered query: i.e. device_list(filters: {name: {i_contains: "akron"}}){.
Args:
name: The query field name
api_version: 'v1' or 'v2' to determine response format
**filters: Filter parameters
""" """
# TODO: This should be extended to support AND, OR multi-lookups # TODO: This should be extended to support AND, OR multi-lookups
if filters: if filters:
@@ -604,11 +624,16 @@ class APIViewTestCases:
else: else:
filter_string = '' filter_string = ''
return self._build_query_with_filter(name, filter_string) return self._build_query_with_filter(name, filter_string, api_version)
def _build_query(self, name, **filters): def _build_query(self, name, api_version='v2', **filters):
""" """
Create a normal query - unfiltered or with a string query: i.e. site(name: "aaa"){. Create a normal query - unfiltered or with a string query: i.e. site(name: "aaa"){.
Args:
name: The query field name
api_version: 'v1' or 'v2' to determine response format
**filters: Filter parameters
""" """
if filters: if filters:
filter_string = ', '.join(f'{k}:{v}' for k, v in filters.items()) filter_string = ', '.join(f'{k}:{v}' for k, v in filters.items())
@@ -616,7 +641,7 @@ class APIViewTestCases:
else: else:
filter_string = '' filter_string = ''
return self._build_query_with_filter(name, filter_string) return self._build_query_with_filter(name, filter_string, api_version)
@override_settings(LOGIN_REQUIRED=True) @override_settings(LOGIN_REQUIRED=True)
def test_graphql_get_object(self): def test_graphql_get_object(self):
@@ -664,9 +689,13 @@ class APIViewTestCases:
@override_settings(LOGIN_REQUIRED=True) @override_settings(LOGIN_REQUIRED=True)
def test_graphql_list_objects(self): def test_graphql_list_objects(self):
url = reverse('graphql_v2')
field_name = f'{self._get_graphql_base_name()}_list' field_name = f'{self._get_graphql_base_name()}_list'
query = self._build_query(field_name)
# Test both GraphQL API versions
for api_version, url_name in [('v1', 'graphql_v1'), ('v2', 'graphql_v2')]:
with self.subTest(api_version=api_version):
url = reverse(url_name)
query = self._build_query(field_name, api_version=api_version)
# Non-authenticated requests should fail # Non-authenticated requests should fail
header = { header = {
@@ -691,6 +720,12 @@ class APIViewTestCases:
self.assertHttpStatus(response, status.HTTP_200_OK) self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content) data = json.loads(response.content)
self.assertNotIn('errors', data) self.assertNotIn('errors', data)
if api_version == 'v1':
# v1 returns direct array
self.assertEqual(len(data['data'][field_name]), 0)
else:
# v2 returns paginated response with results
self.assertEqual(len(data['data'][field_name]['results']), 0) self.assertEqual(len(data['data'][field_name]['results']), 0)
# Remove permission constraint # Remove permission constraint
@@ -702,16 +737,23 @@ class APIViewTestCases:
self.assertHttpStatus(response, status.HTTP_200_OK) self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content) data = json.loads(response.content)
self.assertNotIn('errors', data) self.assertNotIn('errors', data)
if api_version == 'v1':
# v1 returns direct array
self.assertEqual(len(data['data'][field_name]), self.model.objects.count())
else:
# v2 returns paginated response with results
self.assertEqual(len(data['data'][field_name]['results']), self.model.objects.count()) self.assertEqual(len(data['data'][field_name]['results']), self.model.objects.count())
# Clean up permission for next iteration
obj_perm.delete()
@override_settings(LOGIN_REQUIRED=True) @override_settings(LOGIN_REQUIRED=True)
def test_graphql_filter_objects(self): def test_graphql_filter_objects(self):
if not hasattr(self, 'graphql_filter'): if not hasattr(self, 'graphql_filter'):
return return
url = reverse('graphql_v2')
field_name = f'{self._get_graphql_base_name()}_list' field_name = f'{self._get_graphql_base_name()}_list'
query = self._build_filtered_query(field_name, **self.graphql_filter)
# Add object-level permission # Add object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
@@ -722,12 +764,27 @@ class APIViewTestCases:
obj_perm.users.add(self.user) obj_perm.users.add(self.user)
obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model)) obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model))
# Test both GraphQL API versions
for api_version, url_name in [('v1', 'graphql_v1'), ('v2', 'graphql_v2')]:
with self.subTest(api_version=api_version):
url = reverse(url_name)
query = self._build_filtered_query(field_name, api_version=api_version, **self.graphql_filter)
response = self.client.post(url, data={'query': query}, format="json", **self.header) response = self.client.post(url, data={'query': query}, format="json", **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK) self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content) data = json.loads(response.content)
self.assertNotIn('errors', data) self.assertNotIn('errors', data)
if api_version == 'v1':
# v1 returns direct array
self.assertGreater(len(data['data'][field_name]), 0)
else:
# v2 returns paginated response with results
self.assertGreater(len(data['data'][field_name]['results']), 0) self.assertGreater(len(data['data'][field_name]['results']), 0)
# Clean up permission
obj_perm.delete()
class APIViewTestCase( class APIViewTestCase(
GetObjectViewTestCase, GetObjectViewTestCase,
ListObjectsViewTestCase, ListObjectsViewTestCase,