no-mistakes(review): Harden tech-performance tests, null comparator, and pending label

This commit is contained in:
root
2026-09-10 04:07:31 +00:00
parent 43800345c1
commit b7f36ac3b1
2 changed files with 40 additions and 26 deletions
+31 -22
View File
@@ -3,9 +3,9 @@
Anchors two Wahab-facing defects/requests:
1. The FM dashboard built its "Technician Workload" card from
``Tech #<user id>`` instead of the technician's real name. The template must
use ``assigned_technician_name`` (the same field ``/tickets`` already uses),
and no template may reintroduce a ``Tech #`` placeholder.
``Tech #<user id>`` instead of the technician's real name. The data sources
the card consumes must expose the technician's real name via
``assigned_technician_name``, never an id placeholder.
2. ``GET /api/tickets/tech-performance`` reports per-technician workload and
outcomes by real name: totals, per-status buckets, completion rate and
``created_at -> closed_at`` resolution times. Everything derives from
@@ -15,7 +15,6 @@ Anchors two Wahab-facing defects/requests:
from __future__ import annotations
from datetime import datetime
from pathlib import Path
import pytest
from sqlalchemy import select
@@ -26,8 +25,6 @@ from app.models.user import User
pytestmark = pytest.mark.asyncio
TEMPLATES_DIR = Path(__file__).resolve().parent.parent / "app" / "templates"
async def _login(client, email: str = "wahab@denya.com", password: str = "denya123") -> str:
resp = await client.post("/api/auth/login", json={"email": email, "password": password})
@@ -80,24 +77,36 @@ def _ticket(status: str, assigned_to: int | None, *, created_at: datetime | None
return spec
# ── 3a. 'Tech #N' regression ─────────────────────────────────────────
async def test_fm_dashboard_workload_uses_real_technician_names(client):
"""The FM dashboard must build the workload card from the real name field."""
resp = await client.get("/dashboard/fm")
assert resp.status_code == 200
body = resp.text
assert "Tech #" not in body
assert "assigned_technician_name" in body
# ── 3a. Real technician names on the workload data paths ─────────────
async def test_workload_sources_report_real_technician_names(client):
"""The FM workload card reads ``/api/tickets?page_size=200`` and the
performance report reads ``/api/tickets/tech-performance``. For an assigned
ticket both must expose the technician's real full name, never a
``Tech #<id>`` placeholder.
"""
prosper = await _user_id("prosper@denya.com")
await _seed_tickets([_ticket("In Progress", prosper), _ticket("Escalated", prosper)])
async def test_no_template_reintroduces_tech_id_placeholder():
"""Sweep every template for the ``Tech #<id>`` placeholder."""
offenders = [
str(path.relative_to(TEMPLATES_DIR))
for path in TEMPLATES_DIR.rglob("*.html")
if "Tech #" in path.read_text(encoding="utf-8")
token = await _login(client)
list_resp = await client.get("/api/tickets?page_size=200", headers=_auth(token))
assert list_resp.status_code == 200
active = [
t for t in list_resp.json()["items"]
if t["status"] not in ("Closed", "Completed", "Cancelled")
]
assert offenders == []
# Same mapping the FM workload card builds from active assigned tickets.
workload: dict[int, str] = {}
for t in active:
if t["assigned_to"]:
workload.setdefault(t["assigned_to"], t["assigned_technician_name"] or "Unassigned")
assert workload == {prosper: "Prosper"}
perf_resp = await client.get("/api/tickets/tech-performance", headers=_auth(token))
assert perf_resp.status_code == 200
rows = {t["technician_id"]: t for t in perf_resp.json()["technicians"]}
assert rows[prosper]["name"] == "Prosper"
assert all(not row["name"].startswith("Tech #") for row in rows.values())
# ── Page + route wiring ──────────────────────────────────────────────