Spaces:
Running
Running
File size: 3,069 Bytes
b324c71 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | """
Unit tests for the Business Strength Archetype: server-side scoring (bsa/scoring.py)
and the public results route (routes/bsa.py). Firestore is mocked.
"""
from unittest.mock import MagicMock, patch
import pytest
from fastapi import HTTPException
from bsa import scoring
from routes import bsa as bsa_routes
from routes.bsa import ResultIn, submit_result
@pytest.fixture(autouse=True)
def _reset_limits():
bsa_routes.limiter.reset()
def _natural():
return {qid: q["naturalFit"] for qid, q in scoring.QUESTIONS.items()}
def _body(answers=None, **over):
answers = answers or _natural()
base = dict(firstName=" Ada ", email=" Ada@Example.com ", phone=" +234 803 123 4567 ", ageRange=scoring.AGES[1], stage=scoring.STAGES[2],
consent=True, answers=[{"q": q, "dim": d} for q, d in answers.items()],
startedAt=1, sessionId="s-1")
base.update(over)
return ResultIn(**base)
def test_scoring_matches_the_documented_rules():
r = scoring.score(_natural())
assert set(r["raw"].values()) == {6}
assert (r["primary"], r["secondary"], r["blendKey"]) == ("ST", "AN", "ST-AN")
assert sum(r["pct"].values()) == 100
op = {qid: ("OP" if "OP" in q["dims"] else q["dims"][0]) for qid, q in scoring.QUESTIONS.items()}
r = scoring.score(op)
assert r["primary"] == "OP" and r["raw"]["OP"] == 24
def test_rejects_impossible_or_missing_answers():
answers = _natural()
first = min(answers)
bad = next(d for d in scoring.ORDER if d not in scoring.QUESTIONS[first]["dims"])
with pytest.raises(ValueError):
scoring.score({**answers, first: bad})
answers.pop(first)
with pytest.raises(ValueError):
scoring.score(answers)
def test_stores_details_and_server_computed_score():
db = MagicMock()
db.collection.return_value.add.return_value = (None, MagicMock(id="doc1"))
with patch.object(bsa_routes.firestore, "client", return_value=db):
out = submit_result(_body())
assert out["id"] == "doc1" and out["blendKey"] == "ST-AN"
db.collection.assert_called_with("bsa_results")
stored = db.collection.return_value.add.call_args[0][0]
assert stored["firstName"] == "Ada" and stored["email"] == "ada@example.com"
assert stored["phone"] == "+234 803 123 4567"
assert len(stored["answers"]) == 42 and stored["primary"] == "ST"
@pytest.mark.parametrize("over", [{"consent": False}, {"email": "not-an-email"}, {"phone": "call me maybe"}, {"phone": "123456"}, {"stage": "made up"}])
def test_rejects_bad_details(over):
with pytest.raises(HTTPException) as e:
submit_result(_body(**over))
assert e.value.status_code == 400
def test_rate_limits_per_browser():
db = MagicMock()
db.collection.return_value.add.return_value = (None, MagicMock(id="x"))
with patch.object(bsa_routes.firestore, "client", return_value=db):
for _ in range(5):
submit_result(_body())
with pytest.raises(HTTPException) as e:
submit_result(_body())
assert e.value.status_code == 429
|