import os import sys from datetime import datetime, timezone from pathlib import Path from typing import Dict import pytest from fastapi.testclient import TestClient PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) os.environ.setdefault("APPWRITE_ENDPOINT", "http://localhost/v1") os.environ.setdefault("APPWRITE_PROJECT_ID", "test-project") os.environ.setdefault("APPWRITE_API_KEY", "test-key") os.environ.setdefault("APPWRITE_DATABASE_ID", "test-db") os.environ.setdefault("APPWRITE_COLLECTION_CARRINHOS_ID", "test-carts") os.environ.setdefault("APPWRITE_COLLECTION_PEDIDOS_ID", "test-orders") os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_CATALOGO_ID", "test-produtos") os.environ.setdefault("APPWRITE_COLLECTION_LABORATORIOS_ID", "test-labs") os.environ.setdefault("APPWRITE_COLLECTION_CATEGORIAS_ID", "test-categorias") os.environ.setdefault("APPWRITE_COLLECTION_SUBCATEGORIAS_ID", "test-subcat") os.environ.setdefault("APPWRITE_COLLECTION_PAGAMENTOS_ID", "test-payments") os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_ESTOQUE_ID", "test-produtos-estoque") os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_VENDA_ID", "test-produtos-venda") os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_DATA_ID", "test-usuarios-data") os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_PERFIL_ID", "test-usuarios-perfil") os.environ.setdefault("APPWRITE_COLLECTION_USUARIO_EMPRESA_PERFIS_ID", "test-usuario-empresa-perfis") os.environ.setdefault("APPWRITE_COLLECTION_FATURAS_ID", "test-faturas") os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_ID", "test-users") os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_ID", "test-companies") os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_DADOS_ID", "test-companies-data") os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_SOCIOS_ID", "test-empresas-socios") os.environ.setdefault("APPWRITE_COLLECTION_ENDERECOS_ID", "test-addresses") os.environ.setdefault("APPWRITE_COLLECTION_ENTREGAS_ID", "test-entregas") os.environ.setdefault("JWT_SECRET", "test-secret") os.environ.setdefault("JWT_ALGORITHM", "HS256") os.environ.setdefault("SECURITY_API_KEY", "") from src.app.main import app from src.core.deps import get_categorias_service, require_api_key, require_user from src.modules.categorias.schemas import CategoriaCreate, CategoriaOut, CategoriaUpdate from src.modules.categorias.service import _slugify class InMemoryCategoriasService: def __init__(self) -> None: self._items: Dict[str, Dict[str, object]] = {} self._counter = 0 async def list( self, page: int, limit: int | None, q: str | None, sort: str | None, order: str | None, ) -> Dict[str, object]: items = list(self._items.values()) total = len(items) return { "items": [CategoriaOut(**item).model_dump() for item in items], "total": total, } async def get(self, categoria_id: str) -> CategoriaOut: if categoria_id not in self._items: raise AssertionError("Categoria não encontrada nos testes") return CategoriaOut(**self._items[categoria_id]) async def create(self, payload: CategoriaCreate) -> CategoriaOut: data = payload.model_dump(exclude_unset=True) nome = data.get("nome") slug = data.get("slug") or (_slugify(nome) if nome else None) if not slug: raise AssertionError("Falha ao gerar slug") for item in self._items.values(): if item["slug"] == slug: from fastapi import HTTPException, status raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Categoria já existe") self._counter += 1 identifier = f"cat_{self._counter}" timestamp = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") record = { "id": identifier, "nome": nome, "slug": slug, "subcategorias": None, "produtos_catalogo": None, "createdAt": timestamp, "updatedAt": timestamp, } self._items[identifier] = record return CategoriaOut(**record) async def update(self, categoria_id: str, payload: CategoriaUpdate) -> CategoriaOut: if categoria_id not in self._items: raise AssertionError("Categoria não encontrada nos testes") stored = self._items[categoria_id].copy() data = payload.model_dump(exclude_unset=True) if "nome" in data and data["nome"] is not None: stored["nome"] = data["nome"] if "slug" in data and data["slug"] is not None: stored["slug"] = data["slug"] stored["updatedAt"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") self._items[categoria_id] = stored return CategoriaOut(**stored) async def delete(self, categoria_id: str) -> None: self._items.pop(categoria_id, None) @pytest.fixture() def test_client() -> TestClient: service = InMemoryCategoriasService() def override_service() -> InMemoryCategoriasService: return service app.dependency_overrides[get_categorias_service] = override_service app.dependency_overrides[require_api_key] = lambda: None app.dependency_overrides[require_user] = lambda: {"id": "user_1"} client = TestClient(app) yield client app.dependency_overrides.clear() client.close() def test_create_categoria_generates_slug_when_empty(test_client: TestClient) -> None: response = test_client.post("/api/v1/categorias", json={"nome": "Summer Wear", "slug": ""}) assert response.status_code == 201 body = response.json() assert body["slug"] == _slugify("Summer Wear") def test_list_categorias_returns_created_items(test_client: TestClient) -> None: test_client.post("/api/v1/categorias", json={"nome": "Sapatos", "slug": "sapatos"}) test_client.post("/api/v1/categorias", json={"nome": "Chapeus", "slug": "chapeus"}) response = test_client.get("/api/v1/categorias") assert response.status_code == 200 data = response.json() assert data["total"] == 2 assert len(data["items"]) == 2 def test_get_categoria_returns_item(test_client: TestClient) -> None: creation = test_client.post("/api/v1/categorias", json={"nome": "Bolsas", "slug": "bolsas"}) identifier = creation.json()["id"] response = test_client.get(f"/api/v1/categorias/{identifier}") assert response.status_code == 200 assert response.json()["id"] == identifier def test_delete_categoria_removes_item(test_client: TestClient) -> None: creation = test_client.post("/api/v1/categorias", json={"nome": "Cintos", "slug": "cintos"}) identifier = creation.json()["id"] response = test_client.delete(f"/api/v1/categorias/{identifier}") assert response.status_code == 204 list_response = test_client.get("/api/v1/categorias") assert list_response.json()["total"] == 0 def test_create_categoria_conflict(test_client: TestClient) -> None: payload = {"nome": "Cachecois", "slug": "cachecois"} first = test_client.post("/api/v1/categorias", json=payload) assert first.status_code == 201 second = test_client.post("/api/v1/categorias", json=payload) assert second.status_code == 409 assert second.json()["detail"] == "Categoria já existe"