"""Auth: login / current-user / menus / logout / JWT guards.""" def _flatten(nodes): """Flatten menu tree into a list of nodes.""" out = [] for n in nodes or []: out.append(n) out.extend(_flatten(n.get("children") or [])) return out def test_login_and_menus(client): r = client.post("/api/web/auth/login", json={"username": "admin", "password": "Admin@123"}) assert r.status_code == 200 token = r.json()["data"]["token"] assert r.json()["data"]["tokenType"] == "Bearer" me = client.get("/api/web/auth/current-user", headers={"Authorization": f"Bearer {token}"}) assert me.status_code == 200 assert me.json()["data"]["roleCode"] == "admin" assert me.json()["data"]["username"] == "admin" assert "displayName" in me.json()["data"] menus = client.get("/api/web/auth/menus", headers={"Authorization": f"Bearer {token}"}) assert menus.status_code == 200 data = menus.json()["data"] # Prefer richer {tree, permCodes}; tree-list alone also OK if isinstance(data, dict) and "tree" in data: tree = data["tree"] assert "feedback:handle" in data["permCodes"] assert "role:grant" in data["permCodes"] else: tree = data codes = {m["menuCode"] for m in _flatten(tree)} assert "dashboard" in codes assert "role" in codes # Tree must only include M/C pages, not F buttons assert "feedback:handle" not in codes def test_login_wrong_password(client): r = client.post("/api/web/auth/login", json={"username": "admin", "password": "bad"}) assert r.status_code == 401 assert r.json()["code"] == 401 def _assert_error_envelope(body: dict, code: int): assert body["code"] == code assert "message" in body assert "timestamp" in body assert "detail" not in body def test_current_user_invalid_token(client): r = client.get( "/api/web/auth/current-user", headers={"Authorization": "Bearer not-a-valid-token"}, ) assert r.status_code == 401 _assert_error_envelope(r.json(), 401) def test_current_user_missing_token(client): r = client.get("/api/web/auth/current-user") assert r.status_code == 401 _assert_error_envelope(r.json(), 401) def test_logout(client): r = client.post("/api/web/auth/login", json={"username": "admin", "password": "Admin@123"}) token = r.json()["data"]["token"] out = client.post( "/api/web/auth/logout", headers={"Authorization": f"Bearer {token}"}, ) assert out.status_code == 200 assert out.json()["code"] == 200