I can bind datalist and range

This commit is contained in:
2025-11-09 10:51:16 +01:00
parent 255f145aca
commit 42e8566bcf
8 changed files with 240 additions and 269 deletions

View File

@@ -18,7 +18,7 @@ from typing import Any
import pytest
from fasthtml.components import (
Input, Label, Textarea, Select, Option, Button, Datalist
Input, Label, Textarea, Select, Option, Datalist
)
from fasthtml.fastapp import fast_app
@@ -468,7 +468,59 @@ class TestBindingSelectMultiple:
class TestBindingRange:
"""Tests for binding Range (slider) components."""
def test_i_can_bind_range(self, user, rt):
def test_i_can_bind_range(self):
data = Data(50)
range_elt = Input(
type="range",
name="range_name",
min="0",
max="100",
value="50"
)
binding = Binding(data)
updated = mk.manage_binding(range_elt, binding)
expected = Input(
AttributeForbidden("hx_swap_oob"),
type="range",
name="range_name",
min="0",
max="100",
value=50,
hx_post=f"{ROUTE_ROOT}{Routes.Bindings}",
id=AnyValue(),
)
assert matches(updated, expected)
def test_i_can_update_range(self):
data = Data(50)
range_elt = Input(
type="range",
name="range_name",
min="0",
max="100",
value="50"
)
binding = Binding(data)
mk.manage_binding(range_elt, binding)
res = binding.update({"range_name": 25})
expected = [Input(
type="range",
name="range_name",
min="0",
max="100",
value=25,
hx_post=f"{ROUTE_ROOT}{Routes.Bindings}",
id=AnyValue(),
hx_swap_oob="true"
)]
assert matches(res, expected)
def test_i_can_bind_range_with_label(self, user, rt):
"""
Range input should bind with numeric data.
Changing the slider should update the label.
@@ -642,138 +694,23 @@ class TestBindingRadio:
user.should_see("option2")
class TestBindingButton:
"""Tests for binding Button components."""
def test_i_can_click_button_with_binding(self, user, rt):
"""
Clicking a button with HTMX should trigger binding updates.
"""
@rt("/")
def index():
data = Data("initial")
button_elt = Button("Click me", hx_post="/update", hx_vals='{"action": "clicked"}')
label_elt = Label()
mk.manage_binding(button_elt, Binding(data))
mk.manage_binding(label_elt, Binding(data))
return button_elt, label_elt
@rt("/update")
def update(action: str):
data = Data("button clicked")
label_elt = Label()
mk.manage_binding(label_elt, Binding(data))
return label_elt
user.open("/")
user.should_see("initial")
testable_button = user.find_element("button")
testable_button.click()
user.should_see("button clicked")
def test_button_without_htmx_does_nothing(self, user, rt):
"""
Button without HTMX should not trigger updates.
"""
@rt("/")
def index():
data = Data("initial")
button_elt = Button("Plain button") # No HTMX
label_elt = Label()
mk.manage_binding(button_elt, Binding(data))
mk.manage_binding(label_elt, Binding(data))
return button_elt, label_elt
user.open("/")
user.should_see("initial")
testable_button = user.find_element("button")
result = testable_button.click()
assert result is None # No HTMX, no response
class TestBindingDatalist:
"""Tests for binding Input with Datalist (combobox)."""
def test_i_can_bind_input_with_datalist(self, user, rt):
"""
Input with datalist should allow both free text and suggestions.
"""
def test_i_can_bind_datalist(self):
data = Data(["suggestion2"])
datalist = Datalist(
Option(value="suggestion1"),
id="suggestions"
)
@rt("/")
def index():
data = Data("")
datalist = Datalist(
Option(value="suggestion1"),
Option(value="suggestion2"),
Option(value="suggestion3"),
id="suggestions"
)
input_elt = Input(
name="input_name",
list="suggestions"
)
label_elt = Label()
mk.manage_binding(input_elt, Binding(data))
mk.manage_binding(label_elt, Binding(data))
return input_elt, datalist, label_elt
updated = mk.manage_binding(datalist, Binding(data))
expected = Datalist(
Option(value="suggestion2"),
id="suggestions"
)
user.open("/")
user.should_see("")
testable_input = user.find_element("input[list='suggestions']")
# Can type free text
testable_input.send("custom value")
user.should_see("custom value")
# Can select from suggestions
testable_input.select_suggestion("suggestion2")
user.should_see("suggestion2")
def test_datalist_suggestions_are_available(self, user, rt):
"""
Datalist suggestions should be accessible for validation.
"""
@rt("/")
def index():
data = Data("")
datalist = Datalist(
Option(value="apple"),
Option(value="banana"),
Option(value="cherry"),
id="fruits"
)
input_elt = Input(
name="input_name",
list="fruits"
)
label_elt = Label()
mk.manage_binding(input_elt, Binding(data))
mk.manage_binding(label_elt, Binding(data))
return input_elt, datalist, label_elt
user.open("/")
testable_input = user.find_element("input[list='fruits']")
# Check that suggestions are available
suggestions = testable_input.suggestions
assert "apple" in suggestions
assert "banana" in suggestions
assert "cherry" in suggestions
assert matches(updated, expected)
class TestBindingEdgeCases: