"""Palier 21 (0.31.0): description éditable, pièces jointes d'issues, clic carte robuste (délégation côté JS).""" from tests.conftest import csrf_from def test_issue_update_title_and_body(client, fake_gitea): token = csrf_from(client) r = client.post( "/api/issues/Projets/demo/1/update", data={ "title": "Tâche un — précisée", "body": "## Contexte\n\nLa description qui manquait.", "csrf_token": token, }, ) assert r.status_code == 200 payload = r.json() assert payload["ok"] is True assert payload["issue"]["body"].startswith("## Contexte") issue = next( i for i in fake_gitea.issues["Projets/demo"] if i["number"] == 1 ) assert issue["title"] == "Tâche un — précisée" assert "description qui manquait" in issue["body"] # Le journal consigne l'édition. events = client.get("/api/events?repo=Projets/demo").json()["events"] assert any(e["event_type"] == "edited" for e in events) def test_issue_update_rejects_empty_title(client, fake_gitea): token = csrf_from(client) r = client.post( "/api/issues/Projets/demo/1/update", data={"title": " ", "body": "x", "csrf_token": token}, ) assert r.status_code == 400 def test_issue_detail_includes_assets_support(client, fake_gitea): data = client.get("/api/issues/Projets/demo/1").json() assert data["issue"]["attachments_supported"] is True assert data["issue"]["assets"] == [] def test_asset_roundtrip(client, fake_gitea): token = csrf_from(client) r = client.post( "/api/issues/Projets/demo/1/assets", data={"csrf_token": token}, files={"attachment": ("notes.txt", b"bonjour kanbante", "text/plain")}, ) assert r.status_code == 201 asset = r.json()["asset"] assert asset["name"] == "notes.txt" assert asset["size"] == len(b"bonjour kanbante") # Visible dans le détail. data = client.get("/api/issues/Projets/demo/1").json() assert [a["name"] for a in data["issue"]["assets"]] == ["notes.txt"] # Téléchargement proxifié : contenu + disposition. dl = client.get( f"/api/issues/Projets/demo/1/assets/{asset['id']}/download" ) assert dl.status_code == 200 assert dl.content == b"bonjour kanbante" assert "notes.txt" in dl.headers["content-disposition"] # Suppression. token = csrf_from(client) r = client.post( f"/api/issues/Projets/demo/1/assets/{asset['id']}/delete", data={"csrf_token": token}, ) assert r.status_code == 200 data = client.get("/api/issues/Projets/demo/1").json() assert data["issue"]["assets"] == [] def test_asset_upload_rejects_empty_and_huge(client, fake_gitea): token = csrf_from(client) r = client.post( "/api/issues/Projets/demo/1/assets", data={"csrf_token": token}, files={"attachment": ("vide.txt", b"", "text/plain")}, ) assert r.status_code == 400 def test_board_page_has_editor_and_assets_ui(client, fake_gitea): page = client.get("/board/Projets/demo") assert page.status_code == 200 assert 'id="detail-edit-btn"' in page.text assert 'id="detail-edit-form"' in page.text assert 'id="detail-assets"' in page.text assert 'id="asset-form"' in page.text # Création avec description dépliable (0.31.1 :
# natif plutôt qu'un bouton piloté en JS). assert 'id="new-issue-body"' in page.text assert 'id="new-issue-desc"' in page.text assert 'class="composer"' in page.text async def test_gitea_download_follows_browser_download_url(): """Gitea renvoie la fiche JSON de l'asset, pas le binaire : le téléchargement doit suivre browser_download_url (réel 1.27.3, attrapé au smoke de la 0.31.0).""" import httpx from app.gitea_client import GiteaClient def handler(request): url = str(request.url) if url.endswith("/assets/42"): return httpx.Response(200, json={ "id": 42, "name": "preuve.txt", "browser_download_url": "https://gitea.test/attachments/uuid-1", }) if url.endswith("/attachments/uuid-1"): assert request.headers.get("authorization", "").startswith("token ") return httpx.Response( 200, content=b"contenu reel", headers={"content-type": "text/plain"}, ) return httpx.Response(404) client = GiteaClient( base_url="https://gitea.test", token="jeton" + "-factice", cache_ttl=0, transport=httpx.MockTransport(handler), ) content, content_type = await client.download_issue_asset( "Projets", "demo", 1, 42 ) assert content == b"contenu reel" assert content_type == "text/plain"