test: integration tests for resume library<->profile sync endpoints
This commit is contained in:
parent
22bc57242e
commit
1c9bfc9fb6
1 changed files with 134 additions and 0 deletions
134
tests/test_resume_sync_integration.py
Normal file
134
tests/test_resume_sync_integration.py
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
"""Integration tests for resume library<->profile sync endpoints."""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import yaml
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from scripts.db import create_resume, get_resume, list_resumes
|
||||||
|
from scripts.db_migrate import migrate_db
|
||||||
|
|
||||||
|
STRUCT_JSON = {
|
||||||
|
"name": "Alex Rivera",
|
||||||
|
"email": "alex@example.com",
|
||||||
|
"phone": "555-0100",
|
||||||
|
"career_summary": "Senior UX Designer.",
|
||||||
|
"experience": [{"title": "Designer", "company": "Acme", "start_date": "2022",
|
||||||
|
"end_date": "present", "location": "Remote", "bullets": ["Led redesign"]}],
|
||||||
|
"education": [{"institution": "State U", "degree": "B.A.", "field": "Design",
|
||||||
|
"start_date": "2016", "end_date": "2020"}],
|
||||||
|
"skills": ["Figma"],
|
||||||
|
"achievements": ["Design award"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fresh_db(tmp_path, monkeypatch):
|
||||||
|
"""Set up a fresh isolated DB + config dir, wired to dev_api._request_db."""
|
||||||
|
db = tmp_path / "test.db"
|
||||||
|
cfg = tmp_path / "config"
|
||||||
|
cfg.mkdir()
|
||||||
|
# STAGING_DB drives _user_yaml_path() -> dirname(db)/config/user.yaml
|
||||||
|
monkeypatch.setenv("STAGING_DB", str(db))
|
||||||
|
migrate_db(db)
|
||||||
|
import dev_api
|
||||||
|
monkeypatch.setattr(
|
||||||
|
dev_api,
|
||||||
|
"_request_db",
|
||||||
|
type("CV", (), {"get": lambda self: str(db), "set": lambda *a: None})(),
|
||||||
|
)
|
||||||
|
return db, cfg
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_to_profile_updates_yaml(fresh_db, monkeypatch):
|
||||||
|
db, cfg = fresh_db
|
||||||
|
import dev_api
|
||||||
|
client = TestClient(dev_api.app)
|
||||||
|
entry = create_resume(db, name="Test Resume",
|
||||||
|
text="Alex Rivera\n", source="uploaded",
|
||||||
|
struct_json=json.dumps(STRUCT_JSON))
|
||||||
|
resp = client.post(f"/api/resumes/{entry['id']}/apply-to-profile")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert data["ok"] is True
|
||||||
|
assert "backup_id" in data
|
||||||
|
assert "Auto-backup before Test Resume" in data["backup_name"]
|
||||||
|
profile_yaml = cfg / "plain_text_resume.yaml"
|
||||||
|
assert profile_yaml.exists()
|
||||||
|
profile = yaml.safe_load(profile_yaml.read_text())
|
||||||
|
assert profile["career_summary"] == "Senior UX Designer."
|
||||||
|
# Name split: "Alex Rivera" -> name="Alex", surname="Rivera"
|
||||||
|
assert profile["name"] == "Alex"
|
||||||
|
assert profile["surname"] == "Rivera"
|
||||||
|
assert profile["education"][0]["institution"] == "State U"
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_to_profile_creates_backup(fresh_db, monkeypatch):
|
||||||
|
db, cfg = fresh_db
|
||||||
|
profile_path = cfg / "plain_text_resume.yaml"
|
||||||
|
profile_path.write_text(yaml.dump({"name": "Old Name", "career_summary": "Old summary"}))
|
||||||
|
entry = create_resume(db, name="New Resume",
|
||||||
|
text="Alex Rivera\n", source="uploaded",
|
||||||
|
struct_json=json.dumps(STRUCT_JSON))
|
||||||
|
import dev_api
|
||||||
|
client = TestClient(dev_api.app)
|
||||||
|
client.post(f"/api/resumes/{entry['id']}/apply-to-profile")
|
||||||
|
resumes = list_resumes(db_path=db)
|
||||||
|
backup = next((r for r in resumes if r["source"] == "auto_backup"), None)
|
||||||
|
assert backup is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_to_profile_preserves_metadata(fresh_db, monkeypatch):
|
||||||
|
db, cfg = fresh_db
|
||||||
|
profile_path = cfg / "plain_text_resume.yaml"
|
||||||
|
profile_path.write_text(yaml.dump({
|
||||||
|
"name": "Old", "salary_min": 80000, "salary_max": 120000,
|
||||||
|
"remote": True, "gender": "non-binary",
|
||||||
|
}))
|
||||||
|
entry = create_resume(db, name="New",
|
||||||
|
text="Alex\n", source="uploaded",
|
||||||
|
struct_json=json.dumps(STRUCT_JSON))
|
||||||
|
import dev_api
|
||||||
|
client = TestClient(dev_api.app)
|
||||||
|
client.post(f"/api/resumes/{entry['id']}/apply-to-profile")
|
||||||
|
profile = yaml.safe_load(profile_path.read_text())
|
||||||
|
assert profile["salary_min"] == 80000
|
||||||
|
assert profile["remote"] is True
|
||||||
|
assert profile["gender"] == "non-binary"
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_resume_syncs_to_default_library_entry(fresh_db, monkeypatch):
|
||||||
|
db, cfg = fresh_db
|
||||||
|
entry = create_resume(db, name="My Resume",
|
||||||
|
text="Original", source="manual")
|
||||||
|
user_yaml = cfg / "user.yaml"
|
||||||
|
user_yaml.write_text(yaml.dump({"default_resume_id": entry["id"], "wizard_complete": True}))
|
||||||
|
import dev_api
|
||||||
|
client = TestClient(dev_api.app)
|
||||||
|
resp = client.put("/api/settings/resume", json={
|
||||||
|
"name": "Alex", "career_summary": "Updated summary",
|
||||||
|
"experience": [], "education": [], "achievements": [], "skills": [],
|
||||||
|
})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert data["synced_library_entry_id"] == entry["id"]
|
||||||
|
updated = get_resume(db_path=db, resume_id=entry["id"])
|
||||||
|
assert updated["synced_at"] is not None
|
||||||
|
struct = json.loads(updated["struct_json"])
|
||||||
|
assert struct["career_summary"] == "Updated summary"
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_resume_no_default_no_crash(fresh_db, monkeypatch):
|
||||||
|
db, cfg = fresh_db
|
||||||
|
user_yaml = cfg / "user.yaml"
|
||||||
|
user_yaml.write_text(yaml.dump({"wizard_complete": True}))
|
||||||
|
import dev_api
|
||||||
|
client = TestClient(dev_api.app)
|
||||||
|
resp = client.put("/api/settings/resume", json={
|
||||||
|
"name": "Alex", "career_summary": "", "experience": [],
|
||||||
|
"education": [], "achievements": [], "skills": [],
|
||||||
|
})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["synced_library_entry_id"] is None
|
||||||
Loading…
Reference in a new issue