From 8c3195937b8d94a9a1c711c30e4cbac673aca872 Mon Sep 17 00:00:00 2001 From: smilerz Date: Fri, 21 Apr 2023 13:14:23 -0500 Subject: [PATCH 1/5] fix food tests --- cookbook/tests/api/test_api_food.py | 126 +++++++++----- .../tests/api/test_api_shopping_recipe.py | 107 +++++++----- cookbook/tests/factories/__init__.py | 155 +++++++++++------- .../other/test_recipe_full_text_search.py | 112 ++++++------- requirements.txt | 10 +- vue/src/components/IngredientComponent.vue | 41 ++--- 6 files changed, 328 insertions(+), 223 deletions(-) diff --git a/cookbook/tests/api/test_api_food.py b/cookbook/tests/api/test_api_food.py index 98376280..05060034 100644 --- a/cookbook/tests/api/test_api_food.py +++ b/cookbook/tests/api/test_api_food.py @@ -56,23 +56,32 @@ def obj_tree_1(request, space_1): params = request.param # request.param is a magic variable except AttributeError: params = {} - objs = [] inherit = params.pop('inherit', False) - objs.extend(FoodFactory.create_batch(3, space=space_1, **params)) + FoodFactory.create_batch(3, space=space_1, **params) + objs = Food.objects.values_list('id', flat=True) + obj_id = objs[1] + child_id = objs[0] + parent_id = objs[2] # set all foods to inherit everything if inherit: inherit = Food.inheritable_fields - Through = Food.objects.filter(space=space_1).first().inherit_fields.through + Through = Food.objects.filter( + space=space_1).first().inherit_fields.through for i in inherit: Through.objects.bulk_create([ Through(food_id=x, foodinheritfield_id=i.id) for x in Food.objects.filter(space=space_1).values_list('id', flat=True) ]) - objs[0].move(objs[1], node_location) - objs[1].move(objs[2], node_location) - return Food.objects.get(id=objs[1].id) # whenever you move/merge a tree it's safest to re-get the object + Food.objects.get(id=child_id).move( + Food.objects.get(id=obj_id), node_location) + + Food.objects.get(id=obj_id).move( + Food.objects.get(id=parent_id), node_location) + + # whenever you move/merge a tree it's safest to re-get the object + return Food.objects.get(id=obj_id) @pytest.mark.parametrize("arg", [ @@ -107,19 +116,23 @@ def test_list_filter(obj_1, obj_2, u1_s1): assert obj_2.name in [x['name'] for x in response['results']] assert response['results'][0]['name'] < response['results'][1]['name'] - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?page_size=1').content) + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?page_size=1').content) assert len(response['results']) == 1 response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?limit=1').content) assert len(response['results']) == 1 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=''&limit=1').content) + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?query=''&limit=1').content) assert len(response['results']) == 1 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content) + 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) + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[:-4]}').content) assert response['count'] == 1 @@ -262,8 +275,9 @@ def test_integrity(u1_s1, recipe_1_s1): def test_move(u1_s1, obj_tree_1, obj_2, obj_3, space_1): with scope(space=space_1): + # for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj + obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() - child = obj_tree_1.get_descendants()[0] assert parent.get_num_children() == 1 assert parent.get_descendant_count() == 2 assert Food.get_root_nodes().filter(space=space_1).count() == 2 @@ -295,8 +309,9 @@ def test_move(u1_s1, obj_tree_1, obj_2, obj_3, space_1): def test_move_errors(u1_s1, obj_tree_1, obj_3, space_1): with scope(space=space_1): + # for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj + obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() - child = obj_tree_1.get_descendants()[0] # move child to root r = u1_s1.put(reverse(MOVE_URL, args=[obj_tree_1.id, 0])) assert r.status_code == 200 @@ -351,7 +366,7 @@ def test_merge_shopping_entries(obj_tree_1, u1_s1, space_1): with scope(space=space_1): parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] - ShoppingListEntryFactory.create(food=parent, space=space_1) + ShoppingListEntryFactory.create(food=parent, space=space_1) ShoppingListEntryFactory.create(food=child, space=space_1) assert parent.get_num_children() == 1 assert parent.get_descendant_count() == 2 @@ -371,8 +386,10 @@ def test_merge_shopping_entries(obj_tree_1, u1_s1, space_1): assert obj_tree_1.shopping_entries.count() == 1 # now has child's ingredient -def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1): +def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1): with scope(space=space_1): + # for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj + obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] assert parent.get_num_children() == 1 @@ -417,7 +434,6 @@ def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1): def test_merge_errors(u1_s1, obj_tree_1, obj_3, space_1): with scope(space=space_1): parent = obj_tree_1.get_parent() - child = obj_tree_1.get_descendants()[0] # attempt to merge with non-existent parent r = u1_s1.put( @@ -451,8 +467,9 @@ def test_merge_errors(u1_s1, obj_tree_1, obj_3, space_1): def test_root_filter(obj_tree_1, obj_2, obj_3, u1_s1): with scope(space=obj_tree_1.space): + # for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj + obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() - child = obj_tree_1.get_descendants()[0] # should return root objects in the space (obj_1, obj_2), ignoring query filters response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root=0').content) @@ -461,34 +478,46 @@ def test_root_filter(obj_tree_1, obj_2, obj_3, u1_s1): with scopes_disabled(): obj_2.move(parent, node_location) # should return direct children of parent (obj_tree_1, obj_2), ignoring query filters - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}').content) + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}').content) assert response['count'] == 2 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}&query={obj_2.name[4:]}').content) + response = json.loads(u1_s1.get( + f'{reverse(LIST_URL)}?root={parent.id}&query={obj_2.name[4:]}').content) assert response['count'] == 2 def test_tree_filter(obj_tree_1, obj_2, obj_3, u1_s1): with scope(space=obj_tree_1.space): + # for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj + obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() - child = obj_tree_1.get_descendants()[0] obj_2.move(parent, node_location) # should return full tree starting at parent (obj_tree_1, obj_2), ignoring query filters - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}').content) + response = json.loads( + u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}').content) assert response['count'] == 4 - response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}&query={obj_2.name[4:]}').content) + response = json.loads(u1_s1.get( + f'{reverse(LIST_URL)}?tree={parent.id}&query={obj_2.name[4:]}').content) assert response['count'] == 4 # This is more about the model than the API - should this be moved to a different test? @pytest.mark.parametrize("obj_tree_1, field, inherit, new_val", [ - ({'has_category': True, 'inherit': True}, 'supermarket_category', True, 'cat_1'), - ({'has_category': True, 'inherit': False}, 'supermarket_category', False, 'cat_1'), + ({'has_category': True, 'inherit': True}, + 'supermarket_category', True, 'cat_1'), + ({'has_category': True, 'inherit': False}, + 'supermarket_category', False, 'cat_1'), ({'ignore_shopping': True, 'inherit': True}, 'ignore_shopping', True, 'false'), - ({'ignore_shopping': True, 'inherit': False}, 'ignore_shopping', False, 'false'), - ({'substitute_children': True, 'inherit': True}, 'substitute_children', True, 'false'), - ({'substitute_children': True, 'inherit': False}, 'substitute_children', False, 'false'), - ({'substitute_siblings': True, 'inherit': True}, 'substitute_siblings', True, 'false'), - ({'substitute_siblings': True, 'inherit': False}, 'substitute_siblings', False, 'false'), + ({'ignore_shopping': True, 'inherit': False}, + 'ignore_shopping', False, 'false'), + ({'substitute_children': True, 'inherit': True}, + 'substitute_children', True, 'false'), + ({'substitute_children': True, 'inherit': False}, + 'substitute_children', False, 'false'), + ({'substitute_siblings': True, 'inherit': True}, + 'substitute_siblings', True, 'false'), + ({'substitute_siblings': True, 'inherit': False}, + 'substitute_siblings', False, 'false'), ], indirect=['obj_tree_1']) # indirect=True populates magic variable request.param of obj_tree_1 with the parameter def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1): with scope(space=obj_tree_1.space): @@ -498,8 +527,10 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1): new_val = request.getfixturevalue(new_val) # if this test passes it demonstrates that inheritance works # when moving to a parent as each food is created with a different category - assert (getattr(parent, field) == getattr(obj_tree_1, field)) in [inherit, True] - assert (getattr(obj_tree_1, field) == getattr(child, field)) in [inherit, True] + assert (getattr(parent, field) == getattr( + obj_tree_1, field)) in [inherit, True] + assert (getattr(obj_tree_1, field) == getattr( + child, field)) in [inherit, True] # change parent to a new value setattr(parent, field, new_val) with scope(space=parent.space): @@ -515,7 +546,8 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1): @pytest.mark.parametrize("obj_tree_1", [ - ({'has_category': True, 'inherit': False, 'ignore_shopping': True, 'substitute_children': True, 'substitute_siblings': True}), + ({'has_category': True, 'inherit': False, 'ignore_shopping': True, + 'substitute_children': True, 'substitute_siblings': True}), ], indirect=['obj_tree_1']) @pytest.mark.parametrize("global_reset", [True, False]) @pytest.mark.parametrize("field", ['ignore_shopping', 'substitute_children', 'substitute_siblings', 'supermarket_category']) @@ -534,10 +566,13 @@ def test_reset_inherit_space_fields(obj_tree_1, space_1, global_reset, field): assert getattr(parent, field) != getattr(obj_tree_1, field) if global_reset: - space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields + # set default inherit fields + space_1.food_inherit.add( + *Food.inheritable_fields.values_list('id', flat=True)) parent.reset_inheritance(space=space_1) else: - obj_tree_1.child_inherit_fields.set(Food.inheritable_fields.values_list('id', flat=True)) + obj_tree_1.child_inherit_fields.set( + Food.inheritable_fields.values_list('id', flat=True)) obj_tree_1.save() parent.reset_inheritance(space=space_1, food=obj_tree_1) # djangotree bypasses ORM and need to be retrieved again @@ -545,12 +580,14 @@ def test_reset_inherit_space_fields(obj_tree_1, space_1, global_reset, field): parent = Food.objects.get(id=parent.id) child = Food.objects.get(id=child.id) - assert (getattr(parent, field) == getattr(obj_tree_1, field)) == global_reset + assert (getattr(parent, field) == getattr( + obj_tree_1, field)) == global_reset assert getattr(obj_tree_1, field) == getattr(child, field) @pytest.mark.parametrize("obj_tree_1", [ - ({'has_category': True, 'inherit': False, 'ignore_shopping': True, 'substitute_children': True, 'substitute_siblings': True}), + ({'has_category': True, 'inherit': False, 'ignore_shopping': True, + 'substitute_children': True, 'substitute_siblings': True}), ], indirect=['obj_tree_1']) @pytest.mark.parametrize("field", ['ignore_shopping', 'substitute_children', 'substitute_siblings', 'supermarket_category']) def test_reset_inherit_no_food_instances(obj_tree_1, space_1, field): @@ -558,13 +595,17 @@ def test_reset_inherit_no_food_instances(obj_tree_1, space_1, field): parent = obj_tree_1.get_parent() Food.objects.all().delete() - space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields + # set default inherit fields + space_1.food_inherit.add( + *Food.inheritable_fields.values_list('id', flat=True)) parent.reset_inheritance(space=space_1) def test_onhand(obj_1, u1_s1, u2_s1): - assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False - assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False + assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[ + 'food_onhand'] == False + assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[ + 'food_onhand'] == False u1_s1.patch( reverse( @@ -574,10 +615,13 @@ def test_onhand(obj_1, u1_s1, u2_s1): {'food_onhand': True}, content_type='application/json' ) - assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == True - assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False + assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[ + 'food_onhand'] == True + assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[ + 'food_onhand'] == False user1 = auth.get_user(u1_s1) user2 = auth.get_user(u2_s1) user1.userpreference.shopping_share.add(user2) - assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == True + assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[ + 'food_onhand'] == True diff --git a/cookbook/tests/api/test_api_shopping_recipe.py b/cookbook/tests/api/test_api_shopping_recipe.py index 376f5fef..56f35683 100644 --- a/cookbook/tests/api/test_api_shopping_recipe.py +++ b/cookbook/tests/api/test_api_shopping_recipe.py @@ -1,20 +1,14 @@ import json -from datetime import timedelta -import factory import pytest # work around for bug described here https://stackoverflow.com/a/70312265/15762829 from django.conf import settings from django.contrib import auth -from django.forms import model_to_dict from django.urls import reverse -from django.utils import timezone -from django_scopes import scope, scopes_disabled -from pytest_factoryboy import LazyFixture, register +from django_scopes import scopes_disabled -from cookbook.models import Food, Ingredient, ShoppingListEntry, Step -from cookbook.tests.factories import (IngredientFactory, MealPlanFactory, RecipeFactory, - StepFactory, UserFactory) +from cookbook.models import Food, Ingredient +from cookbook.tests.factories import MealPlanFactory, RecipeFactory, StepFactory, UserFactory if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']: @@ -32,9 +26,12 @@ def user2(request, u1_s1): except AttributeError: params = {} user = auth.get_user(u1_s1) - user.userpreference.mealplan_autoadd_shopping = params.get('mealplan_autoadd_shopping', True) - user.userpreference.mealplan_autoinclude_related = params.get('mealplan_autoinclude_related', True) - user.userpreference.mealplan_autoexclude_onhand = params.get('mealplan_autoexclude_onhand', True) + user.userpreference.mealplan_autoadd_shopping = params.get( + 'mealplan_autoadd_shopping', True) + user.userpreference.mealplan_autoinclude_related = params.get( + 'mealplan_autoinclude_related', True) + user.userpreference.mealplan_autoexclude_onhand = params.get( + 'mealplan_autoexclude_onhand', True) user.userpreference.save() return u1_s1 @@ -50,7 +47,6 @@ def recipe(request, space_1, u1_s1): return RecipeFactory(**params) - @pytest.mark.parametrize("arg", [ ['g1_s1', 204], ['u1_s1', 204], @@ -59,11 +55,14 @@ def recipe(request, space_1, u1_s1): ]) @pytest.mark.parametrize("recipe, sle_count", [ ({}, 10), - ({'steps__recipe_count': 1}, 20), # shopping list from recipe with StepRecipe - ({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe - ({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe + # shopping list from recipe with StepRecipe + ({'steps__recipe_count': 1}, 20), + # shopping list from recipe with food recipe + ({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), + # shopping list from recipe with StepRecipe and food recipe + ({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), ], indirect=['recipe']) -def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): +def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): c = request.getfixturevalue(arg[0]) user = auth.get_user(c) user.userpreference.mealplan_autoadd_shopping = True @@ -78,16 +77,20 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): if r.status_code == 204: # skip anonymous user r = json.loads(c.get(reverse(SHOPPING_LIST_URL)).content) - assert len(r) == sle_count # recipe factory creates 10 ingredients by default + # 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 # user in space can't see shopping list - assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0 + assert len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 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 len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 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 len(json.loads( + u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0 r = c.get(url) assert r.status_code == 405 @@ -99,9 +102,12 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1): @pytest.mark.parametrize("recipe, sle_count", [ ({}, 10), - ({'steps__recipe_count': 1}, 20), # shopping list from recipe with StepRecipe - ({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe - ({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe + # shopping list from recipe with StepRecipe + ({'steps__recipe_count': 1}, 20), + # shopping list from recipe with food recipe + ({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), + # shopping list from recipe with StepRecipe and food recipe + ({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), ], indirect=['recipe']) @pytest.mark.parametrize("use_mealplan", [(False), (True), ]) def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u2_s1): @@ -115,31 +121,33 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u user.userpreference.save() if use_mealplan: - mealplan = MealPlanFactory(space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe) + mealplan = MealPlanFactory( + space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe) 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 all_ing = [x['ingredient'] for x in r] keep_ing = all_ing[1:-1] # remove first and last element - del keep_ing[int(len(keep_ing)/2)] # remove a middle 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]) # test modifying shopping list as different user # test increasing servings size of recipe shopping list if use_mealplan: - mealplan.servings = 2*recipe.servings + mealplan.servings = 2 * recipe.servings mealplan.save() else: u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), - {'list_recipe': list_recipe, 'servings': 2*recipe.servings}, + {'list_recipe': list_recipe, 'servings': 2 * recipe.servings}, 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 len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count # testing decreasing servings size of recipe shopping list if use_mealplan: @@ -153,7 +161,8 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u 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 len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count # test removing 3 items from shopping list u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), @@ -162,7 +171,8 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u ) 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 len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 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}), @@ -172,14 +182,16 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u 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 len(json.loads( + u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count @pytest.mark.parametrize("user2, sle_count", [ ({'mealplan_autoadd_shopping': False}, (0, 18)), ({'mealplan_autoinclude_related': False}, (9, 9)), ({'mealplan_autoexclude_onhand': False}, (20, 20)), - ({'mealplan_autoexclude_onhand': False, 'mealplan_autoinclude_related': False}, (10, 10)), + ({'mealplan_autoexclude_onhand': False, + 'mealplan_autoinclude_related': False}, (10, 10)), ], indirect=['user2']) @pytest.mark.parametrize("use_mealplan", [(False), (True), ]) @pytest.mark.parametrize("recipe", [({'steps__recipe_count': 1})], indirect=['recipe']) @@ -191,20 +203,24 @@ 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() if use_mealplan: - 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] + 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] 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 len(json.loads( + user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[1] -def test_shopping_recipe_mixed_authors(u1_s1, u2_s1,space_1): +def test_shopping_recipe_mixed_authors(u1_s1, u2_s1, space_1): with scopes_disabled(): user1 = auth.get_user(u1_s1) user2 = auth.get_user(u2_s1) @@ -213,15 +229,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 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 @pytest.mark.parametrize("recipe", [{'steps__ingredients__header': 1}], indirect=['recipe']) @@ -230,4 +250,5 @@ def test_shopping_with_header_ingredient(u1_s1, recipe): # recipe.step_set.first().ingredient_set.add(IngredientFactory(ingredients__header=1)) 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 len(json.loads( + u1_s1.get(reverse('api:ingredient-list')).content)['results']) == 11 diff --git a/cookbook/tests/factories/__init__.py b/cookbook/tests/factories/__init__.py index c4b70e77..1b514b4f 100644 --- a/cookbook/tests/factories/__init__.py +++ b/cookbook/tests/factories/__init__.py @@ -4,13 +4,12 @@ from decimal import Decimal import factory import pytest -from django.contrib import auth from django.contrib.auth.models import Group, User from django_scopes import scopes_disabled from faker import Factory as FakerFactory from pytest_factoryboy import register -from cookbook.models import Recipe, Step, UserSpace +from cookbook.models import UserSpace # this code will run immediately prior to creating the model object useful when you want a reverse relationship # log = factory.RelatedFactory( @@ -53,7 +52,8 @@ class SpaceFactory(factory.django.DjangoModelFactory): class UserFactory(factory.django.DjangoModelFactory): """User factory.""" - username = factory.LazyAttribute(lambda x: faker.simple_profile()['username']) + username = factory.LazyAttribute( + lambda x: faker.simple_profile()['username']) first_name = factory.LazyAttribute(lambda x: faker.first_name()) last_name = factory.LazyAttribute(lambda x: faker.last_name()) email = factory.LazyAttribute(lambda x: faker.email()) @@ -65,7 +65,8 @@ class UserFactory(factory.django.DjangoModelFactory): return if extracted: - us = UserSpace.objects.create(space=self.space, user=self, active=True) + us = UserSpace.objects.create( + space=self.space, user=self, active=True) us.groups.add(Group.objects.get(name=extracted)) @factory.post_generation @@ -75,7 +76,8 @@ class UserFactory(factory.django.DjangoModelFactory): if extracted: for prefs in extracted: - self.userpreference[prefs] = extracted[prefs]/0 # intentionally break so it can be debugged later + # intentionally break so it can be debugged later + self.userpreference[prefs] = extracted[prefs]/0 class Meta: model = User @@ -98,18 +100,22 @@ class SupermarketCategoryFactory(factory.django.DjangoModelFactory): class FoodFactory(factory.django.DjangoModelFactory): """Food factory.""" name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)[:128]) - plural_name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) + plural_name = factory.LazyAttribute( + lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) supermarket_category = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_category), - yes_declaration=factory.SubFactory(SupermarketCategoryFactory, space=factory.SelfAttribute('..space')), + factory.LazyAttribute(lambda x: x.has_category), + yes_declaration=factory.SubFactory( + SupermarketCategoryFactory, space=factory.SelfAttribute('..space')), no_declaration=None ) recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + factory.LazyAttribute(lambda x: x.has_recipe), + yes_declaration=factory.SubFactory( + 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), no_declaration=None ) + path = None space = factory.SubFactory(SpaceFactory) @factory.post_generation @@ -127,17 +133,19 @@ class FoodFactory(factory.django.DjangoModelFactory): class Meta: model = 'cookbook.Food' - django_get_or_create = ('name', 'plural_name', 'space',) + django_get_or_create = ('name', 'plural_name', 'path', 'space',) @register class RecipeBookFactory(factory.django.DjangoModelFactory): """RecipeBook factory.""" - name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) + name = factory.LazyAttribute(lambda x: faker.sentence( + nb_words=3, variable_nb_words=False)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) icon = None # shared = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) filter = None space = factory.SubFactory(SpaceFactory) @@ -149,7 +157,8 @@ class RecipeBookFactory(factory.django.DjangoModelFactory): @register class RecipeBookEntryFactory(factory.django.DjangoModelFactory): """RecipeBookEntry factory.""" - book = factory.SubFactory(RecipeBookFactory, space=factory.SelfAttribute('..recipe.space')) + book = factory.SubFactory( + RecipeBookFactory, space=factory.SelfAttribute('..recipe.space')) recipe = None class Meta: @@ -173,7 +182,8 @@ class UnitFactory(factory.django.DjangoModelFactory): @register class KeywordFactory(factory.django.DjangoModelFactory): """Keyword factory.""" - name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=2, variable_nb_words=False)) + name = factory.LazyAttribute(lambda x: faker.sentence( + nb_words=2, variable_nb_words=False)) # icon = models.CharField(max_length=16, blank=True, null=True) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) space = factory.SubFactory(SpaceFactory) @@ -184,15 +194,17 @@ class KeywordFactory(factory.django.DjangoModelFactory): class Meta: model = 'cookbook.Keyword' - django_get_or_create = ('name', 'space',) + django_get_or_create = ('name', 'space') exclude = ('num') @register class IngredientFactory(factory.django.DjangoModelFactory): """Ingredient factory.""" - food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) - unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space')) + food = factory.SubFactory( + FoodFactory, space=factory.SelfAttribute('..space')) + unit = factory.SubFactory( + UnitFactory, space=factory.SelfAttribute('..space')) amount = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10)) note = factory.LazyAttribute(lambda x: faker.sentence(nb_words=8)) is_header = False @@ -210,7 +222,8 @@ class MealTypeFactory(factory.django.DjangoModelFactory): # icon = color = factory.LazyAttribute(lambda x: faker.safe_hex_color()) default = False - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) space = factory.SubFactory(SpaceFactory) class Meta: @@ -221,13 +234,17 @@ class MealTypeFactory(factory.django.DjangoModelFactory): class MealPlanFactory(factory.django.DjangoModelFactory): recipe = factory.Maybe( factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + yes_declaration=factory.SubFactory( + 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), no_declaration=None ) - servings = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=1000)/100)) + servings = factory.LazyAttribute( + lambda x: Decimal(faker.random_int(min=1, max=1000) / 100)) title = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - meal_type = factory.SubFactory(MealTypeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) + meal_type = factory.SubFactory( + MealTypeFactory, space=factory.SelfAttribute('..space')) note = factory.LazyAttribute(lambda x: faker.paragraph()) date = factory.LazyAttribute(lambda x: faker.future_date()) space = factory.SubFactory(SpaceFactory) @@ -243,12 +260,14 @@ class MealPlanFactory(factory.django.DjangoModelFactory): class ShoppingListRecipeFactory(factory.django.DjangoModelFactory): name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + factory.LazyAttribute(lambda x: x.has_recipe), + yes_declaration=factory.SubFactory( + 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), no_declaration=None ) servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10)) - mealplan = factory.SubFactory(MealPlanFactory, space=factory.SelfAttribute('..space')) + mealplan = factory.SubFactory( + MealPlanFactory, space=factory.SelfAttribute('..space')) space = factory.SubFactory(SpaceFactory) class Params: @@ -263,26 +282,33 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory): """ShoppingListEntry factory.""" list_recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_mealplan), - yes_declaration=factory.SubFactory(ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')), + factory.LazyAttribute(lambda x: x.has_mealplan), + yes_declaration=factory.SubFactory( + ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')), no_declaration=None ) - food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) - unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space')) + food = factory.SubFactory( + FoodFactory, space=factory.SelfAttribute('..space')) + unit = factory.SubFactory( + UnitFactory, space=factory.SelfAttribute('..space')) # # ingredient = factory.SubFactory(IngredientFactory) - amount = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=100))/10) + amount = factory.LazyAttribute( + lambda x: Decimal(faker.random_int(min=1, max=100)) / 10) order = factory.Sequence(int) checked = False - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) created_at = factory.LazyAttribute(lambda x: faker.past_date()) completed_at = None delay_until = None space = factory.SubFactory(SpaceFactory) @classmethod - def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date + # override create to prevent auto_add_now from changing the created_at date + def _create(cls, target_class, *args, **kwargs): created_at = kwargs.pop('created_at', None) - obj = super(ShoppingListEntryFactory, cls)._create(target_class, *args, **kwargs) + obj = super(ShoppingListEntryFactory, cls)._create( + target_class, *args, **kwargs) if created_at is not None: obj.created_at = created_at obj.save() @@ -298,7 +324,8 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory): @register class StepFactory(factory.django.DjangoModelFactory): name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) - instruction = factory.LazyAttribute(lambda x: ''.join(faker.paragraphs(nb=5))) + instruction = factory.LazyAttribute( + lambda x: ''.join(faker.paragraphs(nb=5))) # TODO add optional recipe food, make dependent on recipe, make number of recipes a Params ingredients__count = 10 # default number of ingredients to add ingredients__header = 0 @@ -330,14 +357,16 @@ class StepFactory(factory.django.DjangoModelFactory): for i in range(num_ing): if num_food_recipe > 0: has_recipe = True - num_food_recipe = num_food_recipe-1 + num_food_recipe = num_food_recipe - 1 else: has_recipe = False - self.ingredients.add(IngredientFactory(space=self.space, food__has_recipe=has_recipe)) + self.ingredients.add(IngredientFactory( + space=self.space, food__has_recipe=has_recipe)) num_header = kwargs.get('header', 0) if num_header > 0: for i in range(num_header): - self.ingredients.add(IngredientFactory(food=None, unit=None, amount=0, is_header=True, space=self.space)) + self.ingredients.add(IngredientFactory( + food=None, unit=None, amount=0, is_header=True, space=self.space)) elif extracted: for ing in extracted: self.ingredients.add(ing) @@ -351,20 +380,27 @@ class RecipeFactory(factory.django.DjangoModelFactory): name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=7)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=20)) - servings_text = factory.LazyAttribute(lambda x: faker.sentence(nb_words=1)) # TODO generate list of expected servings text that can be iterated through + # TODO generate list of expected servings text that can be iterated through + servings_text = factory.LazyAttribute(lambda x: faker.sentence(nb_words=1)) keywords__count = 5 # default number of keywords to generate steps__count = 1 # default number of steps to create steps__recipe_count = 0 # default number of step recipes to create - steps__food_recipe_count = {} # by default, don't create food recipes, to override {'steps__food_recipe_count': {'step': 0, 'count': 1}} - working_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) - waiting_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) + # by default, don't create food recipes, to override {'steps__food_recipe_count': {'step': 0, 'count': 1}} + steps__food_recipe_count = {} + working_time = factory.LazyAttribute( + lambda x: faker.random_int(min=0, max=360)) + waiting_time = factory.LazyAttribute( + lambda x: faker.random_int(min=0, max=360)) internal = False - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=date(2000, 1, 1), date_end=date(2020, 12, 31))) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) + created_at = factory.LazyAttribute(lambda x: faker.date_between_dates( + date_start=date(2000, 1, 1), date_end=date(2020, 12, 31))) space = factory.SubFactory(SpaceFactory) @classmethod - def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date + # override create to prevent auto_add_now from changing the created_at date + def _create(cls, target_class, *args, **kwargs): created_at = kwargs.pop('created_at', None) # updated_at = kwargs.pop('updated_at', None) obj = super(RecipeFactory, cls)._create(target_class, *args, **kwargs) @@ -401,11 +437,13 @@ class RecipeFactory(factory.django.DjangoModelFactory): ing_recipe_count = 0 if food_recipe_count.get('step', None) == i: ing_recipe_count = food_recipe_count.get('count', 0) - self.steps.add(StepFactory(space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers)) - num_ing_headers+-1 + self.steps.add(StepFactory( + space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers)) + num_ing_headers + - 1 if num_recipe_steps > 0: for j in range(num_recipe_steps): - self.steps.add(StepFactory(space=self.space, step_recipe__has_recipe=True, ingredients__count=0)) + self.steps.add(StepFactory( + space=self.space, step_recipe__has_recipe=True, ingredients__count=0)) if extracted and (num_steps + num_recipe_steps == 0): for step in extracted: self.steps.add(step) @@ -428,15 +466,18 @@ class RecipeFactory(factory.django.DjangoModelFactory): @register class CookLogFactory(factory.django.DjangoModelFactory): """CookLog factory.""" - recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + recipe = factory.SubFactory( + RecipeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) created_at = factory.LazyAttribute(lambda x: faker.date_this_decade()) rating = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=5)) servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=32)) space = factory.SubFactory(SpaceFactory) @classmethod - def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date + # override create to prevent auto_add_now from changing the created_at date + def _create(cls, target_class, *args, **kwargs): created_at = kwargs.pop('created_at', None) obj = super(CookLogFactory, cls)._create(target_class, *args, **kwargs) if created_at is not None: @@ -451,13 +492,17 @@ class CookLogFactory(factory.django.DjangoModelFactory): @register class ViewLogFactory(factory.django.DjangoModelFactory): """ViewLog factory.""" - recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.past_datetime(start_date='-365d')) + recipe = factory.SubFactory( + RecipeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory( + UserFactory, space=factory.SelfAttribute('..space')) + created_at = factory.LazyAttribute( + lambda x: faker.past_datetime(start_date='-365d')) space = factory.SubFactory(SpaceFactory) @classmethod - def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date + # override create to prevent auto_add_now from changing the created_at date + def _create(cls, target_class, *args, **kwargs): created_at = kwargs.pop('created_at', None) obj = super(ViewLogFactory, cls)._create(target_class, *args, **kwargs) if created_at is not None: diff --git a/cookbook/tests/other/test_recipe_full_text_search.py b/cookbook/tests/other/test_recipe_full_text_search.py index d2159720..60ca6162 100644 --- a/cookbook/tests/other/test_recipe_full_text_search.py +++ b/cookbook/tests/other/test_recipe_full_text_search.py @@ -259,33 +259,35 @@ def test_fuzzy_lookup(found_recipe, recipes, param_type, user1, space_1): # commenting this out for general use - it is really slow # it should be run on occasion to ensure everything still works -# @pytest.mark.skipif(sqlite and True, reason="requires PostgreSQL") -# @pytest.mark.parametrize("user1", itertools.product( -# [ -# ('fuzzy_search', True), ('fuzzy_search', False), -# ('fulltext', True), ('fulltext', False), -# ('icontains', True), ('icontains', False), -# ('istartswith', True), ('istartswith', False), -# ], -# [('unaccent', True), ('unaccent', False)] -# ), indirect=['user1']) -# @pytest.mark.parametrize("found_recipe", [ -# ({'name': True}), -# ({'description': True}), -# ({'instruction': True}), -# ({'keyword': True}), -# ({'food': True}), -# ], indirect=['found_recipe']) -# def test_search_string(found_recipe, recipes, user1, space_1): -# with scope(space=space_1): -# param1 = f"query={user1[3]}" -# param2 = f"query={user1[4]}" -# r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param1}').content) -# assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[1] -# r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param2}').content) -# assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[2] +@pytest.mark.skipif(sqlite and True, reason="requires PostgreSQL") +@pytest.mark.parametrize("user1", itertools.product( + [ + ('fuzzy_search', True), ('fuzzy_search', False), + ('fulltext', True), ('fulltext', False), + ('icontains', True), ('icontains', False), + ('istartswith', True), ('istartswith', False), + ], + [('unaccent', True), ('unaccent', False)] +), indirect=['user1']) +@pytest.mark.parametrize("found_recipe", [ + ({'name': True}), + ({'description': True}), + ({'instruction': True}), + ({'keyword': True}), + ({'food': True}), +], indirect=['found_recipe']) +def test_search_string(found_recipe, recipes, user1, space_1): + with scope(space=space_1): + param1 = f"query={user1[3]}" + param2 = f"query={user1[4]}" + + r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param1}').content) + assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[1] + + r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param2}').content) + assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[2] @pytest.mark.parametrize("found_recipe, param_type, result", [ @@ -322,33 +324,33 @@ def test_search_date(found_recipe, recipes, param_type, result, u1_s1, u2_s1, sp # TODO this is somehow screwed, probably the search itself, dont want to fix it for now -# @pytest.mark.parametrize("found_recipe, param_type", [ -# ({'rating': True}, 'rating'), -# ({'timescooked': True}, 'timescooked'), -# ], indirect=['found_recipe']) -# def test_search_count(found_recipe, recipes, param_type, u1_s1, u2_s1, space_1): -# param1 = f'?{param_type}=3' -# param2 = f'?{param_type}=-3' -# param3 = f'?{param_type}=0' -# -# r = json.loads(u1_s1.get(reverse(LIST_URL) + param1).content) -# assert r['count'] == 1 -# assert found_recipe[0].id in [x['id'] for x in r['results']] -# -# r = json.loads(u1_s1.get(reverse(LIST_URL) + param2).content) -# assert r['count'] == 1 -# assert found_recipe[1].id in [x['id'] for x in r['results']] -# -# # test search for not rated/cooked -# r = json.loads(u1_s1.get(reverse(LIST_URL) + param3).content) -# assert r['count'] == 11 -# assert (found_recipe[0].id or found_recipe[1].id) not in [x['id'] for x in r['results']] -# -# # test matched returns for lte and gte searches -# r = json.loads(u2_s1.get(reverse(LIST_URL) + param1).content) -# assert r['count'] == 1 -# assert found_recipe[2].id in [x['id'] for x in r['results']] -# -# r = json.loads(u2_s1.get(reverse(LIST_URL) + param2).content) -# assert r['count'] == 1 -# assert found_recipe[2].id in [x['id'] for x in r['results']] +@pytest.mark.parametrize("found_recipe, param_type", [ + ({'rating': True}, 'rating'), + ({'timescooked': True}, 'timescooked'), +], indirect=['found_recipe']) +def test_search_count(found_recipe, recipes, param_type, u1_s1, u2_s1, space_1): + param1 = f'?{param_type}=3' + param2 = f'?{param_type}=-3' + param3 = f'?{param_type}=0' + + r = json.loads(u1_s1.get(reverse(LIST_URL) + param1).content) + assert r['count'] == 1 + assert found_recipe[0].id in [x['id'] for x in r['results']] + + r = json.loads(u1_s1.get(reverse(LIST_URL) + param2).content) + assert r['count'] == 1 + assert found_recipe[1].id in [x['id'] for x in r['results']] + + # test search for not rated/cooked + r = json.loads(u1_s1.get(reverse(LIST_URL) + param3).content) + assert r['count'] == 11 + assert (found_recipe[0].id or found_recipe[1].id) not in [x['id'] for x in r['results']] + + # test matched returns for lte and gte searches + r = json.loads(u2_s1.get(reverse(LIST_URL) + param1).content) + assert r['count'] == 1 + assert found_recipe[2].id in [x['id'] for x in r['results']] + + r = json.loads(u2_s1.get(reverse(LIST_URL) + param2).content) + assert r['count'] == 1 + assert found_recipe[2].id in [x['id'] for x in r['results']] diff --git a/requirements.txt b/requirements.txt index 8500be06..6f27ed80 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,11 +30,11 @@ Jinja2==3.1.2 django-webpack-loader==1.8.1 git+https://github.com/BITSOLVER/django-js-reverse@071e304fd600107bc64bbde6f2491f1fe049ec82 django-allauth==0.52.0 -recipe-scrapers==14.35.0 +recipe-scrapers==14.36.1 django-scopes==1.2.0.post1 -pytest==7.2.2 +pytest==7.3.1 pytest-django==4.5.2 -django-treebeard==4.5.1 +django-treebeard==4.7 django-cors-headers==3.13.0 django-storages==1.13.2 boto3==1.26.41 @@ -42,7 +42,7 @@ django-prometheus==2.2.0 django-hCaptcha==0.2.0 python-ldap==3.4.3 django-auth-ldap==4.2.0 -pytest-factoryboy==2.5.0 +pytest-factoryboy==2.5.1 pyppeteer==1.0.2 validators==0.20.0 -pytube==12.1.0 \ No newline at end of file +pytube==12.1.0 diff --git a/vue/src/components/IngredientComponent.vue b/vue/src/components/IngredientComponent.vue index 7749c9de..1998ceab 100644 --- a/vue/src/components/IngredientComponent.vue +++ b/vue/src/components/IngredientComponent.vue @@ -12,18 +12,17 @@ - +