mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-03 04:25:24 +02:00
feat(backend): ✨ start multi-tenant support (WIP) (#680)
* fix ts types * feat(code-generation): ♻️ update code-generation formats * new scope * add step button * fix linter error * update code-generation tags * feat(backend): ✨ start multi-tenant support * feat(backend): ✨ group invitation token generation and signup * refactor(backend): ♻️ move group admin actions to admin router * set url base to include `/admin` * feat(frontend): ✨ generate user sign-up links * test(backend): ✅ refactor test-suite to further decouple tests (WIP) * feat(backend): 🐛 assign owner on backup import for recipes * fix(backend): 🐛 assign recipe owner on migration from other service Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
3c504e7048
commit
bdaf758712
90 changed files with 1793 additions and 949 deletions
|
@ -11,6 +11,8 @@ from mealie.db.db_setup import SessionLocal, generate_session
|
|||
from mealie.db.init_db import main
|
||||
from tests.app_routes import AppRoutes
|
||||
from tests.test_config import TEST_DATA
|
||||
from tests.utils.factories import random_email, random_string, user_registration_factory
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
from tests.utils.recipe_data import get_raw_no_image, get_raw_recipe, get_recipe_test_cases
|
||||
|
||||
main()
|
||||
|
@ -62,12 +64,46 @@ def admin_token(api_client: requests, api_routes: AppRoutes):
|
|||
return login(form_data, api_client, api_routes)
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def g2_user(admin_token, api_client: requests, api_routes: AppRoutes):
|
||||
# Create the user
|
||||
create_data = {
|
||||
"fullName": random_string(),
|
||||
"username": random_string(),
|
||||
"email": random_email(),
|
||||
"password": "useruser",
|
||||
"group": "New Group",
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.groups, json={"name": "New Group"}, headers=admin_token)
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
# Log in as this user
|
||||
form_data = {"username": create_data["email"], "password": "useruser"}
|
||||
|
||||
token = login(form_data, api_client, api_routes)
|
||||
|
||||
self_response = api_client.get(api_routes.users_self, headers=token)
|
||||
|
||||
assert self_response.status_code == 200
|
||||
|
||||
user_id = json.loads(self_response.text).get("id")
|
||||
group_id = json.loads(self_response.text).get("groupId")
|
||||
|
||||
return TestUser(user_id=user_id, group_id=group_id, token=token)
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def user_token(admin_token, api_client: requests, api_routes: AppRoutes):
|
||||
# Create the user
|
||||
create_data = {
|
||||
"fullName": "User",
|
||||
"email": "user@email.com",
|
||||
"fullName": random_string(),
|
||||
"username": random_string(),
|
||||
"email": random_email(),
|
||||
"password": "useruser",
|
||||
"group": "Home",
|
||||
"admin": False,
|
||||
|
@ -79,7 +115,7 @@ def user_token(admin_token, api_client: requests, api_routes: AppRoutes):
|
|||
assert response.status_code == 201
|
||||
|
||||
# Log in as this user
|
||||
form_data = {"username": "user@email.com", "password": "useruser"}
|
||||
form_data = {"username": create_data["email"], "password": "useruser"}
|
||||
return login(form_data, api_client, api_routes)
|
||||
|
||||
|
||||
|
@ -96,3 +132,45 @@ def raw_recipe_no_image():
|
|||
@fixture(scope="session")
|
||||
def recipe_store():
|
||||
return get_recipe_test_cases()
|
||||
|
||||
|
||||
@fixture(scope="module")
|
||||
def unique_user(api_client: TestClient, api_routes: AppRoutes):
|
||||
registration = user_registration_factory()
|
||||
|
||||
response = api_client.post("/api/users/register", json=registration.dict(by_alias=True))
|
||||
assert response.status_code == 201
|
||||
|
||||
form_data = {"username": registration.username, "password": registration.password}
|
||||
|
||||
token = login(form_data, api_client, api_routes)
|
||||
|
||||
user_data = api_client.get(api_routes.users_self, headers=token).json()
|
||||
assert token is not None
|
||||
|
||||
try:
|
||||
yield TestUser(group_id=user_data.get("groupId"), user_id=user_data.get("id"), token=token)
|
||||
finally:
|
||||
# TODO: Delete User after test
|
||||
pass
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def admin_user(api_client: TestClient, api_routes: AppRoutes):
|
||||
|
||||
form_data = {"username": "changeme@email.com", "password": settings.DEFAULT_PASSWORD}
|
||||
|
||||
token = login(form_data, api_client, api_routes)
|
||||
|
||||
user_data = api_client.get(api_routes.users_self, headers=token).json()
|
||||
assert token is not None
|
||||
|
||||
assert user_data.get("admin") is True
|
||||
assert user_data.get("groupId") is not None
|
||||
assert user_data.get("id") is not None
|
||||
|
||||
try:
|
||||
yield TestUser(group_id=user_data.get("groupId"), user_id=user_data.get("id"), token=token)
|
||||
finally:
|
||||
# TODO: Delete User after test
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import json
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
def test_init_superuser(api_client: TestClient, api_routes: AppRoutes, admin_token, admin_user: TestUser):
|
||||
response = api_client.get(api_routes.users_id(1), headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
admin_data = response.json()
|
||||
|
||||
assert admin_data["id"] == admin_user.user_id
|
||||
assert admin_data["groupId"] == admin_user.group_id
|
||||
|
||||
assert admin_data["fullName"] == "Change Me"
|
||||
assert admin_data["email"] == "changeme@email.com"
|
||||
|
||||
|
||||
def test_create_user(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
create_data = {
|
||||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"password": "MyStrongPassword",
|
||||
"group": "Home",
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
user_data = response.json()
|
||||
|
||||
assert user_data["fullName"] == create_data["fullName"]
|
||||
assert user_data["email"] == create_data["email"]
|
||||
assert user_data["group"] == create_data["group"]
|
||||
assert user_data["admin"] == create_data["admin"]
|
||||
|
||||
|
||||
def test_create_user_as_non_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
create_data = {
|
||||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"password": "MyStrongPassword",
|
||||
"group": "Home",
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=user_token)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_update_user(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
update_data = {"id": 1, "fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.text).get("access_token")
|
||||
|
||||
|
||||
def test_update_other_user_as_not_admin(api_client: TestClient, api_routes: AppRoutes, unique_user: TestUser):
|
||||
update_data = {"id": 1, "fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(1), headers=unique_user.token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_self_demote_admin(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
update_data = {"fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_self_promote_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"id": 3, "fullName": "Updated Name", "email": "user@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(2), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_delete_user(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.delete(api_routes.users_id(2), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
|
@ -0,0 +1,46 @@
|
|||
import json
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.utils.factories import random_string
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
base = "/api/admin/groups"
|
||||
|
||||
def item(id: str) -> str:
|
||||
return f"{Routes.base}/{id}"
|
||||
|
||||
|
||||
def test_create_group(api_client: TestClient, admin_token):
|
||||
response = api_client.post(Routes.base, json={"name": random_string()}, headers=admin_token)
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_user_cant_create_group(api_client: TestClient, unique_user: TestUser):
|
||||
response = api_client.post(Routes.base, json={"name": random_string()}, headers=unique_user.token)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_home_group_not_deletable(api_client: TestClient, admin_token):
|
||||
response = api_client.delete(Routes.item(1), headers=admin_token)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_delete_group(api_client: TestClient, admin_token):
|
||||
response = api_client.post(Routes.base, json={"name": random_string()}, headers=admin_token)
|
||||
assert response.status_code == 201
|
||||
|
||||
group_id = json.loads(response.text)["id"]
|
||||
|
||||
response = api_client.delete(Routes.item(group_id), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
# Ensure Group is Deleted
|
||||
response = api_client.get(Routes.base, headers=admin_token)
|
||||
|
||||
for g in response.json():
|
||||
assert g["id"] != group_id
|
|
@ -1,60 +0,0 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
from tests.utils.assertion_helpers import assert_ignore_keys
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def group_data():
|
||||
return {"name": "Test Group"}
|
||||
|
||||
|
||||
def test_create_group(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.post(api_routes.groups, json={"name": "Test Group"}, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_get_self_group(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.get(api_routes.groups, headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert len(json.loads(response.text)) >= 2
|
||||
|
||||
|
||||
def test_update_group(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
new_data = {
|
||||
"name": "New Group Name",
|
||||
"id": 2,
|
||||
"categories": [],
|
||||
"webhooks": [],
|
||||
"users": [],
|
||||
"mealplans": [],
|
||||
"shoppingLists": [],
|
||||
}
|
||||
# Test Update
|
||||
response = api_client.put(api_routes.groups_id(2), json=new_data, headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Validate Changes
|
||||
response = api_client.get(api_routes.groups, headers=admin_token)
|
||||
all_groups = json.loads(response.text)
|
||||
|
||||
id_2 = filter(lambda x: x["id"] == 2, all_groups)
|
||||
|
||||
assert_ignore_keys(new_data, next(id_2), ["preferences"])
|
||||
|
||||
|
||||
def test_home_group_not_deletable(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.delete(api_routes.groups_id(1), headers=admin_token)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_delete_group(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.delete(api_routes.groups_id(2), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
|
@ -14,7 +14,7 @@ def backup_data():
|
|||
"recipes": True,
|
||||
"settings": False, # ! Broken
|
||||
"groups": False, # ! Also Broken
|
||||
"users": True,
|
||||
"users": False,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
from tests.utils.recipe_data import RecipeSiteTestCase
|
||||
|
||||
|
||||
def get_meal_plan_template(first=None, second=None):
|
||||
return {
|
||||
"group": "Home",
|
||||
"startDate": "2021-01-18",
|
||||
"endDate": "2021-01-19",
|
||||
"planDays": [
|
||||
{
|
||||
"date": "2021-1-18",
|
||||
"meals": [{"slug": first, "name": "", "description": ""}],
|
||||
},
|
||||
{
|
||||
"date": "2021-1-19",
|
||||
"meals": [{"slug": second, "name": "", "description": ""}],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def slug_1(api_client: TestClient, api_routes: AppRoutes, admin_token, recipe_store: list[RecipeSiteTestCase]):
|
||||
slug_1 = api_client.post(api_routes.recipes_create_url, json={"url": recipe_store[0].url}, headers=admin_token)
|
||||
slug_1 = json.loads(slug_1.content)
|
||||
|
||||
yield slug_1
|
||||
|
||||
api_client.delete(api_routes.recipes_recipe_slug(slug_1))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def slug_2(api_client: TestClient, api_routes: AppRoutes, admin_token, recipe_store: list[RecipeSiteTestCase]):
|
||||
slug_2 = api_client.post(api_routes.recipes_create_url, json={"url": recipe_store[1].url}, headers=admin_token)
|
||||
slug_2 = json.loads(slug_2.content)
|
||||
|
||||
yield slug_2
|
||||
|
||||
api_client.delete(api_routes.recipes_recipe_slug(slug_2))
|
||||
|
||||
|
||||
def test_create_mealplan(api_client: TestClient, api_routes: AppRoutes, slug_1, slug_2, admin_token):
|
||||
meal_plan = get_meal_plan_template(slug_1, slug_2)
|
||||
|
||||
response = api_client.post(api_routes.meal_plans_create, json=meal_plan, headers=admin_token)
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_read_mealplan(api_client: TestClient, api_routes: AppRoutes, slug_1, slug_2, admin_token):
|
||||
response = api_client.get(api_routes.meal_plans_all, headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
meal_plan_template = get_meal_plan_template(slug_1, slug_2)
|
||||
|
||||
created_meal_plan = json.loads(response.text)
|
||||
meals = created_meal_plan[0]["planDays"]
|
||||
|
||||
assert meals[0]["meals"][0]["slug"] == meal_plan_template["planDays"][0]["meals"][0]["slug"]
|
||||
assert meals[1]["meals"][0]["slug"] == meal_plan_template["planDays"][1]["meals"][0]["slug"]
|
||||
|
||||
|
||||
def test_update_mealplan(api_client: TestClient, api_routes: AppRoutes, slug_1, slug_2, admin_token):
|
||||
|
||||
response = api_client.get(api_routes.meal_plans_all, headers=admin_token)
|
||||
|
||||
existing_mealplan = json.loads(response.text)
|
||||
existing_mealplan = existing_mealplan[0]
|
||||
|
||||
# Swap
|
||||
plan_uid = existing_mealplan.get("id")
|
||||
existing_mealplan["planDays"][0]["meals"][0]["slug"] = slug_2
|
||||
existing_mealplan["planDays"][1]["meals"][0]["slug"] = slug_1
|
||||
|
||||
response = api_client.put(api_routes.meal_plans_plan_id(plan_uid), json=existing_mealplan, headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api_client.get(api_routes.meal_plans_all, headers=admin_token)
|
||||
existing_mealplan = json.loads(response.text)
|
||||
existing_mealplan = existing_mealplan[0]
|
||||
|
||||
assert existing_mealplan["planDays"][0]["meals"][0]["slug"] == slug_2
|
||||
assert existing_mealplan["planDays"][1]["meals"][0]["slug"] == slug_1
|
||||
|
||||
|
||||
def test_delete_mealplan(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.get(api_routes.meal_plans_all, headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
existing_mealplan = json.loads(response.text)
|
||||
existing_mealplan = existing_mealplan[0]
|
||||
|
||||
plan_uid = existing_mealplan.get("id")
|
||||
response = api_client.delete(api_routes.meal_plans_plan_id(plan_uid), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
|
@ -1,58 +0,0 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.schema.user import SignUpToken
|
||||
from tests.app_routes import AppRoutes
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def active_link(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
data = {"name": "Fixture Token", "admin": True}
|
||||
|
||||
response = api_client.post(api_routes.users_sign_ups, json=data, headers=admin_token)
|
||||
|
||||
return SignUpToken(**json.loads(response.text))
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def sign_up_user():
|
||||
return {
|
||||
"fullName": "Test User",
|
||||
"email": "test_user@email.com",
|
||||
"admin": True,
|
||||
"group": "string",
|
||||
"password": "MySecretPassword",
|
||||
}
|
||||
|
||||
|
||||
def test_create_sign_up_link(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
data = {"name": "Test Token", "admin": False}
|
||||
|
||||
response = api_client.post(api_routes.users_sign_ups, json=data, headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_new_user_signup(api_client: TestClient, api_routes: AppRoutes, active_link: SignUpToken, sign_up_user):
|
||||
|
||||
# Creation
|
||||
response = api_client.post(api_routes.users_sign_ups_token(active_link.token), json=sign_up_user)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Login
|
||||
form_data = {"username": "test_user@email.com", "password": "MySecretPassword"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_delete_sign_up_link(
|
||||
api_client: TestClient, api_routes: AppRoutes, admin_token, active_link: SignUpToken, sign_up_user
|
||||
):
|
||||
response = api_client.delete(api_routes.users_sign_ups_token(active_link.token), headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Validate admin_token is Gone
|
||||
response = api_client.get(api_routes.users_sign_ups, headers=admin_token)
|
||||
assert sign_up_user not in json.loads(response.content)
|
|
@ -1,177 +0,0 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from pytest import fixture
|
||||
|
||||
from mealie.core.config import app_dirs
|
||||
from mealie.schema.user import UserOut
|
||||
from tests.app_routes import AppRoutes
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def admin_user():
|
||||
return UserOut(
|
||||
id=1,
|
||||
fullName="Change Me",
|
||||
username="Change Me",
|
||||
email="changeme@email.com",
|
||||
group="Home",
|
||||
admin=True,
|
||||
tokens=[],
|
||||
)
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def new_user():
|
||||
return UserOut(
|
||||
id=3,
|
||||
fullName="My New User",
|
||||
username="My New User",
|
||||
email="newuser@email.com",
|
||||
group="Home",
|
||||
admin=False,
|
||||
tokens=[],
|
||||
)
|
||||
|
||||
|
||||
def test_failed_login(api_client: TestClient, api_routes: AppRoutes):
|
||||
form_data = {"username": "changeme@email.com", "password": "WRONG_PASSWORD"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_superuser_login(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
form_data = {"username": "changeme@email.com", "password": "MyPassword"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
new_token = json.loads(response.text).get("access_token")
|
||||
|
||||
response = api_client.get(api_routes.users_self, headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
return {"Authorization": f"Bearer {new_token}"}
|
||||
|
||||
|
||||
def test_init_superuser(api_client: TestClient, api_routes: AppRoutes, admin_token, admin_user: UserOut):
|
||||
response = api_client.get(api_routes.users_id(1), headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
assert json.loads(response.text) == admin_user.dict(by_alias=True)
|
||||
|
||||
|
||||
def test_create_user(api_client: TestClient, api_routes: AppRoutes, admin_token, new_user):
|
||||
create_data = {
|
||||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"password": "MyStrongPassword",
|
||||
"group": "Home",
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert json.loads(response.text) == new_user.dict(by_alias=True)
|
||||
|
||||
|
||||
def test_create_user_as_non_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
create_data = {
|
||||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"password": "MyStrongPassword",
|
||||
"group": "Home",
|
||||
"admin": False,
|
||||
"tokens": [],
|
||||
}
|
||||
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=user_token)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_get_all_users(api_client: TestClient, api_routes: AppRoutes, admin_token, new_user, admin_user):
|
||||
response = api_client.get(api_routes.users, headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
all_users = json.loads(response.text)
|
||||
assert admin_user.dict(by_alias=True) in all_users
|
||||
assert new_user.dict(by_alias=True) in all_users
|
||||
|
||||
|
||||
def test_update_user(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
update_data = {"id": 1, "fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.text).get("access_token")
|
||||
|
||||
|
||||
def test_update_other_user_as_not_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"id": 1, "fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(1), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_update_self_as_not_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"fullName": "User fullname", "email": "user@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(4), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_self_demote_admin(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
update_data = {"fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_self_promote_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"id": 3, "fullName": "Updated Name", "email": "user@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(2), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_reset_user_password(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.put(api_routes.users_id_reset_password(3), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
form_data = {"username": "newuser@email.com", "password": "MyPassword"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_delete_user(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.delete(api_routes.users_id(2), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_update_user_image(
|
||||
api_client: TestClient, api_routes: AppRoutes, test_image_jpg: Path, test_image_png: Path, admin_token
|
||||
):
|
||||
response = api_client.post(
|
||||
api_routes.users_id_image(2), files={"profile_image": test_image_jpg.open("rb")}, headers=admin_token
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api_client.post(
|
||||
api_routes.users_id_image(2), files={"profile_image": test_image_png.open("rb")}, headers=admin_token
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
directory = app_dirs.USER_DIR.joinpath("2")
|
||||
assert directory.joinpath("profile_image.png").is_file()
|
||||
|
||||
# Old profile images are removed
|
||||
assert 1 == len([file for file in directory.glob("profile_image.*") if file.is_file()])
|
|
@ -0,0 +1,85 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
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)
|
||||
assert r.status_code == 201
|
||||
invitation = r.json()
|
||||
return invitation["token"]
|
||||
|
||||
|
||||
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)
|
||||
|
||||
assert r.status_code == 200
|
||||
|
||||
items = r.json()
|
||||
|
||||
assert len(items) == 1
|
||||
|
||||
for item in items:
|
||||
assert item["groupId"] == unique_user.group_id
|
||||
assert item["token"] == invite
|
||||
|
||||
|
||||
def register_user(api_client, invite):
|
||||
# Test User can Join Group
|
||||
registration = user_registration_factory()
|
||||
registration.group = ""
|
||||
registration.group_token = invite
|
||||
|
||||
response = api_client.post(Routes.register, json=registration.dict(by_alias=True))
|
||||
print(response.json())
|
||||
return registration, response
|
||||
|
||||
|
||||
def test_group_invitation_link(api_client: TestClient, unique_user: TestUser, invite: str):
|
||||
registration, r = register_user(api_client, invite)
|
||||
assert r.status_code == 201
|
||||
|
||||
# Login as new User
|
||||
form_data = {"username": registration.email, "password": registration.password}
|
||||
|
||||
r = api_client.post(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}"})
|
||||
|
||||
assert r.status_code == 200
|
||||
assert r.json()["groupId"] == unique_user.group_id
|
||||
|
||||
|
||||
def test_group_invitation_delete_after_uses(api_client: TestClient, invite: str) -> None:
|
||||
|
||||
# Register First User
|
||||
_, r = register_user(api_client, invite)
|
||||
assert r.status_code == 201
|
||||
|
||||
# Register Second User
|
||||
_, r = register_user(api_client, invite)
|
||||
assert r.status_code == 201
|
||||
|
||||
# Check Group Invitation is Deleted
|
||||
_, r = register_user(api_client, invite)
|
||||
assert r.status_code == 400
|
|
@ -2,6 +2,7 @@ from fastapi.testclient import TestClient
|
|||
|
||||
from mealie.schema.group.group_preferences import UpdateGroupPreferences
|
||||
from tests.utils.assertion_helpers import assert_ignore_keys
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
|
@ -9,8 +10,8 @@ class Routes:
|
|||
preferences = "/api/groups/preferences"
|
||||
|
||||
|
||||
def test_get_preferences(api_client: TestClient, admin_token) -> None:
|
||||
response = api_client.get(Routes.preferences, headers=admin_token)
|
||||
def test_get_preferences(api_client: TestClient, unique_user: TestUser) -> None:
|
||||
response = api_client.get(Routes.preferences, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
@ -21,8 +22,8 @@ def test_get_preferences(api_client: TestClient, admin_token) -> None:
|
|||
assert preferences["recipeShowNutrition"] is False
|
||||
|
||||
|
||||
def test_preferences_in_group(api_client: TestClient, admin_token) -> None:
|
||||
response = api_client.get(Routes.base, headers=admin_token)
|
||||
def test_preferences_in_group(api_client: TestClient, unique_user: TestUser) -> None:
|
||||
response = api_client.get(Routes.base, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
@ -35,10 +36,10 @@ def test_preferences_in_group(api_client: TestClient, admin_token) -> None:
|
|||
assert group["preferences"]["recipeShowNutrition"] is False
|
||||
|
||||
|
||||
def test_update_preferences(api_client: TestClient, admin_token) -> None:
|
||||
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=admin_token)
|
||||
response = api_client.put(Routes.preferences, json=new_data.dict(), headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.schema.user.registration import CreateUserRegistration
|
||||
from tests.utils.factories import user_registration_factory
|
||||
|
||||
|
||||
class Routes:
|
||||
|
@ -9,21 +9,13 @@ class Routes:
|
|||
|
||||
|
||||
def test_user_registration_new_group(api_client: TestClient):
|
||||
registration = CreateUserRegistration(
|
||||
group="New Group Name",
|
||||
email="email@email.com",
|
||||
username="fake-user-name",
|
||||
password="fake-password",
|
||||
password_confirm="fake-password",
|
||||
advanced=False,
|
||||
private=False,
|
||||
)
|
||||
registration = user_registration_factory()
|
||||
|
||||
response = api_client.post(Routes.base, json=registration.dict(by_alias=True))
|
||||
assert response.status_code == 201
|
||||
|
||||
# Login
|
||||
form_data = {"username": "email@email.com", "password": "fake-password"}
|
||||
form_data = {"username": registration.email, "password": registration.password}
|
||||
|
||||
response = api_client.post(Routes.auth_token, form_data)
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
base = "/api/groups/webhooks"
|
||||
|
||||
def item(item_id: int) -> str:
|
||||
return f"{Routes.base}/{item_id}"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def webhook_data():
|
||||
return {"enabled": True, "name": "Test-Name", "url": "https://my-fake-url.com", "time": "00:00"}
|
||||
|
||||
|
||||
def test_create_webhook(api_client: TestClient, unique_user: TestUser, webhook_data):
|
||||
response = api_client.post(Routes.base, json=webhook_data, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_read_webhook(api_client: TestClient, webhook_data, unique_user: TestUser):
|
||||
response = api_client.get(Routes.item(1), headers=unique_user.token)
|
||||
|
||||
webhook = response.json()
|
||||
|
||||
assert webhook["id"] == 1
|
||||
assert webhook["name"] == webhook_data["name"]
|
||||
assert webhook["url"] == webhook_data["url"]
|
||||
assert webhook["time"] == webhook_data["time"]
|
||||
assert webhook["enabled"] == webhook_data["enabled"]
|
||||
|
||||
|
||||
def test_update_webhook(api_client: TestClient, webhook_data, unique_user: TestUser):
|
||||
webhook_data["id"] = 1
|
||||
webhook_data["name"] = "My New Name"
|
||||
webhook_data["url"] = "https://my-new-fake-url.com"
|
||||
webhook_data["time"] = "01:00"
|
||||
webhook_data["enabled"] = False
|
||||
|
||||
response = api_client.put(Routes.item(1), json=webhook_data, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
updated_webhook = response.json()
|
||||
assert updated_webhook["name"] == webhook_data["name"]
|
||||
assert updated_webhook["url"] == webhook_data["url"]
|
||||
assert updated_webhook["time"] == webhook_data["time"]
|
||||
assert updated_webhook["enabled"] == webhook_data["enabled"]
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_delete_webhook(api_client: TestClient, unique_user: TestUser):
|
||||
response = api_client.delete(Routes.item(1), headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api_client.get(Routes.item(1), headers=unique_user.token)
|
||||
assert response.status_code == 404
|
|
@ -5,25 +5,30 @@ from fastapi.testclient import TestClient
|
|||
from slugify import slugify
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
from tests.utils.recipe_data import RecipeSiteTestCase, get_recipe_test_cases
|
||||
|
||||
recipe_test_data = get_recipe_test_cases()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
||||
def test_create_by_url(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
||||
api_client.delete(api_routes.recipes_recipe_slug(recipe_data.expected_slug), headers=user_token)
|
||||
def test_create_by_url(
|
||||
api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, unique_user: TestUser
|
||||
):
|
||||
api_client.delete(api_routes.recipes_recipe_slug(recipe_data.expected_slug), headers=unique_user.token)
|
||||
|
||||
response = api_client.post(api_routes.recipes_create_url, json={"url": recipe_data.url}, headers=user_token)
|
||||
response = api_client.post(api_routes.recipes_create_url, json={"url": recipe_data.url}, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert json.loads(response.text) == recipe_data.expected_slug
|
||||
|
||||
|
||||
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
||||
def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
||||
def test_read_update(
|
||||
api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, unique_user: TestUser
|
||||
):
|
||||
recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)
|
||||
response = api_client.get(recipe_url, headers=user_token)
|
||||
response = api_client.get(recipe_url, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
|
||||
recipe = json.loads(response.text)
|
||||
|
@ -39,12 +44,12 @@ def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data:
|
|||
test_categories = ["one", "two", "three"]
|
||||
recipe["recipeCategory"] = test_categories
|
||||
|
||||
response = api_client.put(recipe_url, json=recipe, headers=user_token)
|
||||
response = api_client.put(recipe_url, json=recipe, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.text).get("slug") == recipe_data.expected_slug
|
||||
|
||||
response = api_client.get(recipe_url, headers=user_token)
|
||||
response = api_client.get(recipe_url, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
recipe = json.loads(response.text)
|
||||
|
||||
|
@ -53,9 +58,9 @@ def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
||||
def test_rename(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
||||
def test_rename(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, unique_user: TestUser):
|
||||
recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)
|
||||
response = api_client.get(recipe_url, headers=user_token)
|
||||
response = api_client.get(recipe_url, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
|
||||
recipe = json.loads(response.text)
|
||||
|
@ -63,7 +68,7 @@ def test_rename(api_client: TestClient, api_routes: AppRoutes, recipe_data: Reci
|
|||
new_slug = slugify(new_name)
|
||||
recipe["name"] = new_name
|
||||
|
||||
response = api_client.put(recipe_url, json=recipe, headers=user_token)
|
||||
response = api_client.put(recipe_url, json=recipe, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.text).get("slug") == new_slug
|
||||
|
@ -72,7 +77,7 @@ def test_rename(api_client: TestClient, api_routes: AppRoutes, recipe_data: Reci
|
|||
|
||||
|
||||
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
||||
def test_delete(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
||||
def test_delete(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, unique_user: TestUser):
|
||||
recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)
|
||||
response = api_client.delete(recipe_url, headers=user_token)
|
||||
response = api_client.delete(recipe_url, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
|
@ -0,0 +1,76 @@
|
|||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.utils.factories import random_string
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
base = "/api/recipes"
|
||||
user = "/api/users/self"
|
||||
|
||||
|
||||
GROUP_ID = 1
|
||||
ADMIN_ID = 1
|
||||
USER_ID = 2
|
||||
|
||||
|
||||
def test_ownership_on_new_with_admin(api_client: TestClient, admin_token):
|
||||
recipe_name = random_string()
|
||||
|
||||
response = api_client.post(Routes.base, json={"name": recipe_name}, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
recipe = api_client.get(Routes.base + f"/{recipe_name}", headers=admin_token).json()
|
||||
|
||||
assert recipe["userId"] == ADMIN_ID
|
||||
assert recipe["groupId"] == GROUP_ID
|
||||
|
||||
|
||||
def test_ownership_on_new_with_user(api_client: TestClient, g2_user: TestUser):
|
||||
recipe_name = random_string()
|
||||
|
||||
response = api_client.post(Routes.base, json={"name": recipe_name}, headers=g2_user.token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
response = api_client.get(Routes.base + f"/{recipe_name}", headers=g2_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
recipe = response.json()
|
||||
|
||||
assert recipe["userId"] == g2_user.user_id
|
||||
assert recipe["groupId"] == g2_user.group_id
|
||||
|
||||
|
||||
def test_get_all_only_includes_group_recipes(api_client: TestClient, unique_user: TestUser):
|
||||
for _ in range(5):
|
||||
recipe_name = random_string()
|
||||
response = api_client.post(Routes.base, json={"name": recipe_name}, headers=unique_user.token)
|
||||
|
||||
response = api_client.get(Routes.base, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
recipes = response.json()
|
||||
|
||||
assert len(recipes) == 5
|
||||
|
||||
for recipe in recipes:
|
||||
assert recipe["groupId"] == unique_user.group_id
|
||||
assert recipe["userId"] == unique_user.user_id
|
||||
|
||||
|
||||
def test_unique_slug_by_group(api_client: TestClient, unique_user: TestUser, g2_user: TestUser) -> None:
|
||||
create_data = {"name": random_string()}
|
||||
|
||||
response = api_client.post(Routes.base, json=create_data, headers=unique_user.token)
|
||||
assert response.status_code == 201
|
||||
|
||||
response = api_client.post(Routes.base, json=create_data, headers=g2_user.token)
|
||||
assert response.status_code == 201
|
||||
|
||||
# Try to create a recipe again with the same name
|
||||
response = api_client.post(Routes.base, json=create_data, headers=g2_user.token)
|
||||
assert response.status_code == 400
|
28
tests/integration_tests/user_tests/test_user_images.py
Normal file
28
tests/integration_tests/user_tests/test_user_images.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from pathlib import Path
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.core.config import app_dirs
|
||||
from tests.app_routes import AppRoutes
|
||||
|
||||
|
||||
def test_update_user_image(
|
||||
api_client: TestClient, api_routes: AppRoutes, test_image_jpg: Path, test_image_png: Path, admin_token
|
||||
):
|
||||
response = api_client.post(
|
||||
api_routes.users_id_image(2), files={"profile_image": test_image_jpg.open("rb")}, headers=admin_token
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api_client.post(
|
||||
api_routes.users_id_image(2), files={"profile_image": test_image_png.open("rb")}, headers=admin_token
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
directory = app_dirs.USER_DIR.joinpath("2")
|
||||
assert directory.joinpath("profile_image.png").is_file()
|
||||
|
||||
# Old profile images are removed
|
||||
assert 1 == len([file for file in directory.glob("profile_image.*") if file.is_file()])
|
25
tests/integration_tests/user_tests/test_user_login.py
Normal file
25
tests/integration_tests/user_tests/test_user_login.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
import json
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
|
||||
|
||||
def test_failed_login(api_client: TestClient, api_routes: AppRoutes):
|
||||
form_data = {"username": "changeme@email.com", "password": "WRONG_PASSWORD"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_superuser_login(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
form_data = {"username": "changeme@email.com", "password": "MyPassword"}
|
||||
response = api_client.post(api_routes.auth_token, form_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
new_token = json.loads(response.text).get("access_token")
|
||||
|
||||
response = api_client.get(api_routes.users_self, headers=admin_token)
|
||||
assert response.status_code == 200
|
||||
|
||||
return {"Authorization": f"Bearer {new_token}"}
|
|
@ -6,9 +6,11 @@ from tests.utils.recipe_data import RecipeSiteTestCase, get_recipe_test_cases
|
|||
test_cases = get_recipe_test_cases()
|
||||
|
||||
"""
|
||||
|
||||
These tests are skipped by default and only really used when troubleshooting the parser
|
||||
directly. If you are working on improve the parser you can add test cases to the `get_recipe_test_cases` function
|
||||
and then use this test case by removing the `@pytest.mark.skip` and than testing your results.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
|
24
tests/utils/factories.py
Normal file
24
tests/utils/factories.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import random
|
||||
import string
|
||||
|
||||
from mealie.schema.user.registration import CreateUserRegistration
|
||||
|
||||
|
||||
def random_string(length=10) -> str:
|
||||
return "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length)).strip()
|
||||
|
||||
|
||||
def random_email(length=10) -> str:
|
||||
return "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length)) + "@fake.com"
|
||||
|
||||
|
||||
def user_registration_factory() -> CreateUserRegistration:
|
||||
return CreateUserRegistration(
|
||||
group=random_string(),
|
||||
email=random_email(),
|
||||
username=random_string(),
|
||||
password="fake-password",
|
||||
password_confirm="fake-password",
|
||||
advanced=False,
|
||||
private=False,
|
||||
)
|
9
tests/utils/fixture_schemas.py
Normal file
9
tests/utils/fixture_schemas.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestUser:
|
||||
user_id: int
|
||||
group_id: int
|
||||
token: Any
|
Loading…
Add table
Add a link
Reference in a new issue