HR-ATS-Portal/backend/tests/test_analytics_dashboard.py

99 lines
3.4 KiB
Python

"""Pure-logic tests for the dashboard's applications-per-job aggregate.
No DB: the SQL group-bys live on the models, but every decision this endpoint
makes — summing the two sources, zero-filling open reqs without resurrecting
dead postings, ordering, capping — is in _merge_job_counts and the serializer,
which is what the dashboard's numbers stand on.
"""
from __future__ import annotations
from types import SimpleNamespace
from uuid import uuid4
from analytics.serializers import serialize_job_application_count
from analytics.views import _merge_job_counts
def _job(title="Backend Engineer", status="open", **overrides):
fields = {
"id": uuid4(),
"title": title,
"department": "Engineering",
"requisition_status": status,
"vacancies": 2,
"is_active": True,
}
fields.update(overrides)
return SimpleNamespace(**fields)
# ---------------------------------------------------------------- serializer
def test_serializer_coerces_and_stringifies():
job = _job(vacancies=None, department=None)
row = serialize_job_application_count(job, None)
assert row["job_post_id"] == str(job.id)
assert row["count"] == 0
assert row["vacancies"] == 0
assert row["department"] == ""
assert row["is_active"] is True
# ---------------------------------------------------------------- merge
def test_merge_sums_both_sources():
job = _job()
key = str(job.id)
rows = _merge_job_counts({key: 3}, {key: 2}, [job], [], 10)
assert len(rows) == 1
assert rows[0]["count"] == 5
def test_merge_includes_zero_application_open_reqs():
starving = _job(title="Unloved Role")
rows = _merge_job_counts({}, {}, [], [starving], 10)
assert len(rows) == 1
assert rows[0]["count"] == 0
assert rows[0]["title"] == "Unloved Role"
def test_merge_never_resurrects_closed_jobs_without_counts():
# A closed job appears only when it actually received applications:
# it arrives via job_rows (it had counts), never via the open-req fill.
closed_with_apps = _job(title="Closed But Applied", status="closed", is_active=False)
rows = _merge_job_counts({str(closed_with_apps.id): 4}, {}, [closed_with_apps], [], 10)
assert [r["title"] for r in rows] == ["Closed But Applied"]
# No counts and not open -> absent entirely (it is in neither input).
rows = _merge_job_counts({}, {}, [], [], 10)
assert rows == []
def test_merge_drops_counts_for_unknown_jobs():
# A count whose job row could not be loaded must not crash or emit a row.
rows = _merge_job_counts({str(uuid4()): 7}, {}, [], [], 10)
assert rows == []
def test_merge_orders_by_count_desc_then_title_and_caps():
a = _job(title="Alpha")
b = _job(title="beta")
c = _job(title="Zeta")
d = _job(title="Delta")
counts = {str(a.id): 1, str(c.id): 5, str(d.id): 1}
rows = _merge_job_counts(counts, {}, [a, c, d], [b], 3)
# count desc; ties by title case-insensitively; zero rows last; capped at 3.
assert [r["title"] for r in rows] == ["Zeta", "Alpha", "Delta"]
rows = _merge_job_counts(counts, {}, [a, c, d], [b], 10)
assert [r["title"] for r in rows] == ["Zeta", "Alpha", "Delta", "beta"]
def test_merge_top_survives_garbage():
job = _job()
rows = _merge_job_counts({str(job.id): 1}, {}, [job], [], None)
assert len(rows) == 1
rows = _merge_job_counts({str(job.id): 1}, {}, [job], [], 0)
assert len(rows) == 1