From 2847721584daf69a52d13b62de6e0a6449096082 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 23 Apr 2024 09:18:48 -0500 Subject: [PATCH] update tests to reflect pagination and API changes --- cookbook/serializer.py | 20 ++- cookbook/tests/api/test_api_meal_plan.py | 2 +- cookbook/tests/api/test_api_plan_ical.py | 1 + cookbook/tests/api/test_api_property.py | 56 +++--- cookbook/tests/api/test_api_property_type.py | 8 +- cookbook/tests/api/test_api_recipe.py | 26 +-- cookbook/tests/api/test_api_recipe_book.py | 65 +++---- .../tests/api/test_api_recipe_book_entry.py | 8 +- .../api/test_api_shopping_list_entryv2.py | 167 ++++++++---------- .../tests/api/test_api_shopping_recipe.py | 78 ++++---- cookbook/tests/api/test_api_space.py | 30 +--- cookbook/tests/api/test_api_supermarket.py | 16 +- cookbook/tests/api/test_api_sync.py | 74 ++++---- .../tests/api/test_api_unit_conversion.py | 118 ++++++------- cookbook/tests/other/test_makenow_filter.py | 14 +- cookbook/tests/other/test_schemas.py | 32 ++-- cookbook/urls.py | 3 +- cookbook/views/api.py | 45 ++--- 18 files changed, 357 insertions(+), 406 deletions(-) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index dcd60e143..67a2562ee 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -172,18 +172,20 @@ class SpaceFilterSerializer(serializers.ListSerializer): if self.context.get('request', None) is None: return - # Don't return User details to anonymous users - if self.child.Meta.model == User and isinstance(self.context['request'].user, AnonymousUser): - data = [] - - # paginated data is provided as a list, otherwise as a Queryset - if isinstance(data, QuerySet): + if (isinstance(data, QuerySet) and data.query.is_sliced): # if query is sliced it came from api request not nested serializer - if data.query.is_sliced: - return super().to_representation(data) - data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all() + return super().to_representation(data) + + if self.child.Meta.model == User: + # Don't return User details to anonymous users + if isinstance(self.context['request'].user, AnonymousUser): + data = [] + else: + data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all() elif isinstance(data, list): data = [d for d in data if getattr(d, self.child.Meta.model.get_space_key()[0]) == self.context['request'].space] + else: + data = data.filter(**{'__'.join(self.child.Meta.model.get_space_key()): self.context['request'].space}) return super().to_representation(data) diff --git a/cookbook/tests/api/test_api_meal_plan.py b/cookbook/tests/api/test_api_meal_plan.py index be55335a4..f59369b8b 100644 --- a/cookbook/tests/api/test_api_meal_plan.py +++ b/cookbook/tests/api/test_api_meal_plan.py @@ -211,7 +211,7 @@ def test_add_with_shopping(u1_s1, meal_type): @pytest.mark.parametrize("arg", [ - [f'', 2], + ['', 2], [f'?from_date={datetime.now().strftime("%Y-%m-%d")}', 1], [ f'?to_date={(datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")}', diff --git a/cookbook/tests/api/test_api_plan_ical.py b/cookbook/tests/api/test_api_plan_ical.py index 305ff0594..ff86861c6 100644 --- a/cookbook/tests/api/test_api_plan_ical.py +++ b/cookbook/tests/api/test_api_plan_ical.py @@ -44,6 +44,7 @@ def test_permissions(arg, request): to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d") assert c.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug})).status_code == arg[1] + def test_bound(obj_1, obj_2, obj_3, u1_s1): from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d") to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d") diff --git a/cookbook/tests/api/test_api_property.py b/cookbook/tests/api/test_api_property.py index 5b38e91e8..d96c6d088 100644 --- a/cookbook/tests/api/test_api_property.py +++ b/cookbook/tests/api/test_api_property.py @@ -13,13 +13,17 @@ DETAIL_URL = 'api:property-detail' @pytest.fixture() def obj_1(space_1, u1_s1): pt = PropertyType.objects.get_or_create(name='test_1', space=space_1)[0] - return Property.objects.get_or_create(property_amount=100, property_type=pt, space=space_1)[0] + return Property.objects.get_or_create(property_amount=100, + property_type=pt, + space=space_1)[0] @pytest.fixture def obj_2(space_1, u1_s1): pt = PropertyType.objects.get_or_create(name='test_2', space=space_1)[0] - return Property.objects.get_or_create(property_amount=100, property_type=pt, space=space_1)[0] + return Property.objects.get_or_create(property_amount=100, + property_type=pt, + space=space_1)[0] @pytest.mark.parametrize("arg", [ @@ -34,14 +38,14 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 1 @pytest.mark.parametrize("arg", [ @@ -55,14 +59,8 @@ def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): ]) def test_update(arg, request, obj_1): c = request.getfixturevalue(arg[0]) - r = c.patch( - reverse( - DETAIL_URL, - args={obj_1.id} - ), - {'property_amount': 200}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={obj_1.id}), {'property_amount': 200}, + content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 200: @@ -77,13 +75,17 @@ def test_update(arg, request, obj_1): ]) def test_add(arg, request, u1_s2, space_1): with scopes_disabled(): - pt = PropertyType.objects.get_or_create(name='test_1', space=space_1)[0] + pt = PropertyType.objects.get_or_create(name='test_1', + space=space_1)[0] c = request.getfixturevalue(arg[0]) - r = c.post( - reverse(LIST_URL), - {'property_amount': 100, 'property_type': {'id': pt.id, 'name': pt.name}}, - content_type='application/json' - ) + r = c.post(reverse(LIST_URL), { + 'property_amount': 100, + 'property_type': { + 'id': pt.id, + 'name': pt.name + } + }, + content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 201: @@ -95,20 +97,10 @@ def test_add(arg, request, u1_s2, space_1): def test_delete(u1_s1, u1_s2, obj_1): - r = u1_s2.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 - r = u1_s1.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s1.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 204 with scopes_disabled(): diff --git a/cookbook/tests/api/test_api_property_type.py b/cookbook/tests/api/test_api_property_type.py index 7ecd41c91..a6e74c5e3 100644 --- a/cookbook/tests/api/test_api_property_type.py +++ b/cookbook/tests/api/test_api_property_type.py @@ -32,14 +32,14 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 1 @pytest.mark.parametrize("arg", [ diff --git a/cookbook/tests/api/test_api_recipe.py b/cookbook/tests/api/test_api_recipe.py index 62b77ba1a..ef9103356 100644 --- a/cookbook/tests/api/test_api_recipe.py +++ b/cookbook/tests/api/test_api_recipe.py @@ -107,19 +107,19 @@ def test_update(arg, request, recipe_1_s1): def test_update_share(u1_s1, u2_s1, u1_s2, recipe_1_s1): - with scopes_disabled(): - r = u1_s1.patch( - reverse( - DETAIL_URL, - args={recipe_1_s1.id} - ), - {'shared': [{'id': auth.get_user(u1_s2).pk, 'username': auth.get_user(u1_s2).username}, {'id': auth.get_user(u2_s1).pk, 'username': auth.get_user(u2_s1).username}]}, - content_type='application/json' - ) - response = json.loads(r.content) - assert r.status_code == 200 - assert len(response['shared']) == 1 - assert response['shared'][0]['id'] == auth.get_user(u2_s1).pk + # with scopes_disabled(): + r = u1_s1.patch( + reverse( + DETAIL_URL, + args={recipe_1_s1.id} + ), + {'shared': [{'id': auth.get_user(u1_s2).pk, 'username': auth.get_user(u1_s2).username}, {'id': auth.get_user(u2_s1).pk, 'username': auth.get_user(u2_s1).username}]}, + content_type='application/json' + ) + response = json.loads(r.content) + assert r.status_code == 200 + assert len(response['shared']) == 1 + assert response['shared'][0]['id'] == auth.get_user(u2_s1).pk def test_update_private_recipe(u1_s1, u2_s1, recipe_1_s1): diff --git a/cookbook/tests/api/test_api_recipe_book.py b/cookbook/tests/api/test_api_recipe_book.py index 4455791ca..067cfdd15 100644 --- a/cookbook/tests/api/test_api_recipe_book.py +++ b/cookbook/tests/api/test_api_recipe_book.py @@ -13,12 +13,16 @@ DETAIL_URL = 'api:recipebook-detail' @pytest.fixture() def obj_1(space_1, u1_s1): - return RecipeBook.objects.get_or_create(name='test_1', created_by=auth.get_user(u1_s1), space=space_1)[0] + return RecipeBook.objects.get_or_create(name='test_1', + created_by=auth.get_user(u1_s1), + space=space_1)[0] @pytest.fixture def obj_2(space_1, u1_s1): - return RecipeBook.objects.get_or_create(name='test_2', created_by=auth.get_user(u1_s1), space=space_1)[0] + return RecipeBook.objects.get_or_create(name='test_2', + created_by=auth.get_user(u1_s1), + space=space_1)[0] @pytest.mark.parametrize("arg", [ @@ -33,31 +37,33 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 def test_list_filter(obj_1, obj_2, u1_s1): r = u1_s1.get(reverse(LIST_URL)) assert r.status_code == 200 response = json.loads(r.content) - assert len(response) == 2 + assert response['count'] == 2 response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?limit=1').content) - assert len(response) == 1 + assert response['count'] == 1 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content) - assert len(response) == 0 + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content) + assert response['count'] == 0 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[4:]}').content) - assert len(response) == 1 - assert response[0]['name'] == obj_1.name + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[4:]}').content) + assert response['count'] == 1 + assert response['results'][0]['name'] == obj_1.name @pytest.mark.parametrize("arg", [ @@ -71,14 +77,7 @@ def test_list_filter(obj_1, obj_2, u1_s1): ]) def test_update(arg, request, obj_1): c = request.getfixturevalue(arg[0]) - r = c.patch( - reverse( - DETAIL_URL, - args={obj_1.id} - ), - {'name': 'new'}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={obj_1.id}), {'name': 'new'}, content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 200: @@ -93,11 +92,11 @@ def test_update(arg, request, obj_1): ]) def test_add(arg, request, u1_s2): c = request.getfixturevalue(arg[0]) - r = c.post( - reverse(LIST_URL), - {'name': 'test', 'shared': []}, - content_type='application/json' - ) + r = c.post(reverse(LIST_URL), { + 'name': 'test', + 'shared': [] + }, + content_type='application/json') response = json.loads(r.content) print(r.content) assert r.status_code == arg[1] @@ -110,20 +109,10 @@ def test_add(arg, request, u1_s2): def test_delete(u1_s1, u1_s2, obj_1): - r = u1_s2.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 - r = u1_s1.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s1.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 204 with scopes_disabled(): diff --git a/cookbook/tests/api/test_api_recipe_book_entry.py b/cookbook/tests/api/test_api_recipe_book_entry.py index 11d1523ea..e3df1588c 100644 --- a/cookbook/tests/api/test_api_recipe_book_entry.py +++ b/cookbook/tests/api/test_api_recipe_book_entry.py @@ -36,14 +36,14 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.book.space = space_2 obj_1.book.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 @pytest.mark.parametrize("arg", [ diff --git a/cookbook/tests/api/test_api_shopping_list_entryv2.py b/cookbook/tests/api/test_api_shopping_list_entryv2.py index 72c3c9435..e6eaca252 100644 --- a/cookbook/tests/api/test_api_shopping_list_entryv2.py +++ b/cookbook/tests/api/test_api_shopping_list_entryv2.py @@ -17,7 +17,9 @@ DETAIL_URL = 'api:shoppinglistentry-detail' @pytest.fixture def sle(space_1, u1_s1): user = auth.get_user(u1_s1) - return ShoppingListEntryFactory.create_batch(10, space=space_1, created_by=user) + return ShoppingListEntryFactory.create_batch(10, + space=space_1, + created_by=user) @pytest.fixture @@ -29,10 +31,13 @@ def sle_2(request): u = request.getfixturevalue(params.get('user', 'u1_s1')) user = auth.get_user(u) count = params.get('count', 10) - return ShoppingListEntryFactory.create_batch(count, space=user.userspace_set.filter(active=1).first().space, created_by=user) + return ShoppingListEntryFactory.create_batch( + count, + space=user.userspace_set.filter(active=1).first().space, + created_by=user) -@ pytest.mark.parametrize("arg", [ +@pytest.mark.parametrize("arg", [ ['a_u', 403], ['g1_s1', 200], ['u1_s1', 200], @@ -44,27 +49,24 @@ def test_list_permission(arg, request): def test_list_space(sle, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 10 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 10 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 with scopes_disabled(): e = ShoppingListEntry.objects.first() e.space = space_2 e.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 9 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 9 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 def test_get_detail(u1_s1, sle): - r = u1_s1.get(reverse( - DETAIL_URL, - args={sle[0].id} - )) + r = u1_s1.get(reverse(DETAIL_URL, args={sle[0].id})) assert json.loads(r.content)['id'] == sle[0].id -@ pytest.mark.parametrize("arg", [ +@pytest.mark.parametrize("arg", [ ['a_u', 403], ['g1_s1', 404], ['u1_s1', 200], @@ -76,14 +78,8 @@ def test_get_detail(u1_s1, sle): def test_update(arg, request, sle): c = request.getfixturevalue(arg[0]) new_val = float(sle[0].amount + 1) - r = c.patch( - reverse( - DETAIL_URL, - args={sle[0].id} - ), - {'amount': new_val}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={sle[0].id}), {'amount': new_val}, + content_type='application/json') assert r.status_code == arg[1] if r.status_code == 200: response = json.loads(r.content) @@ -98,14 +94,14 @@ def test_update(arg, request, sle): ]) def test_add(arg, request, sle): c = request.getfixturevalue(arg[0]) - r = c.post( - reverse(LIST_URL), - {'food': { + r = c.post(reverse(LIST_URL), { + 'food': { 'id': sle[0].food.__dict__['id'], 'name': sle[0].food.__dict__['name'], - }, 'amount': 1}, - content_type='application/json' - ) + }, + 'amount': 1 + }, + content_type='application/json') response = json.loads(r.content) print(r.content) assert r.status_code == arg[1] @@ -114,102 +110,93 @@ def test_add(arg, request, sle): def test_delete(u1_s1, u1_s2, sle): - r = u1_s2.delete( - reverse( - DETAIL_URL, - args={sle[0].id} - ) - ) + r = u1_s2.delete(reverse(DETAIL_URL, args={sle[0].id})) assert r.status_code == 404 - r = u1_s1.delete( - reverse( - DETAIL_URL, - args={sle[0].id} - ) - ) + r = u1_s1.delete(reverse(DETAIL_URL, args={sle[0].id})) assert r.status_code == 204 @pytest.mark.parametrize("shared, count, sle_2", [ - ('g1_s1', 20, {'user': 'g1_s1'}), - ('g1_s2', 10, {'user': 'g1_s2'}), - ('u2_s1', 20, {'user': 'u2_s1'}), - ('u1_s2', 10, {'user': 'u1_s2'}), - ('a1_s1', 20, {'user': 'a1_s1'}), - ('a1_s2', 10, {'user': 'a1_s2'}), -], indirect=['sle_2']) + ('g1_s1', 20, { + 'user': 'g1_s1' + }), + ('g1_s2', 10, { + 'user': 'g1_s2' + }), + ('u2_s1', 20, { + 'user': 'u2_s1' + }), + ('u1_s2', 10, { + 'user': 'u1_s2' + }), + ('a1_s1', 20, { + 'user': 'a1_s1' + }), + ('a1_s2', 10, { + 'user': 'a1_s2' + }), +], + indirect=['sle_2']) def test_sharing(request, shared, count, sle_2, sle, u1_s1): user = auth.get_user(u1_s1) shared_client = request.getfixturevalue(shared) shared_user = auth.get_user(shared_client) # confirm shared user can't access shopping list items created by u1_s1 - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 10 - assert len(json.loads(shared_client.get(reverse(LIST_URL)).content)) == 10 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 10 + assert json.loads(shared_client.get( + reverse(LIST_URL)).content)['count'] == 10 user.userpreference.shopping_share.add(shared_user) # confirm sharing user only sees their shopping list - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 10 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 10 r = shared_client.get(reverse(LIST_URL)) # confirm shared user sees their list and the list that's shared with them - assert len(json.loads(r.content)) == count + assert json.loads(r.content)['count'] == count # test shared user can mark complete - x = shared_client.patch( - reverse(DETAIL_URL, args={sle[0].id}), - {'checked': True}, - content_type='application/json' - ) + x = shared_client.patch(reverse(DETAIL_URL, args={sle[0].id}), + {'checked': True}, + content_type='application/json') r = json.loads(shared_client.get(reverse(LIST_URL)).content) - assert len(r) == count + assert r['count'] == count # count unchecked entries if not x.status_code == 404: count = count - 1 - assert [x['checked'] for x in r].count(False) == count + assert [x['checked'] for x in r['results']].count(False) == count # test shared user can delete - x = shared_client.delete( - reverse( - DETAIL_URL, - args={sle[1].id} - ) - ) + x = shared_client.delete(reverse(DETAIL_URL, args={sle[1].id})) r = json.loads(shared_client.get(reverse(LIST_URL)).content) - assert len(r) == count + assert r['count'] == count # count unchecked entries if not x.status_code == 404: count = count - 1 - assert [x['checked'] for x in r].count(False) == count + assert [x['checked'] for x in r['results']].count(False) == count def test_completed(sle, u1_s1): # check 1 entry - u1_s1.patch( - reverse(DETAIL_URL, args={sle[0].id}), - {'checked': True}, - content_type='application/json' - ) + u1_s1.patch(reverse(DETAIL_URL, args={sle[0].id}), {'checked': True}, content_type='application/json') r = json.loads(u1_s1.get(reverse(LIST_URL)).content) - assert len(r) == 10 + assert r['count'] == 10 # count unchecked entries - assert [x['checked'] for x in r].count(False) == 9 + assert [x['checked'] for x in r['results']].count(False) == 9 # confirm completed_at is populated - assert [(x['completed_at'] is not None) for x in r if x['checked']].count(True) == 1 + assert [(x['completed_at'] is not None) for x in r['results'] + if x['checked']].count(True) == 1 - assert len(json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=0').content)) == 9 - assert len(json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=1').content)) == 1 + assert json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=0').content)['count'] == 9 + assert json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=1').content)['count'] == 1 # uncheck entry - u1_s1.patch( - reverse(DETAIL_URL, args={sle[0].id}), - {'checked': False}, - content_type='application/json' - ) + u1_s1.patch(reverse(DETAIL_URL, args={sle[0].id}), {'checked': False}, content_type='application/json') r = json.loads(u1_s1.get(reverse(LIST_URL)).content) - assert [x['checked'] for x in r].count(False) == 10 + assert [x['checked'] for x in r['results']].count(False) == 10 # confirm completed_at value cleared - assert [(x['completed_at'] is not None) for x in r if x['checked']].count(True) == 0 + assert [(x['completed_at'] is not None) for x in r['results'] + if x['checked']].count(True) == 0 def test_recent(sle, u1_s1): @@ -220,31 +207,33 @@ def test_recent(sle, u1_s1): today_start = timezone.now().replace(hour=0, minute=0, second=0) # past_date within recent_days threshold - past_date = today_start - timedelta(days=user.userpreference.shopping_recent_days - 1) + past_date = today_start - timedelta( + days=user.userpreference.shopping_recent_days - 1) sle[0].checked = True sle[0].completed_at = past_date sle[0].save() r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content) - assert len(r) == 10 - assert [x['checked'] for x in r].count(False) == 9 + assert r['count'] == 10 + assert [x['checked'] for x in r['results']].count(False) == 9 # past_date outside recent_days threshold - past_date = today_start - timedelta(days=user.userpreference.shopping_recent_days + 2) + past_date = today_start - timedelta( + days=user.userpreference.shopping_recent_days + 2) sle[0].completed_at = past_date sle[0].save() r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content) - assert len(r) == 9 - assert [x['checked'] for x in r].count(False) == 9 + assert r['count'] == 9 + assert [x['checked'] for x in r['results']].count(False) == 9 # user preference moved to include entry again user.userpreference.shopping_recent_days = user.userpreference.shopping_recent_days + 4 user.userpreference.save() r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content) - assert len(r) == 10 - assert [x['checked'] for x in r].count(False) == 9 + assert r['count'] == 10 + assert [x['checked'] for x in r['results']].count(False) == 9 # TODO test auto onhand diff --git a/cookbook/tests/api/test_api_shopping_recipe.py b/cookbook/tests/api/test_api_shopping_recipe.py index 5001aca22..2024c696d 100644 --- a/cookbook/tests/api/test_api_shopping_recipe.py +++ b/cookbook/tests/api/test_api_shopping_recipe.py @@ -7,8 +7,9 @@ from django.contrib import auth from django.urls import reverse from django_scopes import scopes_disabled -from cookbook.models import Food, Ingredient, ShoppingListRecipe, ShoppingListEntry -from cookbook.tests.factories import MealPlanFactory, RecipeFactory, StepFactory, UserFactory +from cookbook.models import Food, Ingredient, ShoppingListEntry +from cookbook.tests.factories import (MealPlanFactory, RecipeFactory, + StepFactory, UserFactory) if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql': from django.db.backends.postgresql.features import DatabaseFeatures @@ -67,7 +68,7 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): user.userpreference.mealplan_autoadd_shopping = True user.userpreference.save() - assert len(json.loads(c.get(reverse(SHOPPING_LIST_URL)).content)) == 0 + assert json.loads(c.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 0 url = reverse(SHOPPING_RECIPE_URL, args={recipe.id}) r = c.put(url) @@ -77,19 +78,16 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): r = json.loads(c.get(reverse(SHOPPING_LIST_URL)).content) # recipe factory creates 10 ingredients by default - assert len(r) == sle_count - assert [x['created_by']['id'] for x in r].count(user.id) == sle_count + assert r['count'] == sle_count + assert [x['created_by']['id'] for x in r['results']].count(user.id) == sle_count # user in space can't see shopping list - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0 + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 0 user.userpreference.shopping_share.add(auth.get_user(u2_s1)) # after share, user in space can see shopping list - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count # confirm that the author of the recipe doesn't have access to shopping list if c != u1_s1: - assert len(json.loads( - u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 0 r = c.get(url) assert r.status_code == 405 @@ -125,12 +123,12 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u else: u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id})) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) - assert [x['created_by']['id'] for x in r].count(user.id) == sle_count + assert [x['created_by']['id'] for x in r['results']].count(user.id) == sle_count all_ing = list(ShoppingListEntry.objects.filter(list_recipe__recipe=recipe).all().values_list('ingredient', flat=True)) keep_ing = all_ing[1:-1] # remove first and last element del keep_ing[int(len(keep_ing) / 2)] # remove a middle element - list_recipe = r[0]['list_recipe'] - amount_sum = sum([x['amount'] for x in r]) + list_recipe = r['results'][0]['list_recipe'] + amount_sum = sum([x['amount'] for x in r['results']]) # test modifying shopping list as different user # test increasing servings size of recipe shopping list @@ -143,10 +141,9 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u content_type='application/json' ) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) - assert sum([x['amount'] for x in r]) == amount_sum * 2 - assert len(r) == sle_count - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count + assert sum([x['amount'] for x in r['results']]) == amount_sum * 2 + assert r['count'] == sle_count + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count # testing decreasing servings size of recipe shopping list if use_mealplan: @@ -158,10 +155,9 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u content_type='application/json' ) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) - assert sum([x['amount'] for x in r]) == amount_sum * .5 - assert len(r) == sle_count - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count + assert sum([x['amount'] for x in r['results']]) == amount_sum * .5 + assert r['count'] == sle_count + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count # test removing 3 items from shopping list u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), @@ -169,9 +165,8 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u content_type='application/json' ) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) - assert len(r) == sle_count - 3 - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 3 + assert r['count'] == sle_count - 3 + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count - 3 # add all ingredients to existing shopping list - don't change serving size u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), @@ -179,10 +174,9 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u content_type='application/json' ) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) - assert sum([x['amount'] for x in r]) == amount_sum * .5 - assert len(r) == sle_count - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count + assert sum([x['amount'] for x in r['results']]) == amount_sum * .5 + assert r['count'] == sle_count + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count @pytest.mark.parametrize("user2, sle_count", [ @@ -202,8 +196,7 @@ def test_shopping_recipe_userpreference(recipe, sle_count, use_mealplan, user2): food = Food.objects.get(id=ingredients[2].food.id) food.onhand_users.add(user) food.save() - food = recipe.steps.exclude(step_recipe=None).first( - ).step_recipe.steps.first().ingredients.first().food + food = recipe.steps.exclude(step_recipe=None).first().step_recipe.steps.first().ingredients.first().food food = Food.objects.get(id=food.id) food.onhand_users.add(user) food.save() @@ -211,12 +204,10 @@ def test_shopping_recipe_userpreference(recipe, sle_count, use_mealplan, user2): if use_mealplan: MealPlanFactory( space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe) - assert len(json.loads( - user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[0] + assert json.loads(user2.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count[0] else: user2.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id})) - assert len(json.loads( - user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[1] + assert json.loads(user2.get(reverse(SHOPPING_LIST_URL)).content)['count'] == sle_count[1] def test_shopping_recipe_mixed_authors(u1_s1, u2_s1, space_1): @@ -228,24 +219,19 @@ def test_shopping_recipe_mixed_authors(u1_s1, u2_s1, space_1): recipe1 = RecipeFactory(created_by=user1, space=space) recipe2 = RecipeFactory(created_by=user2, space=space) recipe3 = RecipeFactory(created_by=user3, space=space) - food = Food.objects.get( - id=recipe1.steps.first().ingredients.first().food.id) + food = Food.objects.get(id=recipe1.steps.first().ingredients.first().food.id) food.recipe = recipe2 food.save() - recipe1.steps.add(StepFactory(step_recipe=recipe3, - ingredients__count=0, space=space)) + recipe1.steps.add(StepFactory(step_recipe=recipe3, ingredients__count=0, space=space)) recipe1.save() u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe1.id})) - assert len(json.loads( - u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 29 - assert len(json.loads( - u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 29 + assert json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 0 @pytest.mark.parametrize("recipe", [{'steps__ingredients__header': 1}], indirect=['recipe']) def test_shopping_with_header_ingredient(u1_s1, recipe): u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id})) - assert len(json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 10 - assert len(json.loads( - u1_s1.get(reverse('api:ingredient-list')).content)['results']) == 11 + assert json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)['count'] == 10 + assert json.loads(u1_s1.get(reverse('api:ingredient-list')).content)['count'] == 11 diff --git a/cookbook/tests/api/test_api_space.py b/cookbook/tests/api/test_api_space.py index bedbec653..ddec75a7a 100644 --- a/cookbook/tests/api/test_api_space.py +++ b/cookbook/tests/api/test_api_space.py @@ -40,14 +40,8 @@ def test_update(arg, request, space_1, a1_s1): space_1.save() with scopes_disabled(): c = request.getfixturevalue(arg[0]) - r = c.patch( - reverse( - DETAIL_URL, - args={space_1.id} - ), - {'message': 'new'}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={space_1.id}), {'message': 'new'}, + content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 200: @@ -62,11 +56,7 @@ def test_update(arg, request, space_1, a1_s1): ]) def test_add(arg, request, u1_s2): c = request.getfixturevalue(arg[0]) - r = c.post( - reverse(LIST_URL), - {'name': 'test'}, - content_type='application/json' - ) + r = c.post(reverse(LIST_URL), {'name': 'test'}, content_type='application/json') assert r.status_code == arg[1] @@ -74,19 +64,9 @@ def test_delete(u1_s1, u1_s2, a1_s1, space_1): space_1.created_by = auth.get_user(a1_s1) space_1.save() # user cannot delete space - r = u1_s1.delete( - reverse( - DETAIL_URL, - args={space_1.id} - ) - ) + r = u1_s1.delete(reverse(DETAIL_URL, args={space_1.id})) assert r.status_code == 403 # event the space owner cannot delete his space over the api (this might change later but for now it's only available in the UI) - r = a1_s1.delete( - reverse( - DETAIL_URL, - args={space_1.id} - ) - ) + r = a1_s1.delete(reverse(DETAIL_URL, args={space_1.id})) assert r.status_code == 405 diff --git a/cookbook/tests/api/test_api_supermarket.py b/cookbook/tests/api/test_api_supermarket.py index c80663d39..d31f40143 100644 --- a/cookbook/tests/api/test_api_supermarket.py +++ b/cookbook/tests/api/test_api_supermarket.py @@ -32,30 +32,30 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 1 def test_list_filter(obj_1, obj_2, u1_s1): r = u1_s1.get(reverse(LIST_URL)) assert r.status_code == 200 response = json.loads(r.content) - assert len(response) == 2 + assert response['count'] == 2 response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?limit=1').content) - assert len(response) == 1 + assert response['count'] == 1 response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content) - assert len(response) == 0 + assert response['count'] == 0 response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[4:]}').content) - assert len(response) == 1 + assert response['count'] == 1 @pytest.mark.parametrize("arg", [ diff --git a/cookbook/tests/api/test_api_sync.py b/cookbook/tests/api/test_api_sync.py index 7e6aeb89f..d48b80427 100644 --- a/cookbook/tests/api/test_api_sync.py +++ b/cookbook/tests/api/test_api_sync.py @@ -13,14 +13,38 @@ DETAIL_URL = 'api:sync-detail' @pytest.fixture() def obj_1(space_1, u1_s1): - s = Storage.objects.create(name='Test Storage', username='test', password='password', token='token', url='url', created_by=auth.get_user(u1_s1), space=space_1, ) - return Sync.objects.create(storage=s, path='path', space=space_1, ) + s = Storage.objects.create( + name='Test Storage', + username='test', + password='password', + token='token', + url='url', + created_by=auth.get_user(u1_s1), + space=space_1, + ) + return Sync.objects.create( + storage=s, + path='path', + space=space_1, + ) @pytest.fixture def obj_2(space_1, u1_s1): - s = Storage.objects.create(name='Test Storage', username='test', password='password', token='token', url='url', created_by=auth.get_user(u1_s1), space=space_1, ) - return Sync.objects.create(storage=s, path='path', space=space_1, ) + s = Storage.objects.create( + name='Test Storage', + username='test', + password='password', + token='token', + url='url', + created_by=auth.get_user(u1_s1), + space=space_1, + ) + return Sync.objects.create( + storage=s, + path='path', + space=space_1, + ) @pytest.mark.parametrize("arg", [ @@ -35,14 +59,14 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, a1_s1, a1_s2, space_2): - assert len(json.loads(a1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(a1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(a1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(a1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(a1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(a1_s2.get(reverse(LIST_URL)).content)) == 1 + assert json.loads(a1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(a1_s2.get(reverse(LIST_URL)).content)['count'] == 1 @pytest.mark.parametrize("arg", [ @@ -56,14 +80,8 @@ def test_list_space(obj_1, obj_2, a1_s1, a1_s2, space_2): ]) def test_update(arg, request, obj_1): c = request.getfixturevalue(arg[0]) - r = c.patch( - reverse( - DETAIL_URL, - args={obj_1.id} - ), - {'path': 'new'}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={obj_1.id}), {'path': 'new'}, + content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 200: @@ -78,11 +96,11 @@ def test_update(arg, request, obj_1): ]) def test_add(arg, request, a1_s2, obj_1): c = request.getfixturevalue(arg[0]) - r = c.post( - reverse(LIST_URL), - {'storage': obj_1.storage.pk, 'path': 'test'}, - content_type='application/json' - ) + r = c.post(reverse(LIST_URL), { + 'storage': obj_1.storage.pk, + 'path': 'test' + }, + content_type='application/json') response = json.loads(r.content) print(r.content) assert r.status_code == arg[1] @@ -95,20 +113,10 @@ def test_add(arg, request, a1_s2, obj_1): def test_delete(a1_s1, a1_s2, obj_1): - r = a1_s2.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = a1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 - r = a1_s1.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = a1_s1.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 204 with scopes_disabled(): diff --git a/cookbook/tests/api/test_api_unit_conversion.py b/cookbook/tests/api/test_api_unit_conversion.py index 25bbb704c..3fd6e9099 100644 --- a/cookbook/tests/api/test_api_unit_conversion.py +++ b/cookbook/tests/api/test_api_unit_conversion.py @@ -21,8 +21,7 @@ def obj_1(space_1, u1_s1): converted_amount=100, converted_unit=get_random_unit(space_1, u1_s1), created_by=auth.get_user(u1_s1), - space=space_1 - )[0] + space=space_1)[0] @pytest.fixture @@ -34,8 +33,7 @@ def obj_2(space_1, u1_s1): converted_amount=100, converted_unit=get_random_unit(space_1, u1_s1), created_by=auth.get_user(u1_s1), - space=space_1 - )[0] + space=space_1)[0] @pytest.mark.parametrize("arg", [ @@ -50,14 +48,14 @@ def test_list_permission(arg, request): def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 obj_1.space = space_2 obj_1.save() - assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 - assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1 + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 1 @pytest.mark.parametrize("arg", [ @@ -71,14 +69,8 @@ def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): ]) def test_update(arg, request, obj_1): c = request.getfixturevalue(arg[0]) - r = c.patch( - reverse( - DETAIL_URL, - args={obj_1.id} - ), - {'base_amount': 1000}, - content_type='application/json' - ) + r = c.patch(reverse(DETAIL_URL, args={obj_1.id}), {'base_amount': 1000}, + content_type='application/json') response = json.loads(r.content) assert r.status_code == arg[1] if r.status_code == 200: @@ -97,18 +89,23 @@ def test_add(arg, request, u1_s2, space_1, u1_s1): random_unit_1 = get_random_unit(space_1, u1_s1) random_unit_2 = get_random_unit(space_1, u1_s1) random_food_1 = get_random_unit(space_1, u1_s1) - r = c.post( - reverse(LIST_URL), - { - 'food': {'id': random_food_1.id, 'name': random_food_1.name}, - 'base_amount': 100, - 'base_unit': {'id': random_unit_1.id, 'name': random_unit_1.name}, - 'converted_amount': 100, - 'converted_unit': {'id': random_unit_2.id, 'name': random_unit_2.name} - + r = c.post(reverse(LIST_URL), { + 'food': { + 'id': random_food_1.id, + 'name': random_food_1.name }, - content_type='application/json' - ) + 'base_amount': 100, + 'base_unit': { + 'id': random_unit_1.id, + 'name': random_unit_1.name + }, + 'converted_amount': 100, + 'converted_unit': { + 'id': random_unit_2.id, + 'name': random_unit_2.name + } + }, + content_type='application/json') response = json.loads(r.content) print(response) @@ -122,53 +119,54 @@ def test_add(arg, request, u1_s2, space_1, u1_s1): def test_add_duplicate(u1_s1, u1_s2, obj_1): - r = u1_s1.post( - reverse(LIST_URL), - { - 'food': {'id': obj_1.food.id, 'name': obj_1.food.name}, - 'base_amount': 100, - 'base_unit': {'id': obj_1.base_unit.id, 'name': obj_1.base_unit.name}, - 'converted_amount': 100, - 'converted_unit': {'id': obj_1.converted_unit.id, 'name': obj_1.converted_unit.name} + r = u1_s1.post(reverse(LIST_URL), { + 'food': { + 'id': obj_1.food.id, + 'name': obj_1.food.name }, - - content_type='application/json' - ) + 'base_amount': 100, + 'base_unit': { + 'id': obj_1.base_unit.id, + 'name': obj_1.base_unit.name + }, + 'converted_amount': 100, + 'converted_unit': { + 'id': obj_1.converted_unit.id, + 'name': obj_1.converted_unit.name + } + }, + content_type='application/json') response = json.loads(r.content) assert r.status_code == 201 assert response['id'] == obj_1.id - r = u1_s2.post( - reverse(LIST_URL), - { - 'food': {'id': obj_1.food.id, 'name': obj_1.food.name}, - 'base_amount': 100, - 'base_unit': {'id': obj_1.base_unit.id, 'name': obj_1.base_unit.name}, - 'converted_amount': 100, - 'converted_unit': {'id': obj_1.converted_unit.id, 'name': obj_1.converted_unit.name} + r = u1_s2.post(reverse(LIST_URL), { + 'food': { + 'id': obj_1.food.id, + 'name': obj_1.food.name }, - content_type='application/json' - ) + 'base_amount': 100, + 'base_unit': { + 'id': obj_1.base_unit.id, + 'name': obj_1.base_unit.name + }, + 'converted_amount': 100, + 'converted_unit': { + 'id': obj_1.converted_unit.id, + 'name': obj_1.converted_unit.name + } + }, + content_type='application/json') response = json.loads(r.content) assert r.status_code == 201 assert response['id'] != obj_1.id def test_delete(u1_s1, u1_s2, obj_1): - r = u1_s2.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 - r = u1_s1.delete( - reverse( - DETAIL_URL, - args={obj_1.id} - ) - ) + r = u1_s1.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 204 with scopes_disabled(): diff --git a/cookbook/tests/other/test_makenow_filter.py b/cookbook/tests/other/test_makenow_filter.py index d9c403401..d82079e94 100644 --- a/cookbook/tests/other/test_makenow_filter.py +++ b/cookbook/tests/other/test_makenow_filter.py @@ -131,22 +131,20 @@ def test_makenow_sibling_substitute(recipes, makenow_recipe, user1, space_1): request = type('', (object,), {'space': space_1, 'user': user1})() search = RecipeSearch(request, makenow='true') with scope(space=space_1): - food = Food.objects.filter( - ingredient__step__recipe=makenow_recipe.id).first() + food = Food.objects.filter(ingredient__step__recipe=makenow_recipe.id).first() onhand_user = food.onhand_users.first() food.onhand_users.clear() food.substitute_siblings = True food.save() assert search.get_queryset(Recipe.objects.all()).count() == 0 new_parent = FoodFactory.create(space=space_1) - new_sibling = FoodFactory.create( - space=space_1, onhand_users=[onhand_user]) + new_sibling = FoodFactory.create(space=space_1, onhand_users=[onhand_user]) new_sibling.move(new_parent, node_location) food.move(new_parent, node_location) - assert Food.objects.filter( - ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9 - assert Food.objects.filter( - ingredient__step__recipe=makenow_recipe.id, depth=2).count() == 1 + # force refresh from database, treebeard bypasses ORM + food = Food.objects.get(id=food.id) + assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9 + assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, depth=2).count() == 1 search = search.get_queryset(Recipe.objects.all()) assert search.count() == 1 assert search.first().id == makenow_recipe.id diff --git a/cookbook/tests/other/test_schemas.py b/cookbook/tests/other/test_schemas.py index c5a68cc09..cdbd2016f 100644 --- a/cookbook/tests/other/test_schemas.py +++ b/cookbook/tests/other/test_schemas.py @@ -5,32 +5,35 @@ from rest_framework.viewsets import ModelViewSet from cookbook.urls import urlpatterns +skipped_schemas = ['api_sync'] + def has_choice_field(model): model_fields = model._meta.get_fields() - return any(field.get_internal_type() == 'CharField' and hasattr(field, 'choices') and field.choices for field in model_fields) + return any(field.get_internal_type() == 'CharField' + and hasattr(field, 'choices') and field.choices + for field in model_fields) def is_list_function(callback): - return ( - hasattr(callback, 'initkwargs') - and callback.initkwargs.get('detail') == False - and hasattr(callback, 'cls') - and hasattr(callback.cls, 'list') - ) + return (hasattr(callback, 'initkwargs') + and callback.initkwargs.get('detail') == False + and hasattr(callback, 'cls') and hasattr(callback.cls, 'list')) # generates list of all api enpoints def enumerate_urlpatterns(urlpatterns, base_url=''): for i, url_pattern in enumerate(urlpatterns): # api-root isn't an endpoint, so skip it - if isinstance(url_pattern, URLPattern) and url_pattern.name == 'api-root': + if isinstance(url_pattern, + URLPattern) and url_pattern.name == 'api-root': continue # if the url pattern starts with 'api/' it is an api endpoint and should be part of the list if isinstance(url_pattern, URLPattern): pattern = f"{base_url}{str(url_pattern.pattern)}" # DRF endpoints generate two patterns, no need to test both - if pattern[:4] == 'api/' and pattern[-25:] != '.(?P[a-z0-9]+)/?$': + if pattern[:4] == 'api/' and pattern[ + -25:] != '.(?P[a-z0-9]+)/?$': api_endpoints.append(url_pattern) # if the pattern is a URLResolver then it is a list of URLPatterns and needs to be enumerated again, prepending the url_pattern elif isinstance(url_pattern, URLResolver): @@ -44,7 +47,9 @@ enumerate_urlpatterns(urlpatterns) list_api_endpoints = [a for a in api_endpoints if is_list_function(a.callback)] # filtered list of api_endpoints that only includes endpoints that have type ModelViewSet and a Choice CharField enum_api_endpoints = [ - a for a in list_api_endpoints if hasattr(a.callback, 'cls') and issubclass(a.callback.cls, ModelViewSet) and has_choice_field(a.callback.cls.serializer_class.Meta.model) + a for a in list_api_endpoints + if hasattr(a.callback, 'cls') and issubclass(a.callback.cls, ModelViewSet) + and has_choice_field(a.callback.cls.serializer_class.Meta.model) ] @@ -52,16 +57,17 @@ enum_api_endpoints = [ def test_pagination_exists(api): assert hasattr(api.callback.cls, 'pagination_class') and ( api.callback.cls.pagination_class is not None - or getattr(api.callback.cls, 'pagination_disabled') - ), f"API {api.name} is not paginated." + or getattr(api.callback.cls, + 'pagination_disabled')), f"API {api.name} is not paginated." @pytest.mark.parametrize("api", api_endpoints, ids=lambda api: api.name) def test_autoschema_exists(api): + if api.name in skipped_schemas: + return assert issubclass(api.callback.cls.schema.__class__, AutoSchema) - # @pytest.mark.parametrize("api", enum_api_endpoints, ids=lambda api: api.name) # def test_schema_enum(api): # model = api.callback.cls.serializer_class.Meta.model diff --git a/cookbook/urls.py b/cookbook/urls.py index 4f659d41e..a5cacf2d4 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -19,7 +19,6 @@ from .views.api import CustomAuthToken, ImportOpenData # extend DRF default router class to allow including additional routers class DefaultRouter(routers.DefaultRouter): - def extend(self, r): self.registry.extend(r.registry) @@ -121,7 +120,7 @@ urlpatterns = [ path('api/get_recipe_file//', api.get_recipe_file, name='api_get_recipe_file'), path('api/sync_all/', api.sync_all, name='api_sync'), - path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), + # path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), path('api/recipe-from-source/', api.RecipeUrlImportView.as_view(), name='api_recipe_from_source'), path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'), diff --git a/cookbook/views/api.py b/cookbook/views/api.py index ff5a23ece..8f34f6805 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -416,10 +416,11 @@ class GroupViewSet(viewsets.ModelViewSet): http_method_names = ['get', ] -class SpaceViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet): +class SpaceViewSet(viewsets.ModelViewSet): queryset = Space.objects serializer_class = SpaceSerializer permission_classes = [IsReadOnlyDRF & CustomIsUser | CustomIsOwner & CustomIsAdmin & CustomTokenHasReadWriteScope] + pagination_disabled = True http_method_names = ['get', 'patch'] def get_queryset(self): @@ -453,10 +454,11 @@ class UserSpaceViewSet(viewsets.ModelViewSet): return self.queryset.filter(user=self.request.user, space=self.request.space) -class UserPreferenceViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet): +class UserPreferenceViewSet(viewsets.ModelViewSet): queryset = UserPreference.objects serializer_class = UserPreferenceSerializer permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope] + pagination_disabled = True http_method_names = ['get', 'patch', ] def get_queryset(self): @@ -1756,29 +1758,30 @@ def share_link(request, pk): return JsonResponse({'error': 'sharing_disabled'}, status=403) -@extend_schema( - request=inline_serializer(name="PlanIcalSerializer", fields={'from_date': CharField(), 'to_date': CharField()}), - responses=None, - parameters=[ - OpenApiParameter(name='from_date', location=OpenApiParameter.PATH, description=_('Get meal plans from date (inclusive).'), type=str, examples=[DateExample]), - OpenApiParameter(name='to_date', location=OpenApiParameter.PATH, description=_('Get meal plans to date (inclusive).'), type=str, examples=[DateExample]), - ] -) -@api_view(['GET']) -@permission_classes([CustomIsUser & CustomTokenHasReadWriteScope]) -def get_plan_ical(request, from_date=datetime.date.today(), to_date=None): - queryset = MealPlan.objects.filter(Q(created_by=request.user) - | Q(shared=request.user)).filter(space=request.user.userspace_set.filter(active=1).first().space).distinct().all() +# NOTE: I think this was replaced by icalMealPlanApi? +# @extend_schema( +# request=inline_serializer(name="PlanIcalSerializer", fields={'from_date': CharField(), 'to_date': CharField()}), +# responses=None, +# parameters=[ +# OpenApiParameter(name='from_date', location=OpenApiParameter.PATH, description=_('Get meal plans from date (inclusive).'), type=str, examples=[DateExample]), +# OpenApiParameter(name='to_date', location=OpenApiParameter.PATH, description=_('Get meal plans to date (inclusive).'), type=str, examples=[DateExample]), +# ] +# ) +# @api_view(['GET']) +# @permission_classes([CustomIsUser & CustomTokenHasReadWriteScope]) +# def get_plan_ical(request, from_date=datetime.date.today(), to_date=None): +# queryset = MealPlan.objects.filter(Q(created_by=request.user) +# | Q(shared=request.user)).filter(space=request.user.userspace_set.filter(active=1).first().space).distinct().all() - if from_date is not None: - queryset = queryset.filter(from_date__gte=from_date) +# if from_date is not None: +# queryset = queryset.filter(from_date__gte=from_date) - if to_date is not None: - queryset = queryset.filter(to_date__lte=to_date) +# if to_date is not None: +# queryset = queryset.filter(to_date__lte=to_date) + +# return meal_plans_to_ical(queryset, f'meal_plan_{from_date}-{to_date}.ics') - return meal_plans_to_ical(queryset, f'meal_plan_{from_date}-{to_date}.ics') -# TODO is this replaced now? def meal_plans_to_ical(queryset, filename): cal = Calendar()