3c1d5f1323
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
75 lines
3.1 KiB
Python
75 lines
3.1 KiB
Python
"""Tests for POST /api/recipes/{id}/duplicate (#52)."""
|
|
from httpx import AsyncClient
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src.backend.models.orm.recipe import Recipe, RecipeVersion
|
|
from src.backend.models.orm.task import RecipeSubtask, RecipeTask
|
|
from src.backend.models.orm.user import User
|
|
from src.backend.tests.conftest import auth_headers, create_test_recipe
|
|
|
|
|
|
class TestDuplicateRecipe:
|
|
async def test_duplicate_copies_tasks_and_keeps_original(
|
|
self, client: AsyncClient, maker_user: User, db_session: AsyncSession
|
|
):
|
|
src = await create_test_recipe(db_session, maker_user.id)
|
|
src_id = src.id
|
|
before_tasks = (await db_session.execute(select(func.count(RecipeTask.id)))).scalar_one()
|
|
before_subs = (await db_session.execute(select(func.count(RecipeSubtask.id)))).scalar_one()
|
|
|
|
resp = await client.post(
|
|
f"/api/recipes/{src_id}/duplicate",
|
|
json={"code": "REC-COPIA", "name": "Copia"},
|
|
headers=auth_headers(maker_user),
|
|
)
|
|
assert resp.status_code == 201
|
|
data = resp.json()
|
|
assert data["code"] == "REC-COPIA" and data["name"] == "Copia"
|
|
assert data["id"] != src_id
|
|
assert data["description"] == "A recipe for testing"
|
|
assert data["current_version"]["version_number"] == 1
|
|
|
|
# Tasks and subtasks doubled: copied, not moved
|
|
after_tasks = (await db_session.execute(select(func.count(RecipeTask.id)))).scalar_one()
|
|
after_subs = (await db_session.execute(select(func.count(RecipeSubtask.id)))).scalar_one()
|
|
assert after_tasks == before_tasks * 2
|
|
assert after_subs == before_subs * 2
|
|
|
|
new_version = (await db_session.execute(
|
|
select(RecipeVersion).where(RecipeVersion.recipe_id == data["id"])
|
|
)).scalar_one()
|
|
new_tasks = (await db_session.execute(
|
|
select(RecipeTask).where(RecipeTask.version_id == new_version.id)
|
|
)).scalars().all()
|
|
assert len(new_tasks) == before_tasks
|
|
|
|
# Original unchanged
|
|
orig = (await db_session.execute(select(Recipe).where(Recipe.id == src_id))).scalar_one()
|
|
assert orig.code == "REC-001" and orig.name == "Test Recipe"
|
|
orig_versions = (await db_session.execute(
|
|
select(func.count(RecipeVersion.id)).where(RecipeVersion.recipe_id == src_id)
|
|
)).scalar_one()
|
|
assert orig_versions == 1
|
|
|
|
async def test_duplicate_code_conflict(
|
|
self, client: AsyncClient, maker_user: User, db_session: AsyncSession
|
|
):
|
|
src = await create_test_recipe(db_session, maker_user.id)
|
|
resp = await client.post(
|
|
f"/api/recipes/{src.id}/duplicate",
|
|
json={"code": "REC-001", "name": "X"},
|
|
headers=auth_headers(maker_user),
|
|
)
|
|
assert resp.status_code == 409
|
|
|
|
async def test_duplicate_missing_recipe(
|
|
self, client: AsyncClient, maker_user: User
|
|
):
|
|
resp = await client.post(
|
|
"/api/recipes/99999/duplicate",
|
|
json={"code": "NEW", "name": "X"},
|
|
headers=auth_headers(maker_user),
|
|
)
|
|
assert resp.status_code == 404
|