fix food tests
This commit is contained in:
parent
8a8be7fb2d
commit
8c3195937b
@ -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
|
||||
@ -373,6 +388,8 @@ def test_merge_shopping_entries(obj_tree_1, u1_s1, 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
|
||||
|
@ -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,9 +55,12 @@ 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):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
@ -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
|
||||
|
@ -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')),
|
||||
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')),
|
||||
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)
|
||||
@ -244,11 +261,13 @@ 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')),
|
||||
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:
|
||||
@ -264,25 +283,32 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
list_recipe = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_mealplan),
|
||||
yes_declaration=factory.SubFactory(ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')),
|
||||
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:
|
||||
|
@ -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']]
|
||||
|
@ -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
|
@ -12,18 +12,17 @@
|
||||
<i class="far fa-check-circle text-primary" v-if="!ingredient.checked"></i>
|
||||
</td>
|
||||
<td class="text-nowrap" @click="done">
|
||||
<span v-if="ingredient.amount !== 0 && !ingredient.no_amount"
|
||||
v-html="calculateAmount(ingredient.amount)"></span>
|
||||
<span v-if="ingredient.amount !== 0 && !ingredient.no_amount" v-html="calculateAmount(ingredient.amount)"></span>
|
||||
</td>
|
||||
<td @click="done">
|
||||
<template v-if="ingredient.unit !== null && !ingredient.no_amount">
|
||||
<template >
|
||||
<template>
|
||||
<template v-if="ingredient.unit.plural_name === '' || ingredient.unit.plural_name === null">
|
||||
<span>{{ ingredient.unit.name }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="ingredient.always_use_plural_unit">{{ ingredient.unit.plural_name}}</span>
|
||||
<span v-else-if="(ingredient.amount * this.ingredient_factor) > 1">{{ ingredient.unit.plural_name }}</span>
|
||||
<span v-if="ingredient.always_use_plural_unit">{{ ingredient.unit.plural_name }}</span>
|
||||
<span v-else-if="ingredient.amount * this.ingredient_factor > 1">{{ ingredient.unit.plural_name }}</span>
|
||||
<span v-else>{{ ingredient.unit.name }}</span>
|
||||
</template>
|
||||
</template>
|
||||
@ -31,11 +30,10 @@
|
||||
</td>
|
||||
<td @click="done">
|
||||
<template v-if="ingredient.food !== null">
|
||||
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)"
|
||||
v-if="ingredient.food.recipe !== null" target="_blank"
|
||||
rel="noopener noreferrer">{{ ingredient.food.name }}</a>
|
||||
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)" v-if="ingredient.food.recipe !== null" target="_blank" rel="noopener noreferrer">{{
|
||||
ingredient.food.name
|
||||
}}</a>
|
||||
<template v-if="ingredient.food.recipe === null">
|
||||
|
||||
<template>
|
||||
<template v-if="ingredient.food.plural_name === '' || ingredient.food.plural_name === null">
|
||||
<span>{{ ingredient.food.name }}</span>
|
||||
@ -43,7 +41,7 @@
|
||||
<template v-else>
|
||||
<span v-if="ingredient.always_use_plural_food">{{ ingredient.food.plural_name }}</span>
|
||||
<span v-else-if="ingredient.no_amount">{{ ingredient.food.name }}</span>
|
||||
<span v-else-if="(ingredient.amount * this.ingredient_factor) > 1">{{ ingredient.food.plural_name }}</span>
|
||||
<span v-else-if="ingredient.amount * this.ingredient_factor > 1">{{ ingredient.food.plural_name }}</span>
|
||||
<span v-else>{{ ingredient.food.name }}</span>
|
||||
</template>
|
||||
</template>
|
||||
@ -56,10 +54,7 @@
|
||||
<i class="far fa-comment"></i>
|
||||
</span>
|
||||
|
||||
<div class="d-none d-print-block"><i class="far fa-comment-alt d-print-none"></i> {{
|
||||
ingredient.note
|
||||
}}
|
||||
</div>
|
||||
<div class="d-none d-print-block"><i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }}</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
@ -67,19 +62,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {calculateAmount, ResolveUrlMixin} from "@/utils/utils"
|
||||
import { calculateAmount, ResolveUrlMixin } from "@/utils/utils"
|
||||
|
||||
import Vue from "vue"
|
||||
import VueSanitize from "vue-sanitize";
|
||||
import VueSanitize from "vue-sanitize"
|
||||
|
||||
Vue.use(VueSanitize);
|
||||
Vue.use(VueSanitize)
|
||||
|
||||
export default {
|
||||
name: "IngredientComponent",
|
||||
props: {
|
||||
ingredient: Object,
|
||||
ingredient_factor: {type: Number, default: 1},
|
||||
detailed: {type: Boolean, default: true},
|
||||
ingredient_factor: { type: Number, default: 1 },
|
||||
detailed: { type: Boolean, default: true },
|
||||
},
|
||||
mixins: [ResolveUrlMixin],
|
||||
data() {
|
||||
@ -88,9 +83,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
calculateAmount: function (x) {
|
||||
return this.$sanitize(calculateAmount(x, this.ingredient_factor))
|
||||
@ -107,8 +100,8 @@ export default {
|
||||
/* increase size of hover/touchable space without changing spacing */
|
||||
.touchable {
|
||||
padding-right: 2em;
|
||||
padding-left: 2em;
|
||||
margin-right: -2em;
|
||||
padding-left: 3em;
|
||||
margin-right: -3em;
|
||||
margin-left: -2em;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user