From 17a131d71bbfbce0c5014586f607e815cb5c2a85 Mon Sep 17 00:00:00 2001 From: Spark Date: Sun, 11 Oct 2026 13:17:21 -0400 Subject: [PATCH] =?UTF-8?q?test(0.10.0):=20triage=20(s=C3=A9lecteur,=20fil?= =?UTF-8?q?e=20backlog,=20assign-self,=20extraits)=20=E2=80=94=206=20tests?= =?UTF-8?q?,=20133=20au=20total?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/conftest.py | 9 +++++ tests/test_palier7.py | 81 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 tests/test_palier7.py diff --git a/tests/conftest.py b/tests/conftest.py index 9742982..00c649a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -85,6 +85,7 @@ class FakeGitea: self._label_seq = 100 self.cache_invalidations = 0 self.state_changes: list[tuple] = [] + self.assignee_changes: list[tuple] = [] self.created: list[tuple] = [] self.comments: dict[tuple, list[dict]] = { ("Projets/demo", 1): [ @@ -239,6 +240,14 @@ class FakeGitea: self.created.append((owner, repo, title)) return issue + async def set_issue_assignees(self, owner, repo, issue_number, logins): + self.assignee_changes.append((owner, repo, issue_number, list(logins))) + for issue in self.issues.get(f"{owner}/{repo}", []): + if issue["number"] == issue_number: + issue["assignees"] = [{"login": name} for name in logins] + return issue + return {} + async def set_issue_state(self, owner, repo, issue_number, state): if self.fail_state_change: raise httpx.HTTPError("simulated write-back failure") diff --git a/tests/test_palier7.py b/tests/test_palier7.py new file mode 100644 index 0000000..55628df --- /dev/null +++ b/tests/test_palier7.py @@ -0,0 +1,81 @@ +"""Palier 7 (0.10.0): mode Triage (issue #11).""" + +import json +import re + +from tests.conftest import csrf_from + + +def _queue_from(page_html: str) -> list: + m = re.search( + r'', + page_html, re.S, + ) + assert m, "file de triage absente de la page" + return json.loads(m.group(1)) + + +def test_triage_picker_lists_project_with_backlog(client, fake_gitea): + r = client.get("/triage") + assert r.status_code == 200 + assert "Projets/demo" in r.text + assert "au backlog" in r.text + + +def test_triage_session_queue_is_backlog_only(client, fake_gitea): + r = client.get("/triage/Projets/demo") + assert r.status_code == 200 + queue = _queue_from(r.text) + numbers = [c["number"] for c in queue] + # Open issues of the fake repo: #1 and #5, both unplaced -> backlog. + # #3 is closed (goes to done), #2 is a PR (excluded). + assert numbers == [1, 5] + card = queue[0] + assert card["title"] == "Tâche un" + assert "excerpt" in card and "html_url" in card + + +def test_triage_session_empty_when_nothing_to_triage(client, fake_gitea): + for issue in fake_gitea.issues["Projets/demo"]: + if issue["number"] in (1, 5): + issue["state"] = "closed" + r = client.get("/triage/Projets/demo") + assert r.status_code == 200 + assert _queue_from(r.text) == [] + + +def test_assign_self_adds_token_user(client, fake_gitea): + token = csrf_from(client) + # Issue #5 is unassigned in the fake; #1 already belongs to bruno. + r = client.post( + "/api/issues/Projets/demo/5/assign-self", + data={"csrf_token": token}, + ) + assert r.status_code == 200 + assert r.json()["ok"] is True + assert r.json()["assignees"] == ["bruno"] + assert fake_gitea.assignee_changes == [("Projets", "demo", 5, ["bruno"])] + # Idempotent: assigning #1 (already bruno's) writes nothing. + r = client.post( + "/api/issues/Projets/demo/1/assign-self", + data={"csrf_token": token}, + ) + assert r.status_code == 200 + assert r.json()["assignees"] == ["bruno"] + assert len(fake_gitea.assignee_changes) == 1 + + +def test_assign_self_requires_csrf(client, fake_gitea): + r = client.post("/api/issues/Projets/demo/1/assign-self", data={}) + assert r.status_code == 403 + assert fake_gitea.assignee_changes == [] + + +def test_excerpt_strips_markdown(): + from app.main import _excerpt + + text = _excerpt("# Titre\n\nDu **gras** et un [lien](http://x) ici.", 280) + assert "Titre" in text and "gras" in text and "lien" in text + assert "#" not in text and "**" not in text + assert _excerpt(None) == "" + assert len(_excerpt("mot " * 200, 50)) <= 51