diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/conftest.py b/tests/conftest.py
index 0451ea7..48a7eb7 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import dataclasses
import typing as t
import pytest
@@ -7,10 +8,17 @@
from htpy import Node, iter_node
if t.TYPE_CHECKING:
- from collections.abc import Generator
+ from collections.abc import Callable, Generator
-RenderFixture: t.TypeAlias = t.Callable[[Node], list[str]]
+@dataclasses.dataclass(frozen=True)
+class Trace:
+ description: str
+
+
+RenderResult: t.TypeAlias = list[str | Trace]
+RenderFixture: t.TypeAlias = t.Callable[[Node], RenderResult]
+TraceFixture: t.TypeAlias = t.Callable[[str], None]
@pytest.fixture(scope="session")
@@ -28,13 +36,33 @@ def django_env() -> None:
@pytest.fixture
-def render() -> Generator[RenderFixture, None, None]:
+def render_result() -> RenderResult:
+ return []
+
+
+@pytest.fixture
+def trace(render_result: RenderResult) -> Callable[[str], None]:
+ def func(description: str) -> None:
+ render_result.append(Trace(description=description))
+
+ return func
+
+
+@pytest.fixture
+def render(render_result: RenderResult) -> Generator[RenderFixture, None, None]:
called = False
- def func(node: Node) -> list[str]:
+ def func(node: Node) -> RenderResult:
nonlocal called
+
+ if called:
+ raise AssertionError("render() must only be called once per test")
+
called = True
- return list(iter_node(node))
+ for chunk in iter_node(node):
+ render_result.append(chunk)
+
+ return render_result
yield func
diff --git a/tests/test_attributes.py b/tests/test_attributes.py
index e833bdc..b0c5e70 100644
--- a/tests/test_attributes.py
+++ b/tests/test_attributes.py
@@ -178,14 +178,16 @@ def test_attrs_and_kwargs(render: RenderFixture) -> None:
assert render(result) == ['
', "
"]
-def test_class_priority(render: RenderFixture) -> None:
- result = div(".a", {"class": "b"}, class_="c")
- assert render(result) == ['', "
"]
-
+def test_class_priority_dict(render: RenderFixture) -> None:
result = div(".a", {"class": "b"})
assert render(result) == ['', "
"]
+def test_class_priority_dict_and_kwarg(render: RenderFixture) -> None:
+ result = div(".a", {"class": "b"}, class_="c")
+ assert render(result) == ['', "
"]
+
+
def test_attribute_priority(render: RenderFixture) -> None:
result = div({"foo": "a"}, foo="b")
assert render(result) == ['', "
"]
diff --git a/tests/test_children.py b/tests/test_children.py
index 6c2e64b..fcfb818 100644
--- a/tests/test_children.py
+++ b/tests/test_children.py
@@ -13,12 +13,14 @@
from htpy import Element, VoidElement, dd, div, dl, dt, html, img, input, li, my_custom_element, ul
+from .conftest import Trace
+
if t.TYPE_CHECKING:
from collections.abc import Callable, Generator
from htpy import Node
- from .conftest import RenderFixture
+ from .conftest import RenderFixture, TraceFixture
def test_void_element(render: RenderFixture) -> None:
@@ -134,29 +136,43 @@ def test_ignored(render: RenderFixture, ignored_value: t.Any) -> None:
assert render(div[ignored_value]) == ["", "
"]
-def test_sync_iter() -> None:
- trace = "not started"
-
+def test_lazy_iter(render: RenderFixture, trace: TraceFixture) -> None:
def generate_list() -> Generator[Element, None, None]:
- nonlocal trace
-
- trace = "before yield"
+ trace("before yield")
yield li("#a")
+ trace("after yield")
+
+ result = render(ul[generate_list()])
+ assert result == [
+ "",
+ Trace("before yield"),
+ '- ',
+ "
",
+ Trace("after yield"),
+ "
",
+ ]
- trace = "done"
- iterator = iter(ul[generate_list()])
+def test_lazy_callable(render: RenderFixture, trace: TraceFixture) -> None:
+ def parent() -> Element:
+ trace("in parent")
+ return div("#parent")[child]
- assert next(iterator) == ""
- assert trace == "not started"
+ def child() -> str:
+ trace("in child")
+ return "child"
- assert next(iterator) == '- '
- assert trace == "before yield"
- assert next(iterator) == "
"
- assert trace == "before yield"
+ result = render(div[parent])
- assert next(iterator) == "
"
- assert trace == "done"
+ assert result == [
+ "",
+ Trace(description="in parent"),
+ '
',
+ Trace(description="in child"),
+ "child",
+ "
",
+ "
",
+ ]
def test_iter_str(render: RenderFixture) -> None:
@@ -175,23 +191,6 @@ def test_iter_markup(render: RenderFixture) -> None:
assert type(child) is str
-def test_callable() -> None:
- called = False
-
- def generate_img() -> VoidElement:
- nonlocal called
- called = True
- return img
-
- iterator = iter(div[generate_img])
-
- assert next(iterator) == ""
- assert called is False
- assert next(iterator) == "
"
- assert called is True
- assert next(iterator) == "
"
-
-
def test_escape_children(render: RenderFixture) -> None:
result = render(div['>"'])
assert result == ["", ">"", "
"]