1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-02 20:15:24 +02:00

chore: file generation cleanup (#1736)

This PR does too many things :( 

1. Major refactoring of the dev/scripts and dev/code-generation folders. 

Primarily this was removing duplicate code and cleaning up some poorly written code snippets as well as making them more idempotent so then can be re-run over and over again but still maintain the same results. This is working on my machine, but I've been having problems in CI and comparing diffs so running generators in CI will have to wait. 

2. Re-Implement using the generated api routes for testing

This was a _huge_ refactor that touched damn near every test file but now we have auto-generated typed routes with inline hints and it's used for nearly every test excluding a few that use classes for better parameterization. This should greatly reduce errors when writing new tests. 

3. Minor Perf improvements for the All Recipes endpoint

  A. Removed redundant loops
  B. Uses orjson to do the encoding directly and returns a byte response instead of relying on the default 
       jsonable_encoder.

4. Fix some TS type errors that cropped up for seemingly no reason half way through the PR.

See this issue https://github.com/phillipdupuis/pydantic-to-typescript/issues/28

Basically, the generated TS type is not-correct since Pydantic will automatically fill in null fields. The resulting TS type is generated with a ? to indicate it can be null even though we _know_ that i can't be.
This commit is contained in:
Hayden 2022-10-18 14:49:41 -08:00 committed by GitHub
parent a8f0fb14a7
commit 9ecef4c25f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
107 changed files with 2520 additions and 1948 deletions

View file

@ -9,18 +9,12 @@ from pydantic import UUID4
from mealie.repos.repository_factory import AllRepositories
from mealie.schema.cookbook.cookbook import ReadCookBook, SaveCookBook
from tests import utils
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/cookbooks"
def item(item_id: int) -> str:
return f"{Routes.base}/{item_id}"
def get_page_data(group_id: UUID):
def get_page_data(group_id: UUID | str):
name_and_slug = random_string(10)
return {
"name": name_and_slug,
@ -60,13 +54,13 @@ def cookbooks(database: AllRepositories, unique_user: TestUser) -> list[TestCook
def test_create_cookbook(api_client: TestClient, unique_user: TestUser):
page_data = get_page_data(unique_user.group_id)
response = api_client.post(Routes.base, json=page_data, headers=unique_user.token)
response = api_client.post(api_routes.groups_cookbooks, json=page_data, headers=unique_user.token)
assert response.status_code == 201
def test_read_cookbook(api_client: TestClient, unique_user: TestUser, cookbooks: list[TestCookbook]):
sample = random.choice(cookbooks)
response = api_client.get(Routes.item(sample.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_cookbooks_item_id(sample.id), headers=unique_user.token)
assert response.status_code == 200
page_data = response.json()
@ -84,10 +78,12 @@ def test_update_cookbook(api_client: TestClient, unique_user: TestUser, cookbook
update_data["name"] = random_string(10)
response = api_client.put(Routes.item(cookbook.id), json=update_data, headers=unique_user.token)
response = api_client.put(
api_routes.groups_cookbooks_item_id(cookbook.id), json=update_data, headers=unique_user.token
)
assert response.status_code == 200
response = api_client.get(Routes.item(cookbook.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_cookbooks_item_id(cookbook.id), headers=unique_user.token)
assert response.status_code == 200
page_data = response.json()
@ -103,10 +99,10 @@ def test_update_cookbooks_many(api_client: TestClient, unique_user: TestUser, co
page["position"] = x
page["group_id"] = str(unique_user.group_id)
response = api_client.put(Routes.base, json=utils.jsonify(reverse_order), headers=unique_user.token)
response = api_client.put(api_routes.groups_cookbooks, json=utils.jsonify(reverse_order), headers=unique_user.token)
assert response.status_code == 200
response = api_client.get(Routes.base, headers=unique_user.token)
response = api_client.get(api_routes.groups_cookbooks, headers=unique_user.token)
assert response.status_code == 200
known_ids = [x.id for x in cookbooks]
@ -119,9 +115,9 @@ def test_update_cookbooks_many(api_client: TestClient, unique_user: TestUser, co
def test_delete_cookbook(api_client: TestClient, unique_user: TestUser, cookbooks: list[TestCookbook]):
sample = random.choice(cookbooks)
response = api_client.delete(Routes.item(sample.id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_cookbooks_item_id(sample.id), headers=unique_user.token)
assert response.status_code == 200
response = api_client.get(Routes.item(sample.slug), headers=unique_user.token)
response = api_client.get(api_routes.groups_cookbooks_item_id(sample.slug), headers=unique_user.token)
assert response.status_code == 404

View file

@ -1,25 +1,15 @@
import pytest
from fastapi.testclient import TestClient
from tests.utils import api_routes
from tests.utils.factories import user_registration_factory
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/invitations"
auth_token = "/api/auth/token"
self = "/api/users/self"
register = "/api/users/register"
def item(item_id: int) -> str:
return f"{Routes.base}/{item_id}"
@pytest.fixture(scope="function")
def invite(api_client: TestClient, unique_user: TestUser) -> None:
# Test Creation
r = api_client.post(Routes.base, json={"uses": 2}, headers=unique_user.token)
r = api_client.post(api_routes.groups_invitations, json={"uses": 2}, headers=unique_user.token)
assert r.status_code == 201
invitation = r.json()
return invitation["token"]
@ -27,7 +17,7 @@ def invite(api_client: TestClient, unique_user: TestUser) -> None:
def test_get_all_invitation(api_client: TestClient, unique_user: TestUser, invite: str) -> None:
# Get All Invites
r = api_client.get(Routes.base, headers=unique_user.token)
r = api_client.get(api_routes.groups_invitations, headers=unique_user.token)
assert r.status_code == 200
@ -46,7 +36,7 @@ def register_user(api_client, invite):
registration.group = ""
registration.group_token = invite
response = api_client.post(Routes.register, json=registration.dict(by_alias=True))
response = api_client.post(api_routes.users_register, json=registration.dict(by_alias=True))
return registration, response
@ -57,13 +47,13 @@ def test_group_invitation_link(api_client: TestClient, unique_user: TestUser, in
# Login as new User
form_data = {"username": registration.email, "password": registration.password}
r = api_client.post(Routes.auth_token, form_data)
r = api_client.post(api_routes.auth_token, form_data)
assert r.status_code == 200
token = r.json().get("access_token")
assert token is not None
# Check user Group is Same
r = api_client.get(Routes.self, headers={"Authorization": f"Bearer {token}"})
r = api_client.get(api_routes.users_self, headers={"Authorization": f"Bearer {token}"})
assert r.status_code == 200
assert r.json()["groupId"] == unique_user.group_id

View file

@ -3,26 +3,13 @@ from datetime import date, timedelta
from fastapi.testclient import TestClient
from mealie.schema.meal_plan.new_meal import CreatePlanEntry
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/mealplans"
recipe = "/api/recipes"
today = "/api/groups/mealplans/today"
@staticmethod
def all_slice(page: int, perPage: int, start_date: str, end_date: str):
return f"{Routes.base}?page={page}&perPage={perPage}&start_date={start_date}&end_date={end_date}"
@staticmethod
def item(item_id: int) -> str:
return f"{Routes.base}/{item_id}"
@staticmethod
def recipe_slug(recipe_name: str) -> str:
return f"{Routes.recipe}/{recipe_name}"
def route_all_slice(page: int, perPage: int, start_date: str, end_date: str):
return f"{api_routes.groups_mealplans}?page={page}&perPage={perPage}&start_date={start_date}&end_date={end_date}"
def test_create_mealplan_no_recipe(api_client: TestClient, unique_user: TestUser):
@ -31,7 +18,7 @@ def test_create_mealplan_no_recipe(api_client: TestClient, unique_user: TestUser
new_plan = CreatePlanEntry(date=date.today(), entry_type="breakfast", title=title, text=text).dict()
new_plan["date"] = date.today().strftime("%Y-%m-%d")
response = api_client.post(Routes.base, json=new_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=new_plan, headers=unique_user.token)
assert response.status_code == 201
@ -42,10 +29,10 @@ def test_create_mealplan_no_recipe(api_client: TestClient, unique_user: TestUser
def test_create_mealplan_with_recipe(api_client: TestClient, unique_user: TestUser):
recipe_name = random_string(length=25)
response = api_client.post(Routes.recipe, json={"name": recipe_name}, headers=unique_user.token)
response = api_client.post(api_routes.recipes, json={"name": recipe_name}, headers=unique_user.token)
assert response.status_code == 201
response = api_client.get(Routes.recipe_slug(recipe_name), headers=unique_user.token)
response = api_client.get(api_routes.recipes_slug(recipe_name), headers=unique_user.token)
recipe = response.json()
recipe_id = recipe["id"]
@ -53,7 +40,7 @@ def test_create_mealplan_with_recipe(api_client: TestClient, unique_user: TestUs
new_plan["date"] = date.today().strftime("%Y-%m-%d")
new_plan["recipeId"] = str(recipe_id)
response = api_client.post(Routes.base, json=new_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=new_plan, headers=unique_user.token)
response_json = response.json()
assert response.status_code == 201
@ -70,7 +57,7 @@ def test_crud_mealplan(api_client: TestClient, unique_user: TestUser):
# Create
new_plan["date"] = date.today().strftime("%Y-%m-%d")
response = api_client.post(Routes.base, json=new_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=new_plan, headers=unique_user.token)
response_json = response.json()
assert response.status_code == 201
plan_id = response_json["id"]
@ -79,7 +66,9 @@ def test_crud_mealplan(api_client: TestClient, unique_user: TestUser):
response_json["title"] = random_string()
response_json["text"] = random_string()
response = api_client.put(Routes.item(plan_id), headers=unique_user.token, json=response_json)
response = api_client.put(
api_routes.groups_mealplans_item_id(plan_id), headers=unique_user.token, json=response_json
)
assert response.status_code == 200
@ -87,11 +76,11 @@ def test_crud_mealplan(api_client: TestClient, unique_user: TestUser):
assert response.json()["text"] == response_json["text"]
# Delete
response = api_client.delete(Routes.item(plan_id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_mealplans_item_id(plan_id), headers=unique_user.token)
assert response.status_code == 200
response = api_client.get(Routes.item(plan_id), headers=unique_user.token)
response = api_client.get(api_routes.groups_mealplans_item_id(plan_id), headers=unique_user.token)
assert response.status_code == 404
@ -106,10 +95,10 @@ def test_get_all_mealplans(api_client: TestClient, unique_user: TestUser):
).dict()
new_plan["date"] = date.today().strftime("%Y-%m-%d")
response = api_client.post(Routes.base, json=new_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=new_plan, headers=unique_user.token)
assert response.status_code == 201
response = api_client.get(Routes.base, headers=unique_user.token, params={"page": 1, "perPage": -1})
response = api_client.get(api_routes.groups_mealplans, headers=unique_user.token, params={"page": 1, "perPage": -1})
assert response.status_code == 200
assert len(response.json()["items"]) >= 3
@ -128,7 +117,7 @@ def test_get_slice_mealplans(api_client: TestClient, unique_user: TestUser):
# Add the meal plans to the database
for meal_plan in meal_plans:
meal_plan["date"] = meal_plan["date"].strftime("%Y-%m-%d")
response = api_client.post(Routes.base, json=meal_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=meal_plan, headers=unique_user.token)
assert response.status_code == 201
# Get meal slice of meal plans from database
@ -138,7 +127,7 @@ def test_get_slice_mealplans(api_client: TestClient, unique_user: TestUser):
start_date = date_range[0].strftime("%Y-%m-%d")
end_date = date_range[-1].strftime("%Y-%m-%d")
response = api_client.get(Routes.all_slice(1, -1, start_date, end_date), headers=unique_user.token)
response = api_client.get(route_all_slice(1, -1, start_date, end_date), headers=unique_user.token)
assert response.status_code == 200
response_json = response.json()
@ -157,11 +146,11 @@ def test_get_mealplan_today(api_client: TestClient, unique_user: TestUser):
# Add the meal plans to the database
for meal_plan in test_meal_plans:
meal_plan["date"] = meal_plan["date"].strftime("%Y-%m-%d")
response = api_client.post(Routes.base, json=meal_plan, headers=unique_user.token)
response = api_client.post(api_routes.groups_mealplans, json=meal_plan, headers=unique_user.token)
assert response.status_code == 201
# Get meal plan for today
response = api_client.get(Routes.today, headers=unique_user.token)
response = api_client.get(api_routes.groups_mealplans_today, headers=unique_user.token)
assert response.status_code == 200

View file

@ -2,24 +2,16 @@ from uuid import UUID
import pytest
from fastapi.testclient import TestClient
from pydantic import UUID4
from mealie.repos.all_repositories import AllRepositories
from mealie.schema.meal_plan.plan_rules import PlanRulesOut, PlanRulesSave
from mealie.schema.recipe.recipe import RecipeCategory
from mealie.schema.recipe.recipe_category import CategorySave
from tests import utils
from tests.utils import api_routes
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/mealplans/rules"
@staticmethod
def item(item_id: UUID4) -> str:
return f"{Routes.base}/{item_id}"
@pytest.fixture(scope="function")
def category(
database: AllRepositories,
@ -65,7 +57,9 @@ def test_group_mealplan_rules_create(
"categories": [category.dict()],
}
response = api_client.post(Routes.base, json=utils.jsonify(payload), headers=unique_user.token)
response = api_client.post(
api_routes.groups_mealplans_rules, json=utils.jsonify(payload), headers=unique_user.token
)
assert response.status_code == 201
# Validate the response data
@ -90,7 +84,7 @@ def test_group_mealplan_rules_create(
def test_group_mealplan_rules_read(api_client: TestClient, unique_user: TestUser, plan_rule: PlanRulesOut):
response = api_client.get(Routes.item(plan_rule.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_mealplans_rules_item_id(plan_rule.id), headers=unique_user.token)
assert response.status_code == 200
# Validate the response data
@ -109,7 +103,9 @@ def test_group_mealplan_rules_update(api_client: TestClient, unique_user: TestUs
"entryType": "lunch",
}
response = api_client.put(Routes.item(plan_rule.id), json=payload, headers=unique_user.token)
response = api_client.put(
api_routes.groups_mealplans_rules_item_id(plan_rule.id), json=payload, headers=unique_user.token
)
assert response.status_code == 200
# Validate the response data
@ -124,7 +120,7 @@ def test_group_mealplan_rules_update(api_client: TestClient, unique_user: TestUs
def test_group_mealplan_rules_delete(
api_client: TestClient, unique_user: TestUser, plan_rule: PlanRulesOut, database: AllRepositories
):
response = api_client.delete(Routes.item(plan_rule.id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_mealplans_rules_item_id(plan_rule.id), headers=unique_user.token)
assert response.status_code == 200
# Validate no entry in database

View file

@ -10,19 +10,12 @@ from mealie.services.event_bus_service.event_types import (
EventOperation,
EventTypes,
)
from tests.utils import api_routes
from tests.utils.assertion_helpers import assert_ignore_keys
from tests.utils.factories import random_bool, random_email, random_int, random_string
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/events/notifications"
@staticmethod
def item(item_id: int) -> str:
return f"{Routes.base}/{item_id}"
def preferences_generator():
return GroupEventNotifierOptions(
recipe_created=random_bool(),
@ -66,7 +59,7 @@ def event_generator():
def test_create_notification(api_client: TestClient, unique_user: TestUser):
payload = notifier_generator()
response = api_client.post(Routes.base, json=payload, headers=unique_user.token)
response = api_client.post(api_routes.groups_events_notifications, json=payload, headers=unique_user.token)
assert response.status_code == 201
payload_as_dict = response.json()
@ -78,12 +71,14 @@ def test_create_notification(api_client: TestClient, unique_user: TestUser):
assert "apprise_url" not in payload_as_dict
# Cleanup
response = api_client.delete(Routes.item(payload_as_dict["id"]), headers=unique_user.token)
response = api_client.delete(
api_routes.groups_events_notifications_item_id(payload_as_dict["id"]), headers=unique_user.token
)
def test_ensure_apprise_url_is_secret(api_client: TestClient, unique_user: TestUser):
payload = notifier_generator()
response = api_client.post(Routes.base, json=payload, headers=unique_user.token)
response = api_client.post(api_routes.groups_events_notifications, json=payload, headers=unique_user.token)
assert response.status_code == 201
payload_as_dict = response.json()
@ -94,7 +89,7 @@ def test_ensure_apprise_url_is_secret(api_client: TestClient, unique_user: TestU
def test_update_apprise_notification(api_client: TestClient, unique_user: TestUser):
payload = notifier_generator()
response = api_client.post(Routes.base, json=payload, headers=unique_user.token)
response = api_client.post(api_routes.groups_events_notifications, json=payload, headers=unique_user.token)
assert response.status_code == 201
update_payload = response.json()
@ -104,12 +99,18 @@ def test_update_apprise_notification(api_client: TestClient, unique_user: TestUs
update_payload["enabled"] = random_bool()
update_payload["options"] = preferences_generator()
response = api_client.put(Routes.item(update_payload["id"]), json=update_payload, headers=unique_user.token)
response = api_client.put(
api_routes.groups_events_notifications_item_id(update_payload["id"]),
json=update_payload,
headers=unique_user.token,
)
assert response.status_code == 200
# Re-Get The Item
response = api_client.get(Routes.item(update_payload["id"]), headers=unique_user.token)
response = api_client.get(
api_routes.groups_events_notifications_item_id(update_payload["id"]), headers=unique_user.token
)
assert response.status_code == 200
# Validate Updated Values
@ -120,20 +121,26 @@ def test_update_apprise_notification(api_client: TestClient, unique_user: TestUs
assert_ignore_keys(updated_payload["options"], update_payload["options"])
# Cleanup
response = api_client.delete(Routes.item(update_payload["id"]), headers=unique_user.token)
response = api_client.delete(
api_routes.groups_events_notifications_item_id(update_payload["id"]), headers=unique_user.token
)
def test_delete_apprise_notification(api_client: TestClient, unique_user: TestUser):
payload = notifier_generator()
response = api_client.post(Routes.base, json=payload, headers=unique_user.token)
response = api_client.post(api_routes.groups_events_notifications, json=payload, headers=unique_user.token)
assert response.status_code == 201
payload_as_dict = response.json()
response = api_client.delete(Routes.item(payload_as_dict["id"]), headers=unique_user.token)
response = api_client.delete(
api_routes.groups_events_notifications_item_id(payload_as_dict["id"]), headers=unique_user.token
)
assert response.status_code == 204
response = api_client.get(Routes.item(payload_as_dict["id"]), headers=unique_user.token)
response = api_client.get(
api_routes.groups_events_notifications_item_id(payload_as_dict["id"]), headers=unique_user.token
)
assert response.status_code == 404

View file

@ -3,16 +3,11 @@ from uuid import uuid4
from fastapi.testclient import TestClient
from mealie.repos.repository_factory import AllRepositories
from tests.utils import api_routes
from tests.utils.factories import random_bool
from tests.utils.fixture_schemas import TestUser
class Routes:
self = "/api/groups/self"
members = "/api/groups/members"
permissions = "/api/groups/permissions"
def get_permissions_payload(user_id: str, can_manage=None) -> dict:
return {
"user_id": user_id,
@ -25,7 +20,7 @@ def get_permissions_payload(user_id: str, can_manage=None) -> dict:
def test_get_group_members(api_client: TestClient, user_tuple: list[TestUser]):
usr_1, usr_2 = user_tuple
response = api_client.get(Routes.members, headers=usr_1.token)
response = api_client.get(api_routes.groups_members, headers=usr_1.token)
assert response.status_code == 200
members = response.json()
@ -48,7 +43,7 @@ def test_set_memeber_permissions(api_client: TestClient, user_tuple: list[TestUs
payload = get_permissions_payload(str(usr_2.user_id))
# Test
response = api_client.put(Routes.permissions, json=payload, headers=usr_1.token)
response = api_client.put(api_routes.groups_permissions, json=payload, headers=usr_1.token)
assert response.status_code == 200
@ -67,7 +62,7 @@ def test_set_memeber_permissions_unauthorized(api_client: TestClient, unique_use
}
# Test
response = api_client.put(Routes.permissions, json=payload, headers=unique_user.token)
response = api_client.put(api_routes.groups_permissions, json=payload, headers=unique_user.token)
assert response.status_code == 403
@ -82,7 +77,7 @@ def test_set_memeber_permissions_other_group(
database.users.update(user.id, user)
payload = get_permissions_payload(str(g2_user.user_id))
response = api_client.put(Routes.permissions, json=payload, headers=unique_user.token)
response = api_client.put(api_routes.groups_permissions, json=payload, headers=unique_user.token)
assert response.status_code == 403
@ -96,5 +91,5 @@ def test_set_memeber_permissions_no_user(
database.users.update(user.id, user)
payload = get_permissions_payload(str(uuid4()))
response = api_client.put(Routes.permissions, json=payload, headers=unique_user.token)
response = api_client.put(api_routes.groups_permissions, json=payload, headers=unique_user.token)
assert response.status_code == 404

View file

@ -1,17 +1,13 @@
from fastapi.testclient import TestClient
from mealie.schema.group.group_preferences import UpdateGroupPreferences
from tests.utils import api_routes
from tests.utils.assertion_helpers import assert_ignore_keys
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/self"
preferences = "/api/groups/preferences"
def test_get_preferences(api_client: TestClient, unique_user: TestUser) -> None:
response = api_client.get(Routes.preferences, headers=unique_user.token)
response = api_client.get(api_routes.groups_preferences, headers=unique_user.token)
assert response.status_code == 200
preferences = response.json()
@ -21,7 +17,7 @@ def test_get_preferences(api_client: TestClient, unique_user: TestUser) -> None:
def test_preferences_in_group(api_client: TestClient, unique_user: TestUser) -> None:
response = api_client.get(Routes.base, headers=unique_user.token)
response = api_client.get(api_routes.groups_self, headers=unique_user.token)
assert response.status_code == 200
@ -37,7 +33,7 @@ def test_preferences_in_group(api_client: TestClient, unique_user: TestUser) ->
def test_update_preferences(api_client: TestClient, unique_user: TestUser) -> None:
new_data = UpdateGroupPreferences(recipe_public=False, recipe_show_nutrition=True)
response = api_client.put(Routes.preferences, json=new_data.dict(), headers=unique_user.token)
response = api_client.put(api_routes.groups_preferences, json=new_data.dict(), headers=unique_user.token)
assert response.status_code == 200

View file

@ -1,24 +1,19 @@
from fastapi.testclient import TestClient
from tests.utils import api_routes
from tests.utils.factories import user_registration_factory
class Routes:
self = "/api/users/self"
base = "/api/users/register"
auth_token = "/api/auth/token"
def test_user_registration_new_group(api_client: TestClient):
registration = user_registration_factory()
response = api_client.post(Routes.base, json=registration.dict(by_alias=True))
response = api_client.post(api_routes.users_register, json=registration.dict(by_alias=True))
assert response.status_code == 201
# Login
form_data = {"username": registration.email, "password": registration.password}
response = api_client.post(Routes.auth_token, form_data)
response = api_client.post(api_routes.auth_token, form_data)
assert response.status_code == 200
token = response.json().get("access_token")
@ -28,13 +23,13 @@ def test_user_registration_new_group(api_client: TestClient):
def test_new_user_group_permissions(api_client: TestClient):
registration = user_registration_factory()
response = api_client.post(Routes.base, json=registration.dict(by_alias=True))
response = api_client.post(api_routes.users_register, json=registration.dict(by_alias=True))
assert response.status_code == 201
# Login
form_data = {"username": registration.email, "password": registration.password}
response = api_client.post(Routes.auth_token, form_data)
response = api_client.post(api_routes.auth_token, form_data)
assert response.status_code == 200
token = response.json().get("access_token")
@ -43,7 +38,7 @@ def test_new_user_group_permissions(api_client: TestClient):
# Get User
headers = {"Authorization": f"Bearer {token}"}
response = api_client.get(Routes.self, headers=headers)
response = api_client.get(api_routes.users_self, headers=headers)
assert response.status_code == 200
user = response.json()

View file

@ -1,12 +1,12 @@
from fastapi.testclient import TestClient
from mealie.repos.repository_factory import AllRepositories
from tests.utils import routes
from tests.utils import api_routes
from tests.utils.fixture_schemas import TestUser
def test_seed_invalid_locale(api_client: TestClient, unique_user: TestUser):
for route in [routes.seeders.Seeders.foods, routes.seeders.Seeders.labels, routes.seeders.Seeders.units]:
for route in (api_routes.groups_seeders_foods, api_routes.groups_seeders_labels, api_routes.groups_seeders_units):
resp = api_client.post(route, json={"locale": "invalid"}, headers=unique_user.token)
assert resp.status_code == 422
@ -18,7 +18,7 @@ def test_seed_foods(api_client: TestClient, unique_user: TestUser, database: All
foods = database.ingredient_foods.by_group(unique_user.group_id).get_all()
assert len(foods) == 0
resp = api_client.post(routes.seeders.Seeders.foods, json={"locale": "en-US"}, headers=unique_user.token)
resp = api_client.post(api_routes.groups_seeders_foods, json={"locale": "en-US"}, headers=unique_user.token)
assert resp.status_code == 200
# Check that the foods was created
@ -33,7 +33,7 @@ def test_seed_units(api_client: TestClient, unique_user: TestUser, database: All
units = database.ingredient_units.by_group(unique_user.group_id).get_all()
assert len(units) == 0
resp = api_client.post(routes.seeders.Seeders.units, json={"locale": "en-US"}, headers=unique_user.token)
resp = api_client.post(api_routes.groups_seeders_units, json={"locale": "en-US"}, headers=unique_user.token)
assert resp.status_code == 200
# Check that the foods was created
@ -48,7 +48,7 @@ def test_seed_labels(api_client: TestClient, unique_user: TestUser, database: Al
labels = database.group_multi_purpose_labels.by_group(unique_user.group_id).get_all()
assert len(labels) == 0
resp = api_client.post(routes.seeders.Seeders.labels, json={"locale": "en-US"}, headers=unique_user.token)
resp = api_client.post(api_routes.groups_seeders_labels, json={"locale": "en-US"}, headers=unique_user.token)
assert resp.status_code == 200
# Check that the foods was created

View file

@ -7,23 +7,11 @@ from pydantic import UUID4
from mealie.schema.group.group_shopping_list import ShoppingListItemOut, ShoppingListOut
from tests import utils
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
class Routes:
shopping = "/api/groups/shopping"
items = shopping + "/items"
@staticmethod
def item(item_id: str | UUID4) -> str:
return f"{Routes.items}/{item_id}"
@staticmethod
def shopping_list(list_id: str | UUID4) -> str:
return f"{Routes.shopping}/lists/{list_id}"
def create_item(list_id: UUID4) -> dict:
return {
"shopping_list_id": str(list_id),
@ -59,19 +47,19 @@ def test_shopping_list_items_create_one(
) -> None:
item = create_item(shopping_list.id)
response = api_client.post(Routes.items, json=item, headers=unique_user.token)
response = api_client.post(api_routes.groups_shopping_items, json=item, headers=unique_user.token)
as_json = utils.assert_derserialize(response, 201)
# Test Item is Getable
created_item_id = as_json["id"]
response = api_client.get(Routes.item(created_item_id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_items_item_id(created_item_id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
# Ensure List Id is Set
assert as_json["shoppingListId"] == str(shopping_list.id)
# Test Item In List
response = api_client.get(Routes.shopping_list(shopping_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(shopping_list.id), headers=unique_user.token)
response_list = utils.assert_derserialize(response, 200)
assert len(response_list["listItems"]) == 1
@ -89,12 +77,12 @@ def test_shopping_list_items_get_one(
for _ in range(3):
item = random.choice(list_with_items.list_items)
response = api_client.get(Routes.item(item.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_items_item_id(item.id), headers=unique_user.token)
assert response.status_code == 200
def test_shopping_list_items_get_one_404(api_client: TestClient, unique_user: TestUser) -> None:
response = api_client.get(Routes.item(uuid4()), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_items_item_id(uuid4()), headers=unique_user.token)
assert response.status_code == 404
@ -111,7 +99,9 @@ def test_shopping_list_items_update_one(
update_data = create_item(list_with_items.id)
update_data["id"] = str(item.id)
response = api_client.put(Routes.item(item.id), json=update_data, headers=unique_user.token)
response = api_client.put(
api_routes.groups_shopping_items_item_id(item.id), json=update_data, headers=unique_user.token
)
item_json = utils.assert_derserialize(response, 200)
assert item_json["note"] == update_data["note"]
@ -124,11 +114,11 @@ def test_shopping_list_items_delete_one(
item = random.choice(list_with_items.list_items)
# Delete Item
response = api_client.delete(Routes.item(item.id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_shopping_items_item_id(item.id), headers=unique_user.token)
assert response.status_code == 200
# Validate Get Item Returns 404
response = api_client.get(Routes.item(item.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_items_item_id(item.id), headers=unique_user.token)
assert response.status_code == 404
@ -158,11 +148,11 @@ def test_shopping_list_items_update_many_reorder(
# update list
# the default serializer fails on certain complex objects, so we use FastAPI's serliazer first
as_dict = utils.jsonify(as_dict)
response = api_client.put(Routes.items, json=as_dict, headers=unique_user.token)
response = api_client.put(api_routes.groups_shopping_items, json=as_dict, headers=unique_user.token)
assert response.status_code == 200
# retrieve list and check positions against list
response = api_client.get(Routes.shopping_list(list_with_items.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(list_with_items.id), headers=unique_user.token)
response_list = utils.assert_derserialize(response, 200)
for i, item_data in enumerate(response_list["listItems"]):
@ -185,11 +175,13 @@ def test_shopping_list_items_update_many_consolidates_common_items(
li.note = master_note
# update list
response = api_client.put(Routes.items, json=serialize_list_items(list_items), headers=unique_user.token)
response = api_client.put(
api_routes.groups_shopping_items, json=serialize_list_items(list_items), headers=unique_user.token
)
assert response.status_code == 200
# retrieve list and check positions against list
response = api_client.get(Routes.shopping_list(list_with_items.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(list_with_items.id), headers=unique_user.token)
response_list = utils.assert_derserialize(response, 200)
assert len(response_list["listItems"]) == 1
@ -220,7 +212,7 @@ def test_shopping_list_item_extras(
new_item_data = create_item(shopping_list.id)
new_item_data["extras"] = {key_str_1: val_str_1}
response = api_client.post(Routes.items, json=new_item_data, headers=unique_user.token)
response = api_client.post(api_routes.groups_shopping_items, json=new_item_data, headers=unique_user.token)
item_as_json = utils.assert_derserialize(response, 201)
# make sure the extra persists
@ -231,7 +223,9 @@ def test_shopping_list_item_extras(
# add more extras to the item
item_as_json["extras"][key_str_2] = val_str_2
response = api_client.put(Routes.item(item_as_json["id"]), json=item_as_json, headers=unique_user.token)
response = api_client.put(
api_routes.groups_shopping_items_item_id(item_as_json["id"]), json=item_as_json, headers=unique_user.token
)
item_as_json = utils.assert_derserialize(response, 200)
# make sure both the new extra and original extra persist

View file

@ -1,29 +1,17 @@
import random
from fastapi.testclient import TestClient
from pydantic import UUID4
from mealie.schema.group.group_shopping_list import ShoppingListOut
from mealie.schema.recipe.recipe import Recipe
from tests import utils
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/shopping/lists"
@staticmethod
def item(item_id: str | UUID4) -> str:
return f"{Routes.base}/{item_id}"
@staticmethod
def add_recipe(item_id: str | UUID4, recipe_id: str | UUID4) -> str:
return f"{Routes.item(item_id)}/recipe/{recipe_id}"
def test_shopping_lists_get_all(api_client: TestClient, unique_user: TestUser, shopping_lists: list[ShoppingListOut]):
response = api_client.get(Routes.base, headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists, headers=unique_user.token)
assert response.status_code == 200
all_lists = response.json()["items"]
@ -40,7 +28,7 @@ def test_shopping_lists_create_one(api_client: TestClient, unique_user: TestUser
"name": random_string(10),
}
response = api_client.post(Routes.base, json=payload, headers=unique_user.token)
response = api_client.post(api_routes.groups_shopping_lists, json=payload, headers=unique_user.token)
response_list = utils.assert_derserialize(response, 201)
assert response_list["name"] == payload["name"]
@ -50,7 +38,7 @@ def test_shopping_lists_create_one(api_client: TestClient, unique_user: TestUser
def test_shopping_lists_get_one(api_client: TestClient, unique_user: TestUser, shopping_lists: list[ShoppingListOut]):
shopping_list = shopping_lists[0]
response = api_client.get(Routes.item(shopping_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(shopping_list.id), headers=unique_user.token)
assert response.status_code == 200
response_list = response.json()
@ -72,7 +60,9 @@ def test_shopping_lists_update_one(
"listItems": [],
}
response = api_client.put(Routes.item(sample_list.id), json=payload, headers=unique_user.token)
response = api_client.put(
api_routes.groups_shopping_lists_item_id(sample_list.id), json=payload, headers=unique_user.token
)
assert response.status_code == 200
response_list = response.json()
@ -87,10 +77,10 @@ def test_shopping_lists_delete_one(
):
sample_list = random.choice(shopping_lists)
response = api_client.delete(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
assert response.status_code == 200
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
assert response.status_code == 404
@ -104,12 +94,14 @@ def test_shopping_lists_add_recipe(
recipe = recipe_ingredient_only
response = api_client.post(Routes.add_recipe(sample_list.id, recipe.id), headers=unique_user.token)
response = api_client.post(
api_routes.groups_shopping_lists_item_id_recipe_recipe_id(sample_list.id, recipe.id), headers=unique_user.token
)
assert response.status_code == 200
# Get List and Check for Ingredients
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
assert len(as_json["listItems"]) == len(recipe.recipe_ingredient)
@ -137,11 +129,13 @@ def test_shopping_lists_remove_recipe(
recipe = recipe_ingredient_only
response = api_client.post(Routes.add_recipe(sample_list.id, recipe.id), headers=unique_user.token)
response = api_client.post(
api_routes.groups_shopping_lists_item_id_recipe_recipe_id(sample_list.id, recipe.id), headers=unique_user.token
)
assert response.status_code == 200
# Get List and Check for Ingredients
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
assert len(as_json["listItems"]) == len(recipe.recipe_ingredient)
@ -152,10 +146,12 @@ def test_shopping_lists_remove_recipe(
assert item["note"] in known_ingredients
# Remove Recipe
response = api_client.delete(Routes.add_recipe(sample_list.id, recipe.id), headers=unique_user.token)
response = api_client.delete(
api_routes.groups_shopping_lists_item_id_recipe_recipe_id(sample_list.id, recipe.id), headers=unique_user.token
)
# Get List and Check for Ingredients
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
assert len(as_json["listItems"]) == 0
assert len(as_json["recipeReferences"]) == 0
@ -172,10 +168,13 @@ def test_shopping_lists_remove_recipe_multiple_quantity(
recipe = recipe_ingredient_only
for _ in range(3):
response = api_client.post(Routes.add_recipe(sample_list.id, recipe.id), headers=unique_user.token)
response = api_client.post(
api_routes.groups_shopping_lists_item_id_recipe_recipe_id(sample_list.id, recipe.id),
headers=unique_user.token,
)
assert response.status_code == 200
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
assert len(as_json["listItems"]) == len(recipe.recipe_ingredient)
@ -186,10 +185,12 @@ def test_shopping_lists_remove_recipe_multiple_quantity(
assert item["note"] in known_ingredients
# Remove Recipe
response = api_client.delete(Routes.add_recipe(sample_list.id, recipe.id), headers=unique_user.token)
response = api_client.delete(
api_routes.groups_shopping_lists_item_id_recipe_recipe_id(sample_list.id, recipe.id), headers=unique_user.token
)
# Get List and Check for Ingredients
response = api_client.get(Routes.item(sample_list.id), headers=unique_user.token)
response = api_client.get(api_routes.groups_shopping_lists_item_id(sample_list.id), headers=unique_user.token)
as_json = utils.assert_derserialize(response, 200)
# All Items Should Still Exists
@ -218,7 +219,7 @@ def test_shopping_list_extras(
new_list_data: dict = {"name": random_string()}
new_list_data["extras"] = {key_str_1: val_str_1}
response = api_client.post(Routes.base, json=new_list_data, headers=unique_user.token)
response = api_client.post(api_routes.groups_shopping_lists, json=new_list_data, headers=unique_user.token)
list_as_json = utils.assert_derserialize(response, 201)
# make sure the extra persists
@ -229,7 +230,9 @@ def test_shopping_list_extras(
# add more extras to the list
list_as_json["extras"][key_str_2] = val_str_2
response = api_client.put(Routes.item(list_as_json["id"]), json=list_as_json, headers=unique_user.token)
response = api_client.put(
api_routes.groups_shopping_lists_item_id(list_as_json["id"]), json=list_as_json, headers=unique_user.token
)
list_as_json = utils.assert_derserialize(response, 200)
# make sure both the new extra and original extra persist

View file

@ -3,18 +3,10 @@ from datetime import datetime, timezone
import pytest
from fastapi.testclient import TestClient
from tests.utils import assert_derserialize, jsonify
from tests.utils import api_routes, assert_derserialize, jsonify
from tests.utils.fixture_schemas import TestUser
class Routes:
base = "/api/groups/webhooks"
@staticmethod
def item(item_id: int) -> str:
return f"{Routes.base}/{item_id}"
@pytest.fixture()
def webhook_data():
return {
@ -27,15 +19,15 @@ def webhook_data():
def test_create_webhook(api_client: TestClient, unique_user: TestUser, webhook_data):
response = api_client.post(Routes.base, json=jsonify(webhook_data), headers=unique_user.token)
response = api_client.post(api_routes.groups_webhooks, json=jsonify(webhook_data), headers=unique_user.token)
assert response.status_code == 201
def test_read_webhook(api_client: TestClient, unique_user: TestUser, webhook_data):
response = api_client.post(Routes.base, json=jsonify(webhook_data), headers=unique_user.token)
response = api_client.post(api_routes.groups_webhooks, json=jsonify(webhook_data), headers=unique_user.token)
item_id = response.json()["id"]
response = api_client.get(Routes.item(item_id), headers=unique_user.token)
response = api_client.get(api_routes.groups_webhooks_item_id(item_id), headers=unique_user.token)
webhook = assert_derserialize(response, 200)
assert webhook["id"] == item_id
@ -46,7 +38,7 @@ def test_read_webhook(api_client: TestClient, unique_user: TestUser, webhook_dat
def test_update_webhook(api_client: TestClient, webhook_data, unique_user: TestUser):
response = api_client.post(Routes.base, json=jsonify(webhook_data), headers=unique_user.token)
response = api_client.post(api_routes.groups_webhooks, json=jsonify(webhook_data), headers=unique_user.token)
item_dict = assert_derserialize(response, 201)
item_id = item_dict["id"]
@ -54,7 +46,9 @@ def test_update_webhook(api_client: TestClient, webhook_data, unique_user: TestU
webhook_data["url"] = "https://my-new-fake-url.com"
webhook_data["enabled"] = False
response = api_client.put(Routes.item(item_id), json=jsonify(webhook_data), headers=unique_user.token)
response = api_client.put(
api_routes.groups_webhooks_item_id(item_id), json=jsonify(webhook_data), headers=unique_user.token
)
updated_webhook = assert_derserialize(response, 200)
assert updated_webhook["name"] == webhook_data["name"]
@ -63,12 +57,12 @@ def test_update_webhook(api_client: TestClient, webhook_data, unique_user: TestU
def test_delete_webhook(api_client: TestClient, webhook_data, unique_user: TestUser):
response = api_client.post(Routes.base, json=jsonify(webhook_data), headers=unique_user.token)
response = api_client.post(api_routes.groups_webhooks, json=jsonify(webhook_data), headers=unique_user.token)
item_dict = assert_derserialize(response, 201)
item_id = item_dict["id"]
response = api_client.delete(Routes.item(item_id), headers=unique_user.token)
response = api_client.delete(api_routes.groups_webhooks_item_id(item_id), headers=unique_user.token)
assert response.status_code == 200
response = api_client.get(Routes.item(item_id), headers=unique_user.token)
response = api_client.get(api_routes.groups_webhooks_item_id(item_id), headers=unique_user.token)
assert response.status_code == 404