""" Unit tests for the public Business Footing Framework route (routes/bff_form.py) and the shared public-form checks (utils/public_forms.py). Firestore is mocked. """ from unittest.mock import MagicMock, patch import pytest from fastapi import HTTPException from routes import bff_form from routes.bff_form import SubmissionIn, submit from utils.public_forms import clean_phone @pytest.fixture(autouse=True) def _reset_limits(): bff_form.limiter.reset() def _body(**over): base = dict( name=" Ada Obi ", email=" Ada@Example.com ", phone="0803 123 4567", consent=True, what=dict(businessStage="early", businessName="Ada Books", sectorId="retail_trade", subsectorId="bookshops", nicheId="other", customNiche="Children's books", products=["Story books", " ", "School texts"]), why=dict(whyRaw=" I love reading ", valueProposition="Good books at fair prices"), how=dict(locationType="physical", state="Lagos", city="Ikeja", hours={"monday": {"open": "09:00", "close": "18:00", "off": False}}, demographics={"ageRanges": ["21–25"]}, channels={"social_media": ["Instagram"]}, revenueStreams="Book sales"), startedAt=1, sessionId="s-1", ) base.update(over) return SubmissionIn(**base) def _db(): db = MagicMock() db.collection.return_value.add.return_value = (None, MagicMock(id="doc1")) return db def test_stores_answers_contact_and_labels(): db = _db() with patch.object(bff_form.firestore, "client", return_value=db): out = submit(_body()) assert out == {"success": True, "id": "doc1"} db.collection.assert_called_with("bff_submissions") doc = db.collection.return_value.add.call_args[0][0] assert (doc["name"], doc["email"], doc["phone"]) == ("Ada Obi", "ada@example.com", "0803 123 4567") assert doc["what"]["products"] == ["Story books", "School texts"] assert doc["why"]["whyRaw"] == "I love reading" assert doc["labels"]["niche"] == "Children's books" and doc["labels"]["stage"].startswith("Running for 1") assert doc["how"]["hours"]["monday"]["open"] == "09:00" @pytest.mark.parametrize("over", [ {"consent": False}, {"email": "nope"}, {"phone": "12345"}, {"what": dict(businessStage="unknown", businessName="X", sectorId="a", subsectorId="b", nicheId="c")}, {"what": dict(businessStage="idea", businessName="X", sectorId="a", subsectorId="b", nicheId="other")}, ]) def test_rejects_bad_submissions(over): with pytest.raises(HTTPException) as e: submit(_body(**over)) assert e.value.status_code == 400 def test_rate_limits_per_browser(): with patch.object(bff_form.firestore, "client", return_value=_db()): for _ in range(5): submit(_body()) with pytest.raises(HTTPException) as e: submit(_body()) assert e.value.status_code == 429 @pytest.mark.parametrize("raw,ok", [ ("+234 803 123 4567", True), ("(0803) 123-4567", True), ("08031234567", True), ("123", False), ("0803 abc 4567", False), ("+1234567890123456", False), ]) def test_phone_check(raw, ok): if ok: assert clean_phone(raw) == " ".join(raw.split()) else: with pytest.raises(HTTPException): clean_phone(raw)