Files
resume-agent/backend/tests/test_enrichment_records.py

239 lines
10 KiB
Python

"""记录模块卡片流测试:校招/社招/实习队列、AI 整理确认、卡内调整、revision 单调性。"""
from __future__ import annotations
from typing import Any
from fastapi.testclient import TestClient
from test_api import (
ANCHOR_CARD_VALUES,
BASE,
active_component,
event,
fill_anchor,
start_manual_profile,
)
from test_enrichment_flow import (
continue_enriching,
created_session,
find_component,
skip_current,
submit_to,
)
def choose(client: TestClient, session_id: str, body: dict[str, Any], value: str) -> dict[str, Any]:
response = event(client, session_id, body, "select", {"value": value})
assert response.status_code == 200, response.text
return response.json()
def confirm_active(
client: TestClient,
session_id: str,
body: dict[str, Any],
*,
use_optimized: bool = False,
) -> dict[str, Any]:
response = event(
client,
session_id,
body,
"confirm",
{"confirmed": True, "use_optimized": use_optimized},
)
assert response.status_code == 200, response.text
return response.json()
def latest_patch(body: dict[str, Any]) -> dict[str, Any]:
turns = body.get("turns") or ([body["turn"]] if body.get("turn") else [])
for turn in reversed(turns):
for block in reversed(turn["blocks"]):
if block["type"] == "resume_patch" and "revision" in block["data"]:
return block["data"]
raise AssertionError("no resume patch with revision")
def latest_patch_revision(body: dict[str, Any]) -> int:
return latest_patch(body)["revision"]
def anchor_via_card(
client: TestClient, job_type: str, anchor_type: str | None, values: dict[str, str]
):
session_id, body = start_manual_profile(client, job_type=job_type)
if anchor_type is not None:
assert body["stage"] == "ANCHOR_TYPE_SELECT"
response = event(client, session_id, body, "select", {"anchor_type": anchor_type})
assert response.status_code == 200, response.text
body = response.json()
body = fill_anchor(client, session_id, body, values)
assert body["stage"] == "ANCHOR_CONFIRM"
body = confirm_active(client, session_id, body)
created = client.post(f"{BASE}/sessions/{session_id}/create", json={})
assert created.status_code == 200, created.text
return session_id, created.json()
INTERNSHIP_ENTRY = {
"company": "星河科技",
"position": "后端实习生",
"start_date": "2024-03",
"end_date_or_present": "2024-09",
"description": "负责接口开发,将响应时间降低了30%。",
}
WORK_ANCHOR = {
"company": "星河科技",
"position": "后端工程师",
"start_date": "2020-01",
"end_date_or_present": "2023-05",
}
def test_campus_queue_full_happy_path(client: TestClient):
session_id, body = created_session(client)
body = continue_enriching(client, session_id, body)
block = active_component(body)
assert block["data"]["component"] == "record_fields"
assert block["data"]["module"] == "internship"
assert block["data"]["record_type"] == "internship_experience"
assert block["data"]["skippable"] is True
# 卡片标题与内容一致(项1回归)
assert "实习" in block["data"]["title"]
bad = submit_to(client, session_id, body, "record_fields", {"company": "星河科技"})
assert bad.status_code == 422
body = submit_to(client, session_id, body, "record_fields", dict(INTERNSHIP_ENTRY)).json()
card = active_component(body)
assert card["data"]["component"] == "experience_confirm_card"
assert card["data"]["confirmation_kind"] == "module_entry"
assert "highlights" not in card["data"]["value"]
proposal = card["data"]["ai_proposal"]
assert proposal["optimized_description"] == "承担接口开发,推动响应时间降低30%。"
assert proposal["source"] == "rule_polish"
body = confirm_active(client, session_id, body, use_optimized=True)
internship = latest_patch(body)["value"]["sections"][-1]["items"][0]
assert internship["description"] == proposal["optimized_description"]
assert "resume_bullets" not in internship
assert internship["provenance"] == "rule_polish"
assert body["stage"] == "RESUME_ENRICHING"
assert active_component(body)["data"]["component"] == "add_another"
assert latest_patch_revision(body) == 2
body = choose(client, session_id, body, "next")
# 实习之后项目作为独立模块出现(项4回归)
assert active_component(body)["data"]["module"] == "project"
body = skip_current(client, session_id, body) # → competition
assert find_component(body, "competition_fields")
body = skip_current(client, session_id, body) # → skills
assert active_component(body)["data"]["component"] == "tags_input"
body = submit_to(client, session_id, body, "tags_input", {"field": "skills", "value": ["Python"]}).json()
assert latest_patch_revision(body) == 3
body = submit_to(client, session_id, body, "tags_input", {"field": "certificates", "value": []}).json()
assert latest_patch_revision(body) == 4
assert body["stage"] == "RESUME_ENRICHING"
assert active_component(body)["data"]["component"] == "custom_card_picker"
body = choose(client, session_id, body, "finish")
assert body["stage"] == "CONTENT_READY"
def test_social_queue_starts_with_more_work(client: TestClient):
session_id, body = anchor_via_card(client, "social", None, dict(WORK_ANCHOR))
body = continue_enriching(client, session_id, body)
assert find_component(body, "progress_card")["data"]["module"] == "more_work"
block = active_component(body)
assert block["data"]["component"] == "record_fields"
assert block["data"]["record_type"] == "work_experience"
body = submit_to(client, session_id, body, "record_fields", {
"company": "云图网络", "position": "开发工程师",
"start_date": "2023-06", "end_date_or_present": "present",
}).json()
body = confirm_active(client, session_id, body)
assert active_component(body)["data"]["component"] == "add_another"
body = choose(client, session_id, body, "again")
assert find_component(body, "progress_card")["data"]["module"] == "more_work"
body = skip_current(client, session_id, body)
assert find_component(body, "progress_card")["data"]["module"] == "project"
def test_internship_queue_campus_and_project_modules_are_independent(client: TestClient):
session_id, body = anchor_via_card(
client, "internship", None, dict(ANCHOR_CARD_VALUES)
)
body = continue_enriching(client, session_id, body)
assert find_component(body, "progress_card")["data"]["module"] == "campus_experience"
block = active_component(body)
assert block["data"]["record_type"] == "campus_experience"
body = submit_to(client, session_id, body, "record_fields", {
"organization": "计算机协会", "role": "技术部负责人",
"start_date": "2023-09", "end_date_or_present": "2024-06",
"description": "组织校内编程训练营。",
}).json()
body = confirm_active(client, session_id, body, use_optimized=True)
campus_item = latest_patch(body)["value"]["sections"][-1]["items"][0]
assert campus_item["organization"] == "计算机协会"
body = choose(client, session_id, body, "next")
assert active_component(body)["data"]["module"] == "project"
body = submit_to(client, session_id, body, "record_fields", {
"project_name": "校园二手交易平台", "project_role": "前端负责人",
"start_date": "2023-03", "end_date_or_present": "2023-09",
}).json()
body = confirm_active(client, session_id, body)
assert active_component(body)["data"]["component"] == "add_another"
kinds = [section["kind"] for section in latest_patch(body)["value"]["sections"]]
assert "campus_experience" in kinds
assert "project_experience" in kinds
def test_module_confirm_edit_reissues_prefilled_card(client: TestClient):
session_id, body = created_session(client)
body = continue_enriching(client, session_id, body)
body = submit_to(client, session_id, body, "record_fields", dict(INTERNSHIP_ENTRY)).json()
edited = event(client, session_id, body, "edit", {})
assert edited.status_code == 200, edited.text
body = edited.json()
block = active_component(body)
assert block["data"]["component"] == "record_fields"
assert block["data"]["value"]["company"] == "星河科技"
entry = dict(INTERNSHIP_ENTRY, company="云图网络")
body = submit_to(client, session_id, body, "record_fields", entry).json()
assert active_component(body)["data"]["value"]["company"] == "云图网络"
def test_module_confirmation_can_keep_original_description(client: TestClient):
session_id, body = created_session(client)
body = continue_enriching(client, session_id, body)
body = submit_to(client, session_id, body, "record_fields", dict(INTERNSHIP_ENTRY)).json()
proposal = active_component(body)["data"]["ai_proposal"]
assert proposal["optimized_description"] != INTERNSHIP_ENTRY["description"]
body = confirm_active(client, session_id, body, use_optimized=False)
internship = latest_patch(body)["value"]["sections"][-1]["items"][0]
assert internship["description"] == INTERNSHIP_ENTRY["description"]
assert internship["provenance"] == "user_provided"
def test_empty_description_gets_conservative_proposal(client: TestClient):
session_id, body = created_session(client)
body = continue_enriching(client, session_id, body)
entry = {key: value for key, value in INTERNSHIP_ENTRY.items() if key != "description"}
body = submit_to(client, session_id, body, "record_fields", entry).json()
card = active_component(body)
assert card["data"]["value"].get("description") is None
assert card["data"]["ai_proposal"]["optimized_description"] == (
"在星河科技担任后端实习生。"
)
body = confirm_active(client, session_id, body, use_optimized=False)
internship = latest_patch(body)["value"]["sections"][-1]["items"][0]
assert "description" not in internship