Skip to content

Commit 44cc503

Browse files
committed
Add tests demonstrating decorator generator handling
1 parent a67237c commit 44cc503

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ dev = [
5252
"fastapi>=0.116.1",
5353
"litestar>=2.17",
5454
"pre-commit>=4.2",
55+
"pytest>=8.4.2",
56+
"pytest-asyncio>=1.2.0",
5557
"python-fasthtml>=0.12.25; python_full_version>='3.10'",
5658
"quart>=0.20",
5759
"sanic>=25.3",

tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Test configuration."""
2+
3+
import sys
4+
from pathlib import Path
5+
6+
# Ensure the local src/ package is importable without installing
7+
ROOT = Path(__file__).resolve().parents[1]
8+
SRC = ROOT / "src"
9+
if str(SRC) not in sys.path:
10+
sys.path.insert(0, str(SRC))

tests/test_datastar_response.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Tests for datastar_response decorator with various function types."""
2+
3+
import importlib.util
4+
5+
import pytest
6+
7+
from datastar_py.sse import ServerSentEventGenerator as SSE
8+
9+
10+
def _has(module: str) -> bool:
11+
return importlib.util.find_spec(module) is not None
12+
13+
14+
pytest.importorskip("starlette")
15+
from datastar_py.starlette import DatastarResponse, datastar_response # noqa: E402
16+
17+
18+
@pytest.mark.asyncio
19+
async def test_async_generator_support():
20+
"""Async generators should yield multiple events."""
21+
22+
@datastar_response
23+
async def multi_event():
24+
yield SSE.patch_signals({"step": 1})
25+
yield SSE.patch_signals({"step": 2})
26+
27+
result = multi_event()
28+
assert isinstance(result, DatastarResponse)
29+
30+
# Consume and verify events
31+
events = []
32+
async for event in result.body_iterator:
33+
events.append(event)
34+
35+
assert len(events) == 2
36+
assert "step" in events[0]
37+
assert "step" in events[1]
38+
39+
40+
@pytest.mark.asyncio
41+
async def test_async_single_event():
42+
"""Async functions returning single event should work."""
43+
44+
@datastar_response
45+
async def single():
46+
return SSE.patch_signals({"done": True})
47+
48+
result = single()
49+
assert isinstance(result, DatastarResponse)
50+
events = []
51+
async for event in result.body_iterator:
52+
events.append(event)
53+
assert events
54+
55+
56+
def test_sync_generator():
57+
"""Sync generators should yield multiple events."""
58+
59+
@datastar_response
60+
def sync_multi():
61+
yield SSE.patch_signals({"count": 1})
62+
yield SSE.patch_signals({"count": 2})
63+
64+
result = sync_multi()
65+
assert isinstance(result, DatastarResponse)
66+
67+
68+
def test_sync_single_event():
69+
"""Sync functions returning single event should work."""
70+
71+
@datastar_response
72+
def single():
73+
return SSE.patch_signals({"value": 42})
74+
75+
result = single()
76+
assert isinstance(result, DatastarResponse)
77+
78+
79+
# Optional smoke tests for other adapters to ensure decorator returns the right type
80+
if _has("litestar"):
81+
from datastar_py.litestar import DatastarResponse as LitestarResponse
82+
from datastar_py.litestar import datastar_response as litestar_response
83+
84+
def test_litestar_sync_generator():
85+
@litestar_response
86+
def sync_multi():
87+
yield SSE.patch_signals({"count": 1})
88+
yield SSE.patch_signals({"count": 2})
89+
90+
resp = sync_multi()
91+
assert isinstance(resp, LitestarResponse)
92+
93+
@pytest.mark.asyncio
94+
async def test_litestar_async_function():
95+
@litestar_response
96+
async def single():
97+
return SSE.patch_signals({"done": True})
98+
99+
resp = single()
100+
assert isinstance(resp, LitestarResponse)
101+
events = []
102+
async for event in resp.iterator:
103+
events.append(event)
104+
assert events
105+
106+
107+
if _has("django"):
108+
from datastar_py.django import DatastarResponse as DjangoResponse
109+
from datastar_py.django import datastar_response as django_response
110+
111+
@pytest.mark.asyncio
112+
async def test_django_async_function():
113+
@django_response
114+
async def single():
115+
return SSE.patch_signals({"done": True})
116+
117+
resp = await single()
118+
assert isinstance(resp, DjangoResponse)
119+
120+
@pytest.mark.asyncio
121+
async def test_django_sync_generator():
122+
@django_response
123+
def sync_multi():
124+
yield SSE.patch_signals({"count": 1})
125+
yield SSE.patch_signals({"count": 2})
126+
127+
resp = await sync_multi()
128+
assert isinstance(resp, DjangoResponse)

0 commit comments

Comments
 (0)