Added first controls
This commit is contained in:
@@ -2,10 +2,10 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from fasthtml.components import Button
|
||||
from fasthtml.components import Button, Div
|
||||
from myutils.observable import make_observable, bind
|
||||
|
||||
from myfasthtml.core.commands import Command, CommandsManager
|
||||
from myfasthtml.core.commands import Command, CommandsManager, LambdaCommand
|
||||
from myfasthtml.core.constants import ROUTE_ROOT, Routes
|
||||
from myfasthtml.test.matcher import matches
|
||||
|
||||
@@ -24,72 +24,173 @@ def reset_command_manager():
|
||||
CommandsManager.reset()
|
||||
|
||||
|
||||
def test_i_can_create_a_command_with_no_params():
|
||||
command = Command('test', 'Command description', callback)
|
||||
assert command.id is not None
|
||||
assert command.name == 'test'
|
||||
assert command.description == 'Command description'
|
||||
assert command.execute() == "Hello World"
|
||||
class TestCommandDefault:
|
||||
|
||||
def test_i_can_create_a_command_with_no_params(self):
|
||||
command = Command('test', 'Command description', callback)
|
||||
assert command.id is not None
|
||||
assert command.name == 'test'
|
||||
assert command.description == 'Command description'
|
||||
assert command.execute() == "Hello World"
|
||||
|
||||
def test_command_are_registered(self):
|
||||
command = Command('test', 'Command description', callback)
|
||||
assert CommandsManager.commands.get(str(command.id)) is command
|
||||
|
||||
|
||||
def test_command_are_registered():
|
||||
command = Command('test', 'Command description', callback)
|
||||
assert CommandsManager.commands.get(str(command.id)) is command
|
||||
class TestCommandBind:
|
||||
|
||||
def test_i_can_bind_a_command_to_an_element(self):
|
||||
command = Command('test', 'Command description', callback)
|
||||
elt = Button()
|
||||
updated = command.bind_ft(elt)
|
||||
|
||||
expected = Button(hx_post=f"{ROUTE_ROOT}{Routes.Commands}")
|
||||
|
||||
assert matches(updated, expected)
|
||||
|
||||
def test_i_can_suppress_swapping_with_target_attr(self):
|
||||
command = Command('test', 'Command description', callback).htmx(target=None)
|
||||
elt = Button()
|
||||
updated = command.bind_ft(elt)
|
||||
|
||||
expected = Button(hx_post=f"{ROUTE_ROOT}{Routes.Commands}", hx_swap="none")
|
||||
|
||||
assert matches(updated, expected)
|
||||
|
||||
def test_i_can_bind_a_command_to_an_observable(self):
|
||||
data = Data("hello")
|
||||
|
||||
def on_data_change(old, new):
|
||||
return old, new
|
||||
|
||||
def another_callback():
|
||||
data.value = "new value"
|
||||
return "another callback result"
|
||||
|
||||
make_observable(data)
|
||||
bind(data, "value", on_data_change)
|
||||
command = Command('test', 'Command description', another_callback).bind(data)
|
||||
|
||||
res = command.execute()
|
||||
|
||||
assert res == ["another callback result", ("hello", "new value")]
|
||||
|
||||
def test_i_can_bind_a_command_to_an_observable_2(self):
|
||||
data = Data("hello")
|
||||
|
||||
def on_data_change(old, new):
|
||||
return old, new
|
||||
|
||||
def another_callback():
|
||||
data.value = "new value"
|
||||
return ["another 1", "another 2"]
|
||||
|
||||
make_observable(data)
|
||||
bind(data, "value", on_data_change)
|
||||
command = Command('test', 'Command description', another_callback).bind(data)
|
||||
|
||||
res = command.execute()
|
||||
|
||||
assert res == ["another 1", "another 2", ("hello", "new value")]
|
||||
|
||||
def test_by_default_swap_is_set_to_outer_html(self):
|
||||
command = Command('test', 'Command description', callback)
|
||||
elt = Button()
|
||||
updated = command.bind_ft(elt)
|
||||
|
||||
expected = Button(hx_post=f"{ROUTE_ROOT}{Routes.Commands}", hx_swap="outerHTML")
|
||||
|
||||
assert matches(updated, expected)
|
||||
|
||||
@pytest.mark.parametrize("return_values", [
|
||||
[Div(), Div(id="id1"), "hello", Div(id="id2")], # list
|
||||
(Div(), Div(id="id1"), "hello", Div(id="id2")) # tuple
|
||||
])
|
||||
def test_swap_oob_is_automatically_set_when_multiple_elements_are_returned(self, return_values):
|
||||
"""Test that hx-swap-oob is automatically set, but not for the first."""
|
||||
|
||||
def another_callback():
|
||||
return return_values
|
||||
|
||||
command = Command('test', 'Command description', another_callback)
|
||||
|
||||
res = command.execute()
|
||||
|
||||
assert "hx_swap_oob" not in res[0].attrs
|
||||
assert res[1].attrs["hx-swap-oob"] == "true"
|
||||
assert res[3].attrs["hx-swap-oob"] == "true"
|
||||
|
||||
|
||||
def test_i_can_bind_a_command_to_an_element():
|
||||
command = Command('test', 'Command description', callback)
|
||||
elt = Button()
|
||||
updated = command.bind_ft(elt)
|
||||
class TestCommandExecute:
|
||||
|
||||
expected = Button(hx_post=f"{ROUTE_ROOT}{Routes.Commands}")
|
||||
def test_i_can_create_a_command_with_no_params(self):
|
||||
command = Command('test', 'Command description', callback)
|
||||
assert command.id is not None
|
||||
assert command.name == 'test'
|
||||
assert command.description == 'Command description'
|
||||
assert command.execute() == "Hello World"
|
||||
|
||||
assert matches(updated, expected)
|
||||
def test_i_can_execute_a_command_with_closed_parameter(self):
|
||||
"""The parameter is given when the command is created."""
|
||||
|
||||
def callback_with_param(param):
|
||||
return f"Hello {param}"
|
||||
|
||||
command = Command('test', 'Command description', callback_with_param, "world")
|
||||
assert command.execute() == "Hello world"
|
||||
|
||||
def test_i_can_execute_a_command_with_open_parameter(self):
|
||||
"""The parameter is given by the browser, when the command is executed."""
|
||||
|
||||
def callback_with_param(name):
|
||||
return f"Hello {name}"
|
||||
|
||||
command = Command('test', 'Command description', callback_with_param)
|
||||
assert command.execute(client_response={"name": "world"}) == "Hello world"
|
||||
|
||||
def test_i_can_convert_arg_in_execute(self):
|
||||
"""The parameter is given by the browser, when the command is executed."""
|
||||
|
||||
def callback_with_param(number: int):
|
||||
assert isinstance(number, int)
|
||||
|
||||
command = Command('test', 'Command description', callback_with_param)
|
||||
command.execute(client_response={"number": "10"})
|
||||
|
||||
def test_swap_oob_is_added_when_multiple_elements_are_returned(self):
|
||||
"""Test that hx-swap-oob is automatically set, but not for the first."""
|
||||
|
||||
def another_callback():
|
||||
return Div(id="first"), Div(id="second"), "hello", Div(id="third")
|
||||
|
||||
command = Command('test', 'Command description', another_callback)
|
||||
|
||||
res = command.execute()
|
||||
assert "hx-swap-oob" not in res[0].attrs
|
||||
assert res[1].attrs["hx-swap-oob"] == "true"
|
||||
assert res[3].attrs["hx-swap-oob"] == "true"
|
||||
|
||||
def test_swap_oob_is_not_added_when_there_no_id(self):
|
||||
"""Test that hx-swap-oob is automatically set, but not for the first."""
|
||||
|
||||
def another_callback():
|
||||
return Div(id="first"), Div(), "hello", Div()
|
||||
|
||||
command = Command('test', 'Command description', another_callback)
|
||||
|
||||
res = command.execute()
|
||||
assert "hx-swap-oob" not in res[0].attrs
|
||||
assert "hx-swap-oob" not in res[1].attrs
|
||||
assert "hx-swap-oob" not in res[3].attrs
|
||||
|
||||
|
||||
def test_i_can_suppress_swapping_with_target_attr():
|
||||
command = Command('test', 'Command description', callback).htmx(target=None)
|
||||
elt = Button()
|
||||
updated = command.bind_ft(elt)
|
||||
class TestLambaCommand:
|
||||
|
||||
expected = Button(hx_post=f"{ROUTE_ROOT}{Routes.Commands}", hx_swap="none")
|
||||
def test_i_can_create_a_command_from_lambda(self):
|
||||
command = LambdaCommand(lambda resp: "Hello World")
|
||||
assert command.execute() == "Hello World"
|
||||
|
||||
assert matches(updated, expected)
|
||||
|
||||
|
||||
def test_i_can_bind_a_command_to_an_observable():
|
||||
data = Data("hello")
|
||||
|
||||
def on_data_change(old, new):
|
||||
return old, new
|
||||
|
||||
def another_callback():
|
||||
data.value = "new value"
|
||||
return "another callback result"
|
||||
|
||||
make_observable(data)
|
||||
bind(data, "value", on_data_change)
|
||||
command = Command('test', 'Command description', another_callback).bind(data)
|
||||
|
||||
res = command.execute()
|
||||
|
||||
assert res == ["another callback result", ("hello", "new value")]
|
||||
|
||||
|
||||
def test_i_can_bind_a_command_to_an_observable_2():
|
||||
data = Data("hello")
|
||||
|
||||
def on_data_change(old, new):
|
||||
return old, new
|
||||
|
||||
def another_callback():
|
||||
data.value = "new value"
|
||||
return ["another 1", "another 2"]
|
||||
|
||||
make_observable(data)
|
||||
bind(data, "value", on_data_change)
|
||||
command = Command('test', 'Command description', another_callback).bind(data)
|
||||
|
||||
res = command.execute()
|
||||
|
||||
assert res == ["another 1", "another 2", ("hello", "new value")]
|
||||
def test_by_default_target_is_none(self):
|
||||
command = LambdaCommand(lambda resp: "Hello World")
|
||||
assert command.get_htmx_params()["hx-swap"] == "none"
|
||||
|
||||
Reference in New Issue
Block a user