generated from kgod/ai-review-template
feat: initialize resume agent with OfferPai sync
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.resume_document_mutations import set_generated_profile_summary
|
||||
from builder_flow_helpers import (
|
||||
active_component,
|
||||
confirm_card,
|
||||
create_builder_session,
|
||||
event,
|
||||
finish_education,
|
||||
select_section,
|
||||
send_message,
|
||||
start_education,
|
||||
submit_identity,
|
||||
)
|
||||
|
||||
|
||||
def test_create_resume_suggests_experience_type_before_showing_identity_card(client: TestClient) -> None:
|
||||
_, body = create_builder_session(client, job_type="campus")
|
||||
card = active_component(body)
|
||||
assert card["data"]["component"] == "choice_chips"
|
||||
assert card["data"]["module"] == "builder_next_section"
|
||||
assert card["data"]["value"] == "education"
|
||||
assert all(block["data"].get("component") != "record_fields" for block in body["turn"]["blocks"] if block["type"] == "component")
|
||||
|
||||
|
||||
def test_next_step_offers_skill_recommendation_and_finish_actions(client: TestClient) -> None:
|
||||
_, body = create_builder_session(client)
|
||||
card = active_component(body)
|
||||
values = {option["value"] for option in card["data"]["options"]}
|
||||
assert "builder_recommend_skills" in values
|
||||
assert "builder_finish" in values
|
||||
|
||||
|
||||
def test_builder_skill_recommendations_require_confirmation_before_write(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
recommended = event(client, session_id, body, "select", {"value": "builder_recommend_skills"})
|
||||
assert recommended.status_code == 200, recommended.text
|
||||
recommendation_card = active_component(recommended.json())
|
||||
assert recommendation_card["data"]["module"] == "builder_skill_select"
|
||||
assert recommendation_card["data"]["multiple"] is True
|
||||
options = recommendation_card["data"]["options"]
|
||||
assert options
|
||||
assert recommended.json()["resume"]["content"].get("skill_groups") == []
|
||||
|
||||
chosen = options[0]["value"]
|
||||
confirmed = event(
|
||||
client,
|
||||
session_id,
|
||||
recommended.json(),
|
||||
"select",
|
||||
{"values": [chosen], "value": chosen},
|
||||
)
|
||||
assert confirmed.status_code == 200, confirmed.text
|
||||
skills = [
|
||||
skill
|
||||
for group in confirmed.json()["resume"]["content"]["skill_groups"]
|
||||
for skill in group["skills"]
|
||||
]
|
||||
assert chosen in skills
|
||||
assert any(block["type"] == "resume_patch" for block in confirmed.json()["turn"]["blocks"])
|
||||
|
||||
|
||||
def test_builder_finish_generates_summary_from_current_resume(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
finished = event(client, session_id, body, "select", {"value": "builder_finish"})
|
||||
assert finished.status_code == 200, finished.text
|
||||
payload = finished.json()
|
||||
summary = payload["resume"]["content"]["profile_summary"]
|
||||
assert summary["source"] == "ai_generated"
|
||||
assert summary["stale"] is False
|
||||
assert summary["content"]
|
||||
assert "resume_patch" in {block["type"] for block in payload["turn"]["blocks"]}
|
||||
assert payload.get("builder_stream_phases") == ["saving"]
|
||||
|
||||
|
||||
def test_generated_summary_replaces_only_stale_builder_summary() -> None:
|
||||
stale = {
|
||||
"profile_summary": {"content": "旧的个人总结内容足够长,可以被新的总结替换。", "stale": True},
|
||||
}
|
||||
refreshed = set_generated_profile_summary(stale, "根据最新简历信息生成的个人总结内容足够长。", replace_stale=True)
|
||||
assert refreshed["profile_summary"]["content"] == "根据最新简历信息生成的个人总结内容足够长。"
|
||||
assert refreshed["profile_summary"]["stale"] is False
|
||||
|
||||
current = {
|
||||
"profile_summary": {"content": "用户手工维护的总结内容足够长,不应被自动覆盖。", "stale": False},
|
||||
}
|
||||
preserved = set_generated_profile_summary(current, "新的自动总结内容足够长。", replace_stale=True)
|
||||
assert preserved["profile_summary"]["content"] == current["profile_summary"]["content"]
|
||||
|
||||
|
||||
def test_social_builder_suggests_work_but_allows_another_experience_type(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client, job_type="social")
|
||||
assert active_component(body)["data"]["value"] == "work_experience"
|
||||
response = select_section(client, session_id, body, "project_experience")
|
||||
assert active_component(response)["data"]["record_type"] == "project_experience"
|
||||
|
||||
|
||||
def test_education_missing_facts_asks_follow_up_before_confirmation(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
start_education(client, session_id, body)
|
||||
|
||||
follow_up = send_message(client, session_id, "学习了数据结构和数据库课程。")
|
||||
assert "GPA/均分" in follow_up["turn"]["content"]
|
||||
assert "课程项目" in follow_up["turn"]["content"]
|
||||
assert not any(block["data"].get("component") == "experience_confirm_card" for block in follow_up["turn"]["blocks"] if block["type"] == "component")
|
||||
|
||||
proposal = send_message(client, session_id, "GPA 3.7/4.0,专业前 20%,完成数据库课程项目。")
|
||||
card = active_component(proposal)
|
||||
assert card["data"]["component"] == "experience_confirm_card"
|
||||
assert "学习了数据结构" in card["data"]["value"]["description"]
|
||||
assert "GPA 3.7/4.0" in card["data"]["value"]["description"]
|
||||
|
||||
|
||||
def test_no_information_reply_skips_asked_gaps_and_then_shows_confirmation(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
start_education(client, session_id, body)
|
||||
first_follow_up = send_message(client, session_id, "学习了软件工程相关课程。")
|
||||
assert "没有也可以直接说没有" in first_follow_up["turn"]["content"]
|
||||
|
||||
proposal = send_message(client, session_id, "没有")
|
||||
card = active_component(proposal)
|
||||
assert card["data"]["component"] == "experience_confirm_card"
|
||||
assert card["data"]["value"]["description"] == "学习了软件工程相关课程。"
|
||||
|
||||
|
||||
def test_confirmed_campus_education_recommends_project_experience(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
start_education(client, session_id, body)
|
||||
proposal = finish_education(client, session_id, body, "GPA 3.7/4.0,获得两次校级奖学金,完成数据库课程项目。")
|
||||
confirmed = confirm_card(client, session_id, proposal)
|
||||
|
||||
entry = next(block for block in confirmed["turn"]["blocks"] if block["type"] == "resume_patch")["data"]["value"]["sections"][0]["items"][0]
|
||||
assert entry["description"].startswith("GPA 3.7/4.0")
|
||||
next_card = active_component(confirmed)
|
||||
assert next_card["data"]["component"] == "choice_chips"
|
||||
assert next_card["data"]["value"] == "project_experience"
|
||||
|
||||
|
||||
def test_project_gaps_are_limited_and_only_candidate_after_follow_up(client: TestClient) -> None:
|
||||
session_id, body = create_builder_session(client)
|
||||
identity_card = select_section(client, session_id, body, "project_experience")
|
||||
detail_prompt = submit_identity(
|
||||
client,
|
||||
session_id,
|
||||
identity_card,
|
||||
{
|
||||
"project_name": "Resume Agent",
|
||||
"project_role": "Developer",
|
||||
"start_date": "2024-01",
|
||||
"end_date_or_present": "2024-06",
|
||||
},
|
||||
)
|
||||
assert "没有也可以直接说没有" in detail_prompt["turn"]["content"]
|
||||
|
||||
first_follow_up = send_message(client, session_id, "负责后端接口开发,使用 Python 和 FastAPI。")
|
||||
questions = [line for line in first_follow_up["turn"]["content"].splitlines() if line]
|
||||
assert len(questions) == 2
|
||||
assert "交付物" in first_follow_up["turn"]["content"]
|
||||
assert "量化信息" in first_follow_up["turn"]["content"]
|
||||
|
||||
proposal = send_message(client, session_id, "交付 REST API 并上线,覆盖 3 个业务流程。")
|
||||
assert active_component(proposal)["data"]["component"] == "experience_confirm_card"
|
||||
Reference in New Issue
Block a user