Refine filters

This commit is contained in:
2026-06-06 19:36:44 +02:00
parent ed8589a972
commit 3ce3356064
8 changed files with 993 additions and 2338 deletions
+26 -4
View File
@@ -1,10 +1,11 @@
"""Characterization tests locking the rendered output of the three filter bars.
The FilterBar family (FilterBar / SessionFilterBar / PurchaseFilterBar) is the
target of an upcoming dedup + module split. These tests pin the structural
contract — form/input ids, the hidden ``filter`` field, preset wiring, the
filter_json round-trip, and no double-escaping — so that refactor stays
behaviour-preserving. The renderers were previously untested.
target of a dedup + module split + RangeSlider component extraction. These tests
pin the structural contract — form/input ids, the hidden ``filter`` field,
preset wiring, the filter_json round-trip, no double-escaping, and the
Flowbite-styled native range slider unification — so that refactor stays
behaviour-preserving.
"""
import json
@@ -41,6 +42,24 @@ class FilterBarRenderingTest(TestCase):
self.assertIn(save_url, html) # preset save URL wired in
self.assertNoEscapedTags(html)
def _assert_range_slider(self, html):
"""Every filter bar must use the RangeSlider component with custom
draggable <div> handles, a track fill, and mode-toggle button."""
self.assertIn("range-slider-block", html)
self.assertIn('data-mode="range"', html)
self.assertIn("range-mode-toggle", html)
self.assertIn("range-mode-icon-range", html)
self.assertIn("range-mode-icon-point", html)
self.assertIn("range-track-fill", html)
self.assertIn("range-handle-min", html)
self.assertIn("range-handle-max", html)
# No native range inputs
self.assertNotIn(
'<input type="range"',
html,
"native <input type=range> found — should use custom div handles",
)
def test_game_filter_bar(self):
html = str(
FilterBar(
@@ -50,6 +69,7 @@ class FilterBarRenderingTest(TestCase):
)
)
self._assert_shell(html, "/presets/games/list", "/presets/games/save")
self._assert_range_slider(html)
def test_session_filter_bar(self):
html = str(
@@ -60,6 +80,7 @@ class FilterBarRenderingTest(TestCase):
)
)
self._assert_shell(html, "/presets/sessions/list", "/presets/sessions/save")
self._assert_range_slider(html)
def test_purchase_filter_bar(self):
html = str(
@@ -70,6 +91,7 @@ class FilterBarRenderingTest(TestCase):
)
)
self._assert_shell(html, "/presets/purchases/list", "/presets/purchases/save")
self._assert_range_slider(html)
def test_game_filter_bar_roundtrips_selected_status(self):
"""A status in filter_json renders as a selected tag in the widget."""
+68
View File
@@ -0,0 +1,68 @@
"""Unit tests for filter JSON parsing helpers."""
from django.test import SimpleTestCase
from common.components.filters import _parse_bool, _parse_range
class ParseRangeTest(SimpleTestCase):
def test_empty_dict(self):
self.assertEqual(_parse_range({}, "field"), ("", ""))
def test_missing_key(self):
self.assertEqual(_parse_range({"other": 1}, "field"), ("", ""))
def test_null_value(self):
self.assertEqual(_parse_range({"field": None}, "field"), ("", ""))
def test_non_dict_value(self):
"""A non-dict field value is coerced to ("", "")."""
self.assertEqual(_parse_range({"field": "not_a_dict"}, "field"), ("", ""))
def test_value_only(self):
self.assertEqual(_parse_range({"field": {"value": "10"}}, "field"), ("10", ""))
def test_value_and_value2(self):
self.assertEqual(
_parse_range({"field": {"value": "10", "value2": "20"}}, "field"),
("10", "20"),
)
def test_empty_strings(self):
self.assertEqual(
_parse_range({"field": {"value": "", "value2": ""}}, "field"), ("", "")
)
def test_integer_values_become_strings(self):
self.assertEqual(
_parse_range({"field": {"value": 5, "value2": 15}}, "field"),
("5", "15"),
)
class ParseBoolTest(SimpleTestCase):
def test_empty_dict(self):
self.assertFalse(_parse_bool({}, "field"))
def test_missing_key(self):
self.assertFalse(_parse_bool({"other": 1}, "field"))
def test_null_value(self):
self.assertFalse(_parse_bool({"field": None}, "field"))
def test_non_dict_value(self):
"""A non-dict field value is coerced to False."""
self.assertFalse(_parse_bool({"field": "not_a_dict"}, "field"))
def test_false_value(self):
self.assertFalse(_parse_bool({"field": {"value": False}}, "field"))
def test_true_value(self):
self.assertTrue(_parse_bool({"field": {"value": True}}, "field"))
def test_truthy_string(self):
"""Non-empty strings are truthy — bool("yes") is True."""
self.assertTrue(_parse_bool({"field": {"value": "yes"}}, "field"))
def test_missing_value_in_field(self):
self.assertFalse(_parse_bool({"field": {}}, "field"))