""" Comprehensive binding tests for all bindable FastHTML components. This test suite covers: - Input (text) - already tested - Checkbox - already tested - Textarea - Select (single) - Select (multiple) - Range (slider) - Radio buttons - Button - Input with Datalist (combobox) """ from dataclasses import dataclass import pytest from fasthtml.components import ( Input, Label, Textarea ) from fasthtml.fastapp import fast_app from myfasthtml.controls.helpers import mk from myfasthtml.core.bindings import Binding from myfasthtml.test.testclient import MyTestClient @dataclass class Data: value: str = "hello world" @dataclass class NumericData: value: int = 50 @dataclass class BoolData: value: bool = True @dataclass class ListData: value: list = None def __post_init__(self): if self.value is None: self.value = [] @pytest.fixture def test_app(): test_app, rt = fast_app(default_hdrs=False) return test_app @pytest.fixture def rt(test_app): return test_app.route @pytest.fixture def user(test_app): return MyTestClient(test_app) class TestBindingEdgeCases: """Tests for edge cases and special scenarios.""" def test_multiple_components_bind_to_same_data(self, user, rt): """ Multiple different components can bind to the same data object. """ @rt("/") def index(): data = Data("synchronized") input_elt = Input(name="input_name") textarea_elt = Textarea(name="textarea_name") label_elt = Label() mk.manage_binding(input_elt, Binding(data)) mk.manage_binding(textarea_elt, Binding(data)) mk.manage_binding(label_elt, Binding(data)) return input_elt, textarea_elt, label_elt user.open("/") user.should_see("synchronized") # Change via input testable_input = user.find_element("input") testable_input.send("changed via input") user.should_see("changed via input") # Change via textarea testable_textarea = user.find_element("textarea") testable_textarea.send("changed via textarea") user.should_see("changed via textarea") def test_component_without_name_attribute(self, user, rt): """ Component without name attribute should handle gracefully. """ @rt("/") def index(): data = Data("test") # Input without name - should not crash input_elt = Input() # No name attribute label_elt = Label() mk.manage_binding(label_elt, Binding(data)) return input_elt, label_elt user.open("/") user.should_see("test") def test_binding_with_initial_empty_string(self, user, rt): """ Binding should work correctly with empty string initial values. """ @rt("/") def index(): data = Data("") input_elt = Input(name="input_name") label_elt = Label() mk.manage_binding(input_elt, Binding(data)) mk.manage_binding(label_elt, Binding(data)) return input_elt, label_elt user.open("/") testable_input = user.find_element("input") testable_input.send("now has value") user.should_see("now has value") def test_binding_with_special_characters(self, user, rt): """ Binding should handle special characters correctly. """ @rt("/") def index(): data = Data("Hello") input_elt = Input(name="input_name") label_elt = Label() mk.manage_binding(input_elt, Binding(data)) mk.manage_binding(label_elt, Binding(data)) return input_elt, label_elt user.open("/") testable_input = user.find_element("input") testable_input.send("Special: <>&\"'") user.should_see("Special: <>&\"'")