Added Controls testing + documentation
This commit is contained in:
@@ -1,7 +1,22 @@
|
||||
import pytest
|
||||
from fasthtml.components import Div, Span
|
||||
from fastcore.basics import NotStr
|
||||
from fasthtml.components import Div, Span, Main
|
||||
|
||||
from myfasthtml.test.matcher import find
|
||||
from myfasthtml.test.matcher import find, TestObject, Contains, StartsWith
|
||||
|
||||
|
||||
class Dummy:
|
||||
def __init__(self, attr1, attr2=None):
|
||||
self.attr1 = attr1
|
||||
self.attr2 = attr2
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, Dummy)
|
||||
and self.attr1 == other.attr1
|
||||
and self.attr2 == other.attr2)
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.attr1, self.attr2))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ft, expected', [
|
||||
@@ -9,10 +24,13 @@ from myfasthtml.test.matcher import find
|
||||
(Div(id="id1"), Div(id="id1")),
|
||||
(Div(Span(id="span_id"), id="div_id1"), Div(Span(id="span_id"), id="div_id1")),
|
||||
(Div(id="id1", id2="id2"), Div(id="id1")),
|
||||
(Div(Div(id="id2"), id2="id1"), Div(id="id1")),
|
||||
(Div(Div(id="id2"), id="id1"), Div(id="id1")),
|
||||
(Dummy(attr1="value"), Dummy(attr1="value")),
|
||||
(Dummy(attr1="value"), TestObject(Dummy, attr1="value")),
|
||||
(Div(attr="value1 value2"), Div(attr=Contains("value1"))),
|
||||
])
|
||||
def test_i_can_find(ft, expected):
|
||||
assert find(expected, expected) == [expected]
|
||||
assert find(ft, expected) == [ft]
|
||||
|
||||
|
||||
def test_find_element_by_id_in_a_list():
|
||||
@@ -25,12 +43,41 @@ def test_find_element_by_id_in_a_list():
|
||||
|
||||
def test_i_can_find_sub_element():
|
||||
a = Div(id="id1")
|
||||
b = Div(a, id="id2")
|
||||
c = Div(b, id="id3")
|
||||
b = Span(a, id="id2")
|
||||
c = Main(b, id="id3")
|
||||
|
||||
assert find(c, a) == [a]
|
||||
|
||||
|
||||
def test_i_can_find_when_pattern_appears_also_in_children():
|
||||
a1 = Div(id="id1")
|
||||
b = Div(a1, id="id2")
|
||||
a2 = Div(b, id="id1")
|
||||
c = Main(a2, id="id3")
|
||||
|
||||
assert find(c, a1) == [a2, a1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ft, to_search, expected', [
|
||||
(NotStr("hello"), NotStr("hello"), [NotStr("hello")]),
|
||||
(NotStr("hello my friend"), NotStr("hello"), NotStr("hello my friend")),
|
||||
(NotStr("hello"), TestObject(NotStr, s="hello"), [NotStr("hello")]),
|
||||
(NotStr("hello my friend"), TestObject(NotStr, s=StartsWith("hello")), NotStr("hello my friend")),
|
||||
])
|
||||
def test_i_can_manage_notstr_success_path(ft, to_search, expected):
|
||||
assert find(ft, to_search) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ft, to_search', [
|
||||
(NotStr("my friend"), NotStr("hello")),
|
||||
(NotStr("hello"), Dummy(attr1="hello")), # important, because of the internal __eq__ of NotStr
|
||||
(NotStr("hello my friend"), TestObject(NotStr, s="hello")),
|
||||
])
|
||||
def test_test_i_can_manage_notstr_failure_path(ft, to_search):
|
||||
with pytest.raises(AssertionError):
|
||||
find(ft, to_search)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ft, expected', [
|
||||
(None, Div(id="id1")),
|
||||
(Span(id="id1"), Div(id="id1")),
|
||||
|
||||
@@ -2,8 +2,11 @@ import pytest
|
||||
from fastcore.basics import NotStr
|
||||
from fasthtml.components import *
|
||||
|
||||
from myfasthtml.test.matcher import matches, StartsWith, Contains, DoesNotContain, Empty, DoNotCheck, ErrorOutput, \
|
||||
ErrorComparisonOutput, AttributeForbidden, AnyValue, NoChildren, TestObject
|
||||
from myfasthtml.controls.helpers import mk
|
||||
from myfasthtml.core.commands import Command
|
||||
from myfasthtml.icons.fluent_p3 import add20_regular
|
||||
from myfasthtml.test.matcher import matches, StartsWith, Contains, DoesNotContain, Empty, ErrorOutput, \
|
||||
ErrorComparisonOutput, AttributeForbidden, AnyValue, NoChildren, TestObject, Skip, DoNotCheck, TestIcon, HasHtmx
|
||||
from myfasthtml.test.testclient import MyFT
|
||||
|
||||
|
||||
@@ -50,6 +53,12 @@ class TestMatches:
|
||||
(Dummy(123, "value"), TestObject(Dummy, attr2="value")),
|
||||
(Div(Dummy(123, "value")), Div(TestObject(Dummy, attr1=123))),
|
||||
(Dummy(123, "value"), TestObject("Dummy", attr1=123, attr2="value")),
|
||||
(mk.icon(add20_regular), TestIcon("Add20Regular")),
|
||||
(mk.icon(add20_regular), TestIcon("add20_regular")),
|
||||
(mk.icon(add20_regular), TestIcon()),
|
||||
(Div(None, None, None, Div(id="to_find")), Div(Skip(None), Div(id="to_find"))),
|
||||
(Div(Div(id="to_skip"), Div(id="to_skip"), Div(id="to_find")), Div(Skip(Div(id="to_skip")), Div(id="to_find"))),
|
||||
(Div(hx_post="/url"), Div(HasHtmx(hx_post="/url"))),
|
||||
])
|
||||
def test_i_can_match(self, actual, expected):
|
||||
assert matches(actual, expected)
|
||||
@@ -63,8 +72,8 @@ class TestMatches:
|
||||
([], [Div(), Span()], "Actual is smaller than expected"),
|
||||
("not a list", [Div(), Span()], "The types are different"),
|
||||
([Div(), Span()], [Div(), 123], "The types are different"),
|
||||
(Div(), Span(), "The elements are different"),
|
||||
([Div(), Span()], [Div(), Div()], "The elements are different"),
|
||||
(Div(), Span(), "The types are different"),
|
||||
([Div(), Span()], [Div(), Div()], "The types are different"),
|
||||
(Div(), Div(attr1="value"), "'attr1' is not found in Actual"),
|
||||
(Div(attr2="value"), Div(attr1="value"), "'attr1' is not found in Actual"),
|
||||
(Div(attr1="value1"), Div(attr1="value2"), "The values are different for 'attr1'"),
|
||||
@@ -80,21 +89,23 @@ class TestMatches:
|
||||
(Div(Span()), Div(Empty()), "The condition 'Empty()' is not satisfied"),
|
||||
(Div(), Div(Span()), "Actual is lesser than expected"),
|
||||
(Div(), Div(123), "Actual is lesser than expected"),
|
||||
(Div(Span()), Div(Div()), "The elements are different"),
|
||||
(Div(Span()), Div(Div()), "The types are different"),
|
||||
(Div(123), Div(Div()), "The types are different"),
|
||||
(Div(123), Div(456), "The values are different"),
|
||||
(Div(Span(), Span()), Div(Span(), Div()), "The elements are different"),
|
||||
(Div(Span(Div())), Div(Span(Span())), "The elements are different"),
|
||||
(Div(Span(), Span()), Div(Span(), Div()), "The types are different"),
|
||||
(Div(Span(Div())), Div(Span(Span())), "The types are different"),
|
||||
(Div(attr1="value1"), Div(AttributeForbidden("attr1")), "condition 'AttributeForbidden(attr1)' is not satisfied"),
|
||||
(Div(123, "value"), TestObject(Dummy, attr1=123, attr2="value2"), "The types are different:"),
|
||||
(Div(123, "value"), TestObject(Dummy, attr1=123, attr2="value2"), "The types are different"),
|
||||
(Dummy(123, "value"), TestObject(Dummy, attr1=123, attr3="value3"), "'attr3' is not found in Actual"),
|
||||
(Dummy(123, "value"), TestObject(Dummy, attr1=123, attr2="value2"), "The values are different for 'attr2'"),
|
||||
(Div(Div(123, "value")), Div(TestObject(Dummy, attr1=123, attr2="value2")), "The types are different:"),
|
||||
(Div(Div(123, "value")), Div(TestObject(Dummy, attr1=123, attr2="value2")), "The types are different"),
|
||||
(Div(Dummy(123, "value")), Div(TestObject(Dummy, attr1=123, attr3="value3")), "'attr3' is not found in Actual"),
|
||||
(Div(Dummy(123, "value")), Div(TestObject(Dummy, attr1=123, attr2="value2")), "are different for 'attr2'"),
|
||||
(Div(123, "value"), TestObject("Dummy", attr1=123, attr2="value2"), "The types are different:"),
|
||||
(Dummy(123, "value"), TestObject("Dummy", attr1=123, attr2=Contains("value2")), "The condition 'Contains(value2)' is not satisfied"),
|
||||
|
||||
(Div(123, "value"), TestObject("Dummy", attr1=123, attr2="value2"), "The types are different"),
|
||||
(Dummy(123, "value"), TestObject("Dummy", attr1=123, attr2=Contains("value2")),
|
||||
"The condition 'Contains(value2)' is not satisfied"),
|
||||
(Div(Div(id="to_skip")), Div(Skip(Div(id="to_skip"))), "Nothing more to skip"),
|
||||
(Div(hx_post="/url"), Div(HasHtmx(hx_post="/url2")), "The condition 'HasHtmx()' is not satisfied"),
|
||||
])
|
||||
def test_i_can_detect_errors(self, actual, expected, error_message):
|
||||
with pytest.raises(AssertionError) as exc_info:
|
||||
@@ -440,3 +451,20 @@ Error : The condition 'Contains(value2)' is not satisfied.
|
||||
assert "\n" + res == '''
|
||||
(div "attr1"="123" "attr2"="value2") | (Dummy "attr1"="123" "attr2"="value2")
|
||||
^^^ |'''
|
||||
|
||||
|
||||
class TestPredicates:
|
||||
def test_i_can_validate_contains_with_words_only(self):
|
||||
assert Contains("value", _word=True).validate("value value2 value3")
|
||||
assert Contains("value", "value2", _word=True).validate("value value2 value3")
|
||||
|
||||
assert not Contains("value", _word=True).validate("valuevalue2value3")
|
||||
assert not Contains("value value2", _word=True).validate("value value2 value3")
|
||||
|
||||
def test_i_can_validate_has_htmx(self):
|
||||
div = Div(hx_post="/url")
|
||||
assert HasHtmx(hx_post="/url").validate(div)
|
||||
|
||||
c = Command("c", "testing has_htmx", None)
|
||||
c.bind_ft(div)
|
||||
assert HasHtmx(command=c).validate(div)
|
||||
|
||||
Reference in New Issue
Block a user