File size: 3,132 Bytes
89a70e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Unit tests for utils/niche_requests.py and the /niche-request route: the list of
niches people couldn't find. Firestore is mocked.
"""
from unittest.mock import MagicMock, patch

import pytest
from fastapi import HTTPException

from utils import niche_requests
from routes.bff import NicheRequestIn, niche_request


def test_key_ignores_case_spacing_and_punctuation():
    assert niche_requests.niche_key("  School  Stationery! ") == "school-stationery"
    assert niche_requests.niche_key("school stationery") == "school-stationery"
    assert niche_requests.niche_key("!!!") == ""


def test_route_rejects_text_without_letters():
    with pytest.raises(HTTPException) as e:
        niche_request(NicheRequestIn(text="!!!"), user={"uid": "u1"})
    assert e.value.status_code == 400


def test_list_hides_who_asked_and_sorts_by_count():
    def doc(id_, **d):
        m = MagicMock(id=id_)
        m.to_dict.return_value = d
        return m
    db = MagicMock()
    db.collection.return_value.stream.return_value = [
        doc("a", text="A", userCount=1, uids=["u1"], status="open"),
        doc("b", text="B", userCount=3, uids=["u1", "u2", "u3"], status="open"),
        doc("c", text="C", userCount=9, uids=["x"], status="added"),
    ]
    with patch.object(niche_requests.firestore, "client", return_value=db):
        rows = niche_requests.list_requests("open")
    assert [r["text"] for r in rows] == ["B", "A"]
    assert all("uids" not in r for r in rows)


def test_set_status_validates():
    with pytest.raises(ValueError):
        niche_requests.set_status("x", "deleted")


def _fake_firestore(existing: dict | None):
    fs = MagicMock()
    fs.transactional = lambda f: f          # run the body directly with our fake transaction
    snap = MagicMock(exists=existing is not None)
    snap.to_dict.return_value = existing or {}
    ref = fs.client.return_value.collection.return_value.document.return_value
    ref.get.return_value = snap
    tx = fs.client.return_value.transaction.return_value
    return fs, ref, tx


def test_record_counts_each_person_once_and_keeps_where_they_put_it():
    fs, ref, tx = _fake_firestore({"uids": ["u1"], "sectors": ["trade_commerce/retail_trade"], "status": "added"})
    with patch.object(niche_requests, "firestore", fs):
        key = niche_requests.record("u1", "School  stationery", "trade_commerce", "retail_trade")
    assert key == "school-stationery"
    saved = tx.set.call_args[0][1]
    assert saved["userCount"] == 1 and saved["uids"] == ["u1"]
    assert saved["sectors"] == ["trade_commerce/retail_trade"]
    assert saved["status"] == "added"                 # an admin decision isn't reset by a new request
    assert saved["text"] == "School stationery"
    assert "firstAt" not in saved


def test_record_new_niche_starts_open_with_one_person():
    fs, ref, tx = _fake_firestore(None)
    with patch.object(niche_requests, "firestore", fs):
        niche_requests.record("u2", "Shoe repair")
    saved = tx.set.call_args[0][1]
    assert saved["userCount"] == 1 and saved["status"] == "open" and "firstAt" in saved
    assert saved["sectors"] == []