summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-06-14 02:36:26 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-06-14 02:36:26 -0700
commitf8d61a20759f3833484674173ccb9264d474b6c2 (patch)
tree9c0842ca2c9b27e3a50bae1dda211a681a9135f4 /backend
parent52c431e104b043cc0b7ac6f519ce227d12f2bb70 (diff)
test: add filings backend tests
Diffstat (limited to 'backend')
-rw-r--r--backend/tests/test_api.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py
index 230182e..d898ee2 100644
--- a/backend/tests/test_api.py
+++ b/backend/tests/test_api.py
@@ -22,6 +22,8 @@ def clear_service_caches() -> None:
data_service.HIST_RATIOS_CACHE.clear()
data_service.RATIOS_ENDPOINT_CACHE.clear()
data_service.SECTOR_BENCHMARK_CACHE.clear()
+ data_service.INSIDERS_CACHE.clear()
+ data_service.FILINGS_CACHE.clear()
def quarterly_frame(rows: dict[str, list[float]]) -> pd.DataFrame:
@@ -1310,3 +1312,117 @@ def test_ticker_ratios_route(monkeypatch) -> None:
assert result["pe_ttm"]["value"] == pytest.approx(24.3)
assert result["gross_margin"]["spark"] == []
assert result["dividend_yield"]["vs_sector"] is None
+
+
+# ── Filings ───────────────────────────────────────────────────────────────────
+
+_MOCK_YF_FILINGS = [
+ {
+ "date": "2024-10-31",
+ "type": "10-K",
+ "title": "Annual report",
+ "edgarUrl": "https://www.sec.gov/Archives/10k.htm",
+ "exhibits": {"10-K": "https://www.sec.gov/Archives/10k.htm"},
+ },
+ {
+ "date": "2024-07-31",
+ "type": "10-Q",
+ "title": "Quarterly report",
+ "edgarUrl": "https://www.sec.gov/Archives/10q.htm",
+ "exhibits": {},
+ },
+ {
+ "date": "2024-06-15",
+ "type": "8-K",
+ "title": "Material event disclosure",
+ "edgarUrl": "https://www.sec.gov/Archives/8k.htm",
+ "exhibits": {},
+ },
+ {
+ "date": "2024-05-01",
+ "type": "10-Q",
+ "title": "Quarterly report",
+ "edgarUrl": "https://www.sec.gov/Archives/10q2.htm",
+ "exhibits": {},
+ },
+]
+
+
+class _MockTicker:
+ def __init__(self, sym):
+ self.sec_filings = _MOCK_YF_FILINGS
+
+
+def test_get_sec_filings_kpis(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ kpis = result["kpis"]
+ assert kpis["total"] == 4
+ assert kpis["count_10k"] == 1
+ assert kpis["count_10q"] == 2
+ assert kpis["count_8k"] == 1
+ assert kpis["distinct_forms"] == 3
+
+
+def test_get_sec_filings_sorted_descending(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ dates = [f["date"] for f in result["filings"]]
+ assert dates == sorted(dates, reverse=True)
+
+
+def test_get_sec_filings_url_from_exhibit(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ # 10-K filing should use exhibit URL
+ ten_k = next(f for f in result["filings"] if f["form"] == "10-K")
+ assert ten_k["url"] == "https://www.sec.gov/Archives/10k.htm"
+
+
+def test_get_sec_filings_cadence(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ months = [c["month"] for c in result["cadence"]]
+ assert "2024-10" in months
+ assert "2024-07" in months
+
+
+def test_get_sec_filings_form_mix(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ top_form = result["form_mix"][0]["form"]
+ assert top_form == "10-Q" # 2 count vs 1 each for 10-K and 8-K
+
+
+def test_get_sec_filings_readout(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = data_service.get_sec_filings("AAPL")
+ assert "10-Q" in result["readout"]
+ assert "2024-10-31" in result["readout"]
+
+
+def test_get_sec_filings_empty(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+
+ class _EmptyTicker:
+ def __init__(self, sym):
+ self.sec_filings = []
+
+ monkeypatch.setattr(data_service.yf, "Ticker", _EmptyTicker)
+ result = data_service.get_sec_filings("AAPL")
+ assert result["kpis"]["total"] == 0
+ assert result["filings"] == []
+ assert "No SEC filings found" in result["readout"]
+
+
+def test_ticker_filings_route(monkeypatch):
+ data_service.FILINGS_CACHE.clear()
+ monkeypatch.setattr(data_service.yf, "Ticker", _MockTicker)
+ result = main.ticker_filings("AAPL")
+ assert result["kpis"]["total"] == 4