I can bind elements

This commit is contained in:
2025-11-01 23:44:18 +01:00
parent 991a6f07ff
commit aaba6a5468
14 changed files with 463 additions and 109 deletions

0
tests/core/__init__.py Normal file
View File

View File

@@ -0,0 +1,96 @@
from dataclasses import dataclass
import pytest
from fasthtml.components import Label, Input
from myutils.observable import collect_return_values
from myfasthtml.core.bindings import BindingsManager, Binding
@dataclass
class Data:
value: str = "Hello World"
@pytest.fixture(autouse=True)
def reset_binding_manager():
BindingsManager.reset()
@pytest.fixture()
def data():
return Data()
def test_i_can_register_a_binding(data):
binding = Binding(data, "value")
assert binding.id is not None
assert binding.data is data
assert binding.data_attr == 'value'
def test_i_can_register_a_binding_with_default_attr(data):
binding = Binding(data)
assert binding.id is not None
assert binding.data is data
assert binding.data_attr == 'value'
def test_i_can_retrieve_a_registered_binding(data):
binding = Binding(data)
assert BindingsManager.get_binding(binding.id) is binding
def test_i_can_reset_bindings(data):
Binding(data)
assert len(BindingsManager.bindings) != 0
BindingsManager.reset()
assert len(BindingsManager.bindings) == 0
def test_i_can_bind_an_element_to_a_binding(data):
elt = Label("hello", id="label_id")
Binding(data, ft=elt)
data.value = "new value"
assert elt.children[0] == "new value"
assert elt.attrs["hx-swap-oob"] == "true"
assert elt.attrs["id"] == "label_id"
def test_i_can_bind_an_element_attr_to_a_binding(data):
elt = Input(value="somme value", id="input_id")
Binding(data, ft=elt, ft_attr="value")
data.value = "new value"
assert elt.attrs["value"] == "new value"
assert elt.attrs["hx-swap-oob"] == "true"
assert elt.attrs["id"] == "input_id"
def test_bound_element_has_an_id():
elt = Label("hello")
assert elt.attrs.get("id", None) is None
Binding(Data(), ft=elt)
assert elt.attrs.get("id", None) is not None
def test_i_can_collect_updates_values(data):
elt = Label("hello")
Binding(data, ft=elt)
data.value = "new value"
collected = collect_return_values(data)
assert collected == [elt]
# a second time to ensure no side effect
data.value = "another value"
collected = collect_return_values(data)
assert collected == [elt]

View File

@@ -8,7 +8,7 @@ def callback():
@pytest.fixture(autouse=True)
def test_reset_command_manager():
def reset_command_manager():
CommandsManager.reset()

79
tests/test_integration.py Normal file
View File

@@ -0,0 +1,79 @@
from dataclasses import dataclass
import pytest
from fasthtml.components import Input, Label
from fasthtml.fastapp import fast_app
from myfasthtml.controls.helpers import mk
from myfasthtml.core.bindings import Binding
from myfasthtml.core.commands import Command, CommandsManager
from myfasthtml.test.testclient import MyTestClient, TestableElement
def new_value(value):
return value
@dataclass
class Data:
value: str
@pytest.fixture()
def user():
test_app, rt = fast_app(default_hdrs=False)
user = MyTestClient(test_app)
return user
@pytest.fixture()
def rt(user):
return user.app.route
class TestingCommand:
def test_i_can_trigger_a_command(self, user):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
testable = TestableElement(user, mk.button('button', command))
testable.click()
assert user.get_content() == "this is my new value"
def test_error_is_raised_when_command_is_not_found(self, user):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
CommandsManager.reset()
testable = TestableElement(user, mk.button('button', command))
with pytest.raises(ValueError) as exc_info:
testable.click()
assert "not found." in str(exc_info.value)
def test_i_can_play_a_complex_scenario(self, user, rt):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
@rt('/')
def get(): return mk.button('button', command)
user.open("/")
user.should_see("button")
user.find_element("button").click()
user.should_see("this is my new value")
class TestingBindings:
def test_i_can_bind_elements(self, user, rt):
@rt("/")
def index():
data = Data("hello world")
input_elt = Input(name="input_name")
label_elt = Label()
mk.manage_binding(input_elt, Binding(data, ft_attr="value"))
mk.manage_binding(label_elt, Binding(data))
return input_elt, label_elt
user.open("/")
user.should_see("")
testable_input = user.find_element("input")
testable_input.send("new value")
user.should_see("new value") # the one from the label

View File

@@ -1,53 +0,0 @@
import pytest
from fasthtml.fastapp import fast_app
from myfasthtml.controls.helpers import mk
from myfasthtml.core.commands import Command, CommandsManager
from myfasthtml.test.testclient import MyTestClient, TestableElement
def new_value(value):
return value
@pytest.fixture()
def user():
test_app, rt = fast_app(default_hdrs=False)
user = MyTestClient(test_app)
return user
@pytest.fixture()
def rt(user):
return user.app.route
def test_i_can_trigger_a_command(user):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
testable = TestableElement(user, mk.button('button', command))
testable.click()
assert user.get_content() == "this is my new value"
def test_error_is_raised_when_command_is_not_found(user):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
CommandsManager.reset()
testable = TestableElement(user, mk.button('button', command))
with pytest.raises(ValueError) as exc_info:
testable.click()
assert "not found." in str(exc_info.value)
def test_i_can_play_a_complex_scenario(user, rt):
command = Command('test', 'TestingCommand', new_value, "this is my new value")
@rt('/')
def get(): return mk.button('button', command)
user.open("/")
user.should_see("button")
user.find_element("button").click()
user.should_see("this is my new value")