Files
sales-trainer/backend/tests/test_weak_area_analysis.py

87 lines
3.4 KiB
Python

"""Weak-area evidence contract tests."""
from __future__ import annotations
from app.services.trainee import analyze_weak_areas
def _session(sid, *, outcome="lost", status="finished", mode="trainee", user="u1", org="org-1", score=20, text=True):
return {
"id": sid,
"user_id": user,
"org_id": org,
"mode": mode,
"status": status,
"outcome": outcome,
"persona_id": f"p-{sid}",
"persona_name": f"Persona {sid}",
"persona_meta": {"tier": "B", "initiation_mode": "customer", "channel": "line"},
"debrief": {
"score": score,
"why": "seller did not ask about pain or handle the price objection before the close" if text else "",
"failurePoints": ["missed pain discovery", "weak objection handling"] if text else [],
"coaching": ["build trust and ask for the next step"] if text else [],
"painProgress": {"core pain": 20} if text else {},
},
}
def test_weak_areas_use_judge_evidence_and_exclude_active_preview():
sessions = [
_session("lost-1"),
_session("won-1", outcome="won", score=80, text=False),
_session("active-1", status="active", outcome=None),
_session("preview-1", mode="preview"),
]
result = analyze_weak_areas(sessions, user_id="u1", org_id="org-1")
assert result["total_sessions"] == 2
assert result["wins"] == 1
assert result["losses"] == 1
dimensions = result["dimensions"]
assert dimensions["pain_discovery"]["evidence_count"] == 1
assert dimensions["objection_handling"]["evidence_count"] == 1
assert dimensions["trust_building"]["evidence_count"] == 1
assert dimensions["close_attempt"]["evidence_count"] == 1
assert dimensions["pain_discovery"]["session_ids"] == ["lost-1"]
assert all("preview-1" not in item["session_ids"] for item in dimensions.values())
assert "why" not in result["top_loss_personas"][0]
def test_weak_areas_return_stable_empty_dimensions_without_sessions():
result = analyze_weak_areas([], user_id="u1", org_id="org-1")
assert result["total_sessions"] == 0
assert result["wins"] == 0
assert result["losses"] == 0
assert set(result["dimensions"]) == {
"pain_discovery", "objection_handling", "negotiation", "trust_building", "close_attempt"
}
assert all(item["evidence_count"] == 0 for item in result["dimensions"].values())
def test_weak_area_function_does_not_mix_users_when_caller_scopes_input():
result = analyze_weak_areas([_session("mine", user="u1")], user_id="u1", org_id="org-1")
assert result["top_loss_personas"][0]["persona_id"] == "p-mine"
assert all("u2" not in item["session_ids"] for item in result["dimensions"].values())
def test_weak_area_result_does_not_return_internal_debrief_reasoning():
session = _session("private-reasoning")
session["debrief"]["internal_reasoning"] = "hidden chain of thought"
result = analyze_weak_areas([session], user_id="u1", org_id="org-1")
assert "why" not in result["top_loss_personas"][0]
assert "internal_reasoning" not in str(result)
assert "hidden chain of thought" not in str(result)
def test_weak_area_analysis_requires_actor_scope():
try:
analyze_weak_areas([_session("unscoped")])
except TypeError:
return
raise AssertionError("weak-area analysis must require an actor user_id scope")