Skip to content

Commit 83b4c1a

Browse files
committed
Added tests for the backend API
1 parent 677cdbf commit 83b4c1a

File tree

8 files changed

+560
-0
lines changed

8 files changed

+560
-0
lines changed

backend/tests/api/__init__.py

Whitespace-only changes.

backend/tests/api/conftest.py

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import pytest
2+
from app import app, db
3+
4+
5+
@pytest.fixture
6+
def client():
7+
app_context = app.app_context()
8+
app_context.push()
9+
app.config['TESTING'] = True
10+
db.create_all()
11+
client = app.test_client()
12+
yield client
13+
db.session.rollback()
14+
db.drop_all()
15+
app_context.pop()
16+
17+
18+
@pytest.fixture
19+
def username():
20+
return "testuser"
21+
22+
23+
@pytest.fixture
24+
def name():
25+
return "testname"
26+
27+
28+
@pytest.fixture
29+
def password():
30+
return "testpwd"
31+
32+
33+
@pytest.fixture
34+
def admin_username():
35+
return "testadmin"
36+
37+
38+
@pytest.fixture
39+
def admin_name():
40+
return "adminname"
41+
42+
43+
@pytest.fixture
44+
def admin_password():
45+
return "adminpwd"
46+
47+
48+
@pytest.fixture
49+
def household_name():
50+
return "testhousehold"
51+
52+
53+
@pytest.fixture
54+
def item_name():
55+
return "testitem"
56+
57+
@pytest.fixture
58+
def recipe_name():
59+
return "Test Recipe"
60+
61+
@pytest.fixture
62+
def recipe_description():
63+
return "A test recipe description"
64+
65+
@pytest.fixture
66+
def recipe_yields():
67+
return 4
68+
69+
@pytest.fixture
70+
def recipe_time():
71+
return 30
72+
73+
74+
@pytest.fixture
75+
def onboarded_client(client, admin_username, admin_name, admin_password):
76+
onboard_data = {
77+
'username': admin_username,
78+
'name': admin_name,
79+
'password': admin_password
80+
}
81+
response = client.post('/api/onboarding', json=onboard_data)
82+
return client
83+
84+
85+
@pytest.fixture
86+
def admin_client(client, admin_username, admin_name, admin_password):
87+
onboard_data = {
88+
'username': admin_username,
89+
'name': admin_name,
90+
'password': admin_password
91+
}
92+
response = client.post('/api/onboarding', json=onboard_data)
93+
data = response.get_json()
94+
client.environ_base['HTTP_AUTHORIZATION'] = f'Bearer {data["access_token"]}'
95+
return client
96+
97+
98+
@pytest.fixture
99+
def user_client(admin_client, username, name, password):
100+
data = {
101+
'username': username,
102+
'name': name,
103+
'password': password
104+
}
105+
response = admin_client.post('/api/user/new', json=data)
106+
data = {
107+
'username': username,
108+
'password': password
109+
}
110+
response = admin_client.post('/api/auth', json=data)
111+
data = response.get_json()
112+
admin_client.environ_base['HTTP_AUTHORIZATION'] = f'Bearer {data["access_token"]}'
113+
return admin_client
114+
115+
116+
@pytest.fixture
117+
def user_client_with_household(user_client, household_name):
118+
response = user_client.get('/api/user',)
119+
assert response.status_code == 200
120+
data = response.get_json()
121+
user_id = data['id']
122+
data = {
123+
'name': household_name,
124+
'member': [user_id]
125+
}
126+
response = user_client.post('/api/household', json=data)
127+
return user_client
128+
129+
130+
@pytest.fixture
131+
def household_id(user_client_with_household):
132+
response = user_client_with_household.get('/api/household',)
133+
assert response.status_code == 200
134+
data = response.get_json()
135+
assert len(data) == 1
136+
assert "id" in data[0]
137+
return data[0]["id"]
138+
139+
140+
@pytest.fixture
141+
def shoppinglist_id(user_client_with_household, household_id):
142+
response = user_client_with_household.get(
143+
f'/api/household/{household_id}/shoppinglist',)
144+
assert response.status_code == 200
145+
data = response.get_json()
146+
assert len(data) == 1
147+
assert "id" in data[0]
148+
return data[0]["id"]
149+
150+
151+
@pytest.fixture
152+
def shoppinglist_id_with_item(user_client_with_household, shoppinglist_id, item_name):
153+
data = {"name": item_name}
154+
response = user_client_with_household.post(
155+
f'/api/shoppinglist/{shoppinglist_id}/add-item-by-name', json=data)
156+
assert response.status_code == 200
157+
return shoppinglist_id
158+
159+
160+
@pytest.fixture
161+
def item_id(user_client_with_household, shoppinglist_id_with_item):
162+
response = user_client_with_household.get(
163+
f'/api/shoppinglist/{shoppinglist_id_with_item}/items')
164+
assert response.status_code == 200
165+
data = response.get_json()
166+
assert len(data) == 1
167+
assert "id" in data[0]
168+
return data[0]["id"]
169+
170+
@pytest.fixture
171+
def recipe_with_items(user_client_with_household, household_id, recipe_name, recipe_description, recipe_yields, recipe_time, item_name):
172+
# Create recipe with the item
173+
recipe_data = {
174+
'name': recipe_name,
175+
'description': recipe_description,
176+
'yields': recipe_yields,
177+
'time': recipe_time,
178+
'items': [{'name': item_name, 'description': '2 pieces'}]
179+
}
180+
181+
response = user_client_with_household.post(
182+
f'/api/household/{household_id}/recipe',
183+
json=recipe_data
184+
)
185+
assert response.status_code == 200
186+
recipe = response.get_json()
187+
assert 'id' in recipe
188+
return recipe['id']
189+
190+
@pytest.fixture
191+
def planned_recipe(user_client_with_household, household_id, recipe_with_items):
192+
"""Fixture that creates a meal plan with the test recipe"""
193+
plan_data = {
194+
'recipe_id': recipe_with_items,
195+
'day': 0 # Plan for today
196+
}
197+
response = user_client_with_household.post(
198+
f'/api/household/{household_id}/planner/recipe',
199+
json=plan_data
200+
)
201+
assert response.status_code == 200
202+
203+
# Verify plan was created
204+
response = user_client_with_household.get(
205+
f'/api/household/{household_id}/planner'
206+
)
207+
assert response.status_code == 200
208+
planned_meals = response.get_json()
209+
assert len(planned_meals) > 0
210+
assert any(meal['recipe']['id'] == recipe_with_items for meal in planned_meals)
211+
212+
return recipe_with_items # Return recipe_id for convenience
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import pytest
2+
3+
4+
def test_get_all_households_empty(admin_client):
5+
response = admin_client.get('/api/household',)
6+
assert response.status_code == 200
7+
data = response.get_json()
8+
assert len(data) == 0
9+
10+
11+
def test_add_household_admin(admin_client, household_name):
12+
response = admin_client.get('/api/user',)
13+
assert response.status_code == 200
14+
data = response.get_json()
15+
admin_user_id = data['id']
16+
data = {
17+
'name': household_name,
18+
'member': [admin_user_id]
19+
}
20+
response = admin_client.post('/api/household', json=data)
21+
assert response.status_code == 200
22+
23+
24+
def test_add_household_user(user_client, household_name):
25+
response = user_client.get('/api/user',)
26+
assert response.status_code == 200
27+
data = response.get_json()
28+
user_id = data['id']
29+
data = {
30+
'name': household_name,
31+
'member': [user_id]
32+
}
33+
response = user_client.post('/api/household', json=data)
34+
assert response.status_code == 200
35+
36+
37+
def test_get_all_households(user_client_with_household, household_name):
38+
response = user_client_with_household.get('/api/household',)
39+
assert response.status_code == 200
40+
data = response.get_json()
41+
assert len(data) == 1
42+
assert data[0]["name"] == household_name
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
3+
4+
def test_onboarding_status_true(client):
5+
response = client.get('/api/onboarding',)
6+
assert response.status_code == 200
7+
data = response.get_json()
8+
assert "onboarding" in data
9+
assert data["onboarding"] == True
10+
11+
12+
def test_onboarding_status_false(onboarded_client):
13+
response = onboarded_client.get('/api/onboarding',)
14+
assert response.status_code == 200
15+
data = response.get_json()
16+
assert "onboarding" in data
17+
assert data["onboarding"] == False
18+
19+
20+
def test_onboarding(client, admin_username, admin_name, admin_password):
21+
onboard_data = {
22+
'username': admin_username,
23+
'name': admin_name,
24+
'password': admin_password
25+
}
26+
response = client.post('/api/onboarding', json=onboard_data)
27+
assert response.status_code == 200
28+
data = response.get_json()
29+
assert "access_token" in data
30+
assert "refresh_token" in data

backend/tests/api/test_api_planner.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
def test_meal_planning_basic(user_client_with_household, household_id, planned_recipe):
2+
"""Test basic meal planning operations"""
3+
# Get planned meals and verify the recipe is there
4+
response = user_client_with_household.get(
5+
f'/api/household/{household_id}/planner'
6+
)
7+
assert response.status_code == 200
8+
planned_meals = response.get_json()
9+
assert len(planned_meals) > 0
10+
assert any(meal['recipe']['id'] == planned_recipe for meal in planned_meals)
11+
12+
13+
def test_meal_planning_remove(user_client_with_household, household_id, planned_recipe):
14+
"""Test removing meals from plan"""
15+
# Remove from meal plan
16+
response = user_client_with_household.delete(
17+
f'/api/household/{household_id}/planner/recipe/{planned_recipe}',
18+
json={'day': 0}
19+
)
20+
assert response.status_code == 200
21+
22+
# Verify removal
23+
response = user_client_with_household.get(
24+
f'/api/household/{household_id}/planner'
25+
)
26+
assert response.status_code == 200
27+
planned_meals = response.get_json()
28+
assert not any(meal['recipe']['id'] == planned_recipe for meal in planned_meals)
29+
30+
31+
def test_recent_planned_recipes(user_client_with_household, household_id, planned_recipe):
32+
"""Test getting recently planned recipes"""
33+
# First remove the recipe from the plan
34+
response = user_client_with_household.delete(
35+
f'/api/household/{household_id}/planner/recipe/{planned_recipe}',
36+
json={'day': 0}
37+
)
38+
assert response.status_code == 200
39+
40+
# Now get recent recipes - should include our recently dropped recipe
41+
response = user_client_with_household.get(
42+
f'/api/household/{household_id}/planner/recent-recipes'
43+
)
44+
assert response.status_code == 200
45+
recent_recipes = response.get_json()
46+
assert len(recent_recipes) > 0
47+
assert any(recipe['id'] == planned_recipe for recipe in recent_recipes)
48+
49+
50+
def test_suggested_recipes(user_client_with_household, household_id, recipe_with_items):
51+
"""Test recipe suggestions functionality"""
52+
# Get suggested recipes
53+
response = user_client_with_household.get(
54+
f'/api/household/{household_id}/planner/suggested-recipes'
55+
)
56+
assert response.status_code == 200
57+
suggested_recipes = response.get_json()
58+
assert isinstance(suggested_recipes, list) # Should return a list, even if empty
59+
60+
# Refresh suggestions
61+
response = user_client_with_household.get(
62+
f'/api/household/{household_id}/planner/refresh-suggested-recipes'
63+
)
64+
assert response.status_code == 200
65+
refreshed_suggestions = response.get_json()
66+
assert isinstance(refreshed_suggestions, list)

0 commit comments

Comments
 (0)