diff --git a/src/backend/tests/unit/api/v1/test_projects.py b/src/backend/tests/unit/api/v1/test_projects.py index c5289ad9e..db9400dca 100644 --- a/src/backend/tests/unit/api/v1/test_projects.py +++ b/src/backend/tests/unit/api/v1/test_projects.py @@ -1,7 +1,12 @@ +from uuid import uuid4 + import pytest from fastapi import status from httpx import AsyncClient +CYRILLIC_NAME = "Новый проект" +CYRILLIC_DESC = "Описание проекта с кириллицей" # noqa: RUF001 + @pytest.fixture def basic_case(): @@ -87,3 +92,80 @@ async def test_update_project(client: AsyncClient, logged_in_headers, basic_case assert "description" in result, "The dictionary must contain a key called 'description'" assert "id" in result, "The dictionary must contain a key called 'id'" assert "parent_id" in result, "The dictionary must contain a key called 'parent_id'" + + +async def test_create_project_validation_error(client: AsyncClient, logged_in_headers, basic_case): + invalid_case = basic_case.copy() + invalid_case.pop("name") + response = await client.post("api/v1/projects/", json=invalid_case, headers=logged_in_headers) + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY + + +async def test_delete_project_then_404(client: AsyncClient, logged_in_headers, basic_case): + create_resp = await client.post("api/v1/projects/", json=basic_case, headers=logged_in_headers) + proj_id = create_resp.json()["id"] + + del_resp = await client.delete(f"api/v1/projects/{proj_id}", headers=logged_in_headers) + assert del_resp.status_code == status.HTTP_204_NO_CONTENT + + get_resp = await client.get(f"api/v1/projects/{proj_id}", headers=logged_in_headers) + assert get_resp.status_code == status.HTTP_404_NOT_FOUND + + +async def test_read_project_invalid_id_format(client: AsyncClient, logged_in_headers): + bad_id = "not-a-uuid" + response = await client.get(f"api/v1/projects/{bad_id}", headers=logged_in_headers) + assert response.status_code in (status.HTTP_422_UNPROCESSABLE_ENTITY, status.HTTP_400_BAD_REQUEST) + + +async def test_read_projects_pagination(client: AsyncClient, logged_in_headers): + response = await client.get("api/v1/projects/?limit=1&offset=0", headers=logged_in_headers) + assert response.status_code == status.HTTP_200_OK + result = response.json() + if isinstance(result, list): + assert len(result) <= 1 + else: + assert "items" in result + assert result.get("limit") == 1 + + +async def test_read_projects_empty(client: AsyncClient, logged_in_headers): + # Ensure DB is clean by fetching with a random header that forces each test transactional isolation + random_headers = {**logged_in_headers, "X-Transaction-ID": str(uuid4())} + response = await client.get("api/v1/projects/", headers=random_headers) + if response.json(): + pytest.skip("Pre-existing projects found; skipping empty list assertion") + assert response.status_code == status.HTTP_200_OK + assert response.json() == [] + + +async def test_create_and_read_project_cyrillic(client: AsyncClient, logged_in_headers): + """Ensure that the API correctly handles non-ASCII (Cyrillic) characters during project creation and retrieval.""" + payload = { + "name": CYRILLIC_NAME, + "description": CYRILLIC_DESC, + "flows_list": [], + "components_list": [], + } + + # Create the project with Cyrillic characters + create_resp = await client.post("api/v1/projects/", json=payload, headers=logged_in_headers) + assert create_resp.status_code == status.HTTP_201_CREATED + created = create_resp.json() + assert created["name"] == CYRILLIC_NAME + assert created["description"] == CYRILLIC_DESC + proj_id = created["id"] + + # Fetch the project back to verify round-trip UTF-8 integrity + get_resp = await client.get(f"api/v1/projects/{proj_id}", headers=logged_in_headers) + assert get_resp.status_code == status.HTTP_200_OK + fetched = get_resp.json() + + # Handle potential pagination/envelope variations already seen in other tests + if isinstance(fetched, dict) and "folder" in fetched: + fetched = fetched["folder"] + elif isinstance(fetched, dict) and "project" in fetched: + fetched = fetched["project"] + + assert fetched["name"] == CYRILLIC_NAME + assert fetched["description"] == CYRILLIC_DESC