diff --git a/tests/test_components.py b/tests/test_components.py index 0d75965..38f2398 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -2,47 +2,29 @@ import unittest from unittest.mock import MagicMock, patch import django - +from django.test import SimpleTestCase from django.utils.safestring import SafeText, mark_safe -from common import components as _components -from common.components.core import Node +from common import components from games.models import Platform, Game, Purchase, Session - -class _RenderingComponents: - """Test accessor that renders lazy component nodes to safe HTML strings. - - Component builders now return ``Node`` objects (the lazy tree). These tests - assert on rendered HTML, so we render any node a capitalized builder returns - to a ``SafeText`` string. Internals (``_render_element``) and the legacy - string-returning ``Component()`` are untouched (non-node results pass - through), so cache/escaping tests keep working unchanged. - """ - - def __getattr__(self, name): - attr = getattr(_components, name) - if not (callable(attr) and name[:1].isupper()): - return attr - - def rendered(*args, **kwargs): - result = attr(*args, **kwargs) - return str(result) if isinstance(result, Node) else result - - return rendered - - -components = _RenderingComponents() +# Component builders return lazy ``Node`` objects; these tests assert on rendered +# HTML, so node-returning calls are wrapped in ``str(...)`` at the call site +# (``Node.__str__`` returns a ``SafeText``). Non-node helpers (``randomid``, +# ``_resolve_name_with_icon``, the legacy string ``Component()``) are called +# directly. class ComponentIntegrationTest(unittest.TestCase): """Test Component() works correctly with caching transparent.""" def test_tag_name_component(self): - result = components.Component( - tag_name="div", - attributes=[("class", "test")], - children="hello", + result = str( + components.Component( + tag_name="div", + attributes=[("class", "test")], + children="hello", + ) ) self.assertEqual(result, '
hello
') @@ -54,9 +36,17 @@ class ComponentCacheTest(unittest.TestCase): components._render_element.cache_clear() def test_identical_components_hit_cache(self): - components.Component(tag_name="div", attributes=[("class", "x")], children="hi") + str( + components.Component( + tag_name="div", attributes=[("class", "x")], children="hi" + ) + ) misses = components._render_element.cache_info().misses - components.Component(tag_name="div", attributes=[("class", "x")], children="hi") + str( + components.Component( + tag_name="div", attributes=[("class", "x")], children="hi" + ) + ) info = components._render_element.cache_info() self.assertEqual(info.misses, misses) # no new miss self.assertGreaterEqual(info.hits, 1) # served from cache @@ -67,8 +57,10 @@ class ComponentCacheTest(unittest.TestCase): def test_safe_and_unsafe_children_do_not_collide(self): """A SafeText "" and a plain "" are equal as strings but must render differently — the cache key must keep them distinct.""" - safe = components.Component(tag_name="span", children=[mark_safe("x")]) - unsafe = components.Component(tag_name="span", children=["x"]) + safe = str( + components.Component(tag_name="span", children=[mark_safe("x")]) + ) + unsafe = str(components.Component(tag_name="span", children=["x"])) self.assertIn("x", safe) self.assertIn("<b>x</b>", unsafe) self.assertNotEqual(safe, unsafe) @@ -140,33 +132,37 @@ class PopoverDeterministicTest(unittest.TestCase): """Test that Popover() produces deterministic HTML output.""" def test_same_popover_same_id(self): - r1 = components.Popover("hello", wrapped_content="hello") - r2 = components.Popover("hello", wrapped_content="hello") + r1 = str(components.Popover("hello", wrapped_content="hello")) + r2 = str(components.Popover("hello", wrapped_content="hello")) self.assertEqual(r1, r2) def test_different_content_different_id(self): - r1 = components.Popover("content_a", wrapped_content="content_a") - r2 = components.Popover("content_b", wrapped_content="content_b") + r1 = str(components.Popover("content_a", wrapped_content="content_a")) + r2 = str(components.Popover("content_b", wrapped_content="content_b")) self.assertNotEqual(r1, r2) def test_wrapped_classes_affect_id(self): - r1 = components.Popover("c", wrapped_content="c", wrapped_classes="class_x") - r2 = components.Popover("c", wrapped_content="c", wrapped_classes="class_y") + r1 = str( + components.Popover("c", wrapped_content="c", wrapped_classes="class_x") + ) + r2 = str( + components.Popover("c", wrapped_content="c", wrapped_classes="class_y") + ) self.assertNotEqual(r1, r2) def test_wrapped_content_affects_id(self): - r1 = components.Popover("popover", wrapped_content="wrapped_a") - r2 = components.Popover("popover", wrapped_content="wrapped_b") + r1 = str(components.Popover("popover", wrapped_content="wrapped_a")) + r2 = str(components.Popover("popover", wrapped_content="wrapped_b")) self.assertNotEqual(r1, r2) def test_popover_content_affects_id(self): - r1 = components.Popover("popover_a", wrapped_content="wrapped") - r2 = components.Popover("popover_b", wrapped_content="wrapped") + r1 = str(components.Popover("popover_a", wrapped_content="wrapped")) + r2 = str(components.Popover("popover_b", wrapped_content="wrapped")) self.assertNotEqual(r1, r2) def test_full_html_deterministic(self): - r1 = components.Popover("hello world", wrapped_content="hello world") - r2 = components.Popover("hello world", wrapped_content="hello world") + r1 = str(components.Popover("hello world", wrapped_content="hello world")) + r2 = str(components.Popover("hello world", wrapped_content="hello world")) self.assertEqual(r1.encode(), r2.encode()) @@ -206,26 +202,26 @@ class ComponentReturnTypeTest(unittest.TestCase): """Test that component functions return SafeText and render correctly.""" def test_div_returns_safe_text(self): - result = components.Div([("class", "x")], "hello") + result = str(components.Div([("class", "x")], "hello")) self.assertIsInstance(result, SafeText) def test_div_deterministic(self): - r1 = components.Div([("class", "x")], "hello") - r2 = components.Div([("class", "x")], "hello") + r1 = str(components.Div([("class", "x")], "hello")) + r2 = str(components.Div([("class", "x")], "hello")) self.assertEqual(r1, r2) self.assertIn('
hello
', r1) def test_div_no_args(self): - result = components.Div(children="test") + result = str(components.Div(children="test")) self.assertIsInstance(result, SafeText) self.assertIn("
test
", result) def test_a_returns_safe_text(self): - result = components.A([], "link") + result = str(components.A([], "link")) self.assertIsInstance(result, SafeText) def test_a_literal_href(self): - result = components.A([], "x", href="/literal/path") + result = str(components.A([], "x", href="/literal/path")) self.assertIn('href="/literal/path"', result) def test_a_url_name_reversed(self): @@ -234,35 +230,35 @@ class ComponentReturnTypeTest(unittest.TestCase): with patch( "common.components.primitives.reverse", return_value="/resolved/url" ): - result = components.A([], "link", url_name="some_name") + result = str(components.A([], "link", url_name="some_name")) self.assertIn('href="/resolved/url"', result) def test_a_no_url_or_href(self): - result = components.A([], "link") + result = str(components.A([], "link")) self.assertIn("link", result) self.assertNotIn("href=", result) def test_a_both_url_name_and_href_raises(self): with self.assertRaises(ValueError): - components.A(href="/path", url_name="some_name") + str(components.A(href="/path", url_name="some_name")) def test_button_returns_safe_text(self): - result = components.Button([], "click") + result = str(components.Button([], "click")) self.assertIsInstance(result, SafeText) self.assertIn("", result) self.assertIn("", result) def test_raw_html_children_are_escaped(self): - result = components.Component( - tag_name="div", children=[""] + result = str( + components.Component( + tag_name="div", children=[""] + ) ) self.assertNotIn("