Implemented testing functions

This commit is contained in:
2025-10-25 22:35:15 +02:00
parent 06aff27cad
commit e12e4389b6
3 changed files with 686 additions and 0 deletions

338
tests/test_matches.py Normal file
View File

@@ -0,0 +1,338 @@
import pytest
from fastcore.basics import NotStr
from fasthtml.components import *
from myfasthtml.core.matcher import matches, StartsWith, Contains, DoesNotContain, Empty, DoNotCheck, ErrorOutput, \
ErrorComparisonOutput
from myfasthtml.core.testclient import MyFT
@pytest.mark.parametrize('actual, expected', [
(None, None),
(123, 123),
(Div(), Div()),
([Div(), Span()], [Div(), Span()]),
(Div(attr1="value"), Div(attr1="value")),
(Div(attr1="value", attr2="value"), Div(attr1="value")),
(Div(attr1="valueXXX", attr2="value"), Div(attr1=StartsWith("value"))),
(Div(attr1="before value after", attr2="value"), Div(attr1=Contains("value"))),
(Div(attr1="before after", attr2="value"), Div(attr1=DoesNotContain("value"))),
(None, DoNotCheck()),
(123, DoNotCheck()),
(Div(), DoNotCheck()),
([Div(), Span()], DoNotCheck()),
(NotStr("123456"), NotStr("123")), # for NotStr, only the beginning is checked
(Div(), Div(Empty())),
(Div(123), Div(123)),
(Div(Span(123)), Div(Span(123))),
(Div(Span(123)), Div(DoNotCheck())),
])
def test_i_can_match(actual, expected):
assert matches(actual, expected)
@pytest.mark.parametrize('actual, expected, error_message', [
(None, Div(), "Actual is None"),
(Div(), None, "Actual is not None"),
(123, Div(), "The types are different"),
(123, 124, "The values are different"),
([Div(), Span()], [], "Actual is bigger than expected"),
([], [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(), 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'"),
(Div(attr1="value1"), Div(attr1=StartsWith("value2")), "The condition 'StartsWith(value2)' is not satisfied"),
(Div(attr1="value1"), Div(attr1=Contains("value2")), "The condition 'Contains(value2)' is not satisfied"),
(Div(attr1="value1 value2"), Div(attr1=DoesNotContain("value2")), "The condition 'DoesNotContain(value2)'"),
(NotStr("456"), NotStr("123"), "Notstr values are different"),
(Div(attr="value"), Div(Empty()), "Actual is not empty"),
(Div(120), Div(Empty()), "Actual is not empty"),
(Div(Span()), Div(Empty()), "Actual is not empty"),
(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(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"),
])
def test_i_can_detect_errors(actual, expected, error_message):
with pytest.raises(AssertionError) as exc_info:
matches(actual, expected)
assert error_message in str(exc_info.value)
@pytest.mark.parametrize('element, expected_path', [
(Div(), "Path : 'div"),
(Div(Span()), "Path : 'div.span"),
(Div(Span(Div())), "Path : 'div.span.div"),
(Div(id="div_id"), "Path : 'div#div_id"),
(Div(cls="div_class"), "Path : 'div[class=div_class]"),
(Div(name="div_class"), "Path : 'div[name=div_class]"),
(Div(attr="value"), "Path : 'div"),
(Div(Span(Div(), cls="span_class"), id="div_id"), "Path : 'div#div_id.span[class=span_class].div"),
])
def test_i_can_properly_show_path(element, expected_path):
def _construct_test_element(source, tail):
res = MyFT(source.tag, source.attrs)
if source.children:
res.children = [_construct_test_element(child, tail) for child in source.children]
else:
res.children = [tail]
return res
with pytest.raises(AssertionError) as exc_info:
actual = _construct_test_element(element, "Actual")
expected = _construct_test_element(element, "Expected")
matches(actual, expected)
assert expected_path in str(exc_info.value)
def test_i_can_output_error_path():
elt = Div()
expected = Div()
path = "div#div_id.div.span[class=span_class].p[name=p_name].div"
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "id"="div_id" ...',
' (div ...',
' (span "class"="span_class" ...',
' (p "name"="p_name" ...',
' (div )']
def test_i_can_output_error_attribute():
elt = Div(attr1="value1", attr2="value2")
expected = elt
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1" "attr2"="value2")']
def test_i_can_output_error_attribute_missing_1():
elt = Div(attr2="value2")
expected = Div(attr1="value1", attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="** MISSING **" "attr2"="value2")',
' ^^^^^^^^^^^^^^^^^^^^^^^ ']
def test_i_can_output_error_attribute_missing_2():
elt = Div(attr1="value1")
expected = Div(attr1="value1", attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1" "attr2"="** MISSING **")',
' ^^^^^^^^^^^^^^^^^^^^^^^']
def test_i_can_output_error_attribute_wrong_value():
elt = Div(attr1="value3", attr2="value2")
expected = Div(attr1="value1", attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value3" "attr2"="value2")',
' ^^^^^^^^^^^^^^^^ ']
def test_i_can_output_error_constant():
elt = 123
expected = elt
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['123']
def test_i_can_output_error_constant_wrong_value():
elt = 123
expected = 456
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['123',
'^^^']
def test_i_can_output_error_when_predicate():
elt = "before value after"
expected = Contains("value")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ["before value after"]
def test_i_can_output_error_when_predicate_wrong_value():
elt = "before after"
expected = Contains("value")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ["before after",
"^^^^^^^^^^^^"]
def test_i_can_output_error_child_element():
elt = Div(P(id="p_id"), Div(id="child_1"), Div(id="child_2"), attr1="value1")
expected = elt
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1"',
' (p "id"="p_id")',
' (div "id"="child_1")',
' (div "id"="child_2")',
')',
]
def test_i_can_output_error_child_element_indicating_sub_children():
elt = Div(P(id="p_id"), Div(Div(id="child_2"), id="child_1"), attr1="value1")
expected = elt
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1"',
' (p "id"="p_id")',
' (div "id"="child_1" ...)',
')',
]
def test_i_can_output_error_child_element_wrong_value():
elt = Div(P(id="p_id"), Div(id="child_2"), attr1="value1")
expected = Div(P(id="p_id"), Div(id="child_1"), attr1="value1")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1"',
' (p "id"="p_id")',
' (div "id"="child_2")',
' ^^^^^^^^^^^^^^',
')',
]
def test_i_can_output_error_fewer_elements():
elt = Div(P(id="p_id"), attr1="value1")
expected = Div(P(id="p_id"), Div(id="child_1"), attr1="value1")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(div "attr1"="value1"',
' (p "id"="p_id")',
' ! ** MISSING ** !',
')',
]
def test_i_can_output_comparison():
actual = Div(P(id="p_id"), attr1="value1")
expected = actual
actual_out = ErrorOutput("", actual, expected)
expected_out = ErrorOutput("", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "attr1"="value1" | (div "attr1"="value1"
(p "id"="p_id") | (p "id"="p_id")
) | )'''
def test_i_can_output_comparison_with_path():
actual = Div(P(id="p_id"), attr1="value1")
expected = actual
actual_out = ErrorOutput("div#div_id.span[class=cls].div", actual, expected)
expected_out = ErrorOutput("div#div_id.span[class=cls].div", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "id"="div_id" ... | (div "id"="div_id" ...
(span "class"="cls" ... | (span "class"="cls" ...
(div "attr1"="value1" | (div "attr1"="value1"
(p "id"="p_id") | (p "id"="p_id")
) | )'''
def test_i_can_output_comparison_when_missing_attributes():
actual = Div(P(id="p_id"), attr1="value1")
expected = Div(P(id="p_id"), attr2="value1")
actual_out = ErrorOutput("", actual, expected)
expected_out = ErrorOutput("", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "attr2"="** MISSING **" | (div "attr2"="value1"
^^^^^^^^^^^^^^^^^^^^^^^ |
(p "id"="p_id") | (p "id"="p_id")
) | )'''
def test_i_can_output_comparison_when_wrong_attributes():
actual = Div(P(id="p_id"), attr1="value2")
expected = Div(P(id="p_id"), attr1="value1")
actual_out = ErrorOutput("", actual, expected)
expected_out = ErrorOutput("", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "attr1"="value2" | (div "attr1"="value1"
^^^^^^^^^^^^^^^^ |
(p "id"="p_id") | (p "id"="p_id")
) | )'''
def test_i_can_output_comparison_when_fewer_elements():
actual = Div(P(id="p_id"), attr1="value1")
expected = Div(Span(id="s_id"), P(id="p_id"), attr1="value1")
actual_out = ErrorOutput("", actual, expected)
expected_out = ErrorOutput("", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "attr1"="value1" | (div "attr1"="value1"
(p "id"="p_id") | (span "id"="s_id")
^ ^^^^^^^^^^^ |
! ** MISSING ** ! | (p "id"="p_id")
) | )'''
def test_i_can_see_the_diff_when_matching():
actual = Div(attr1="value1")
expected = Div(attr1=Contains("value2"))
with pytest.raises(AssertionError) as exc_info:
matches(actual, expected)
debug_output = str(exc_info.value)
assert "\n" + debug_output == """
Path : 'div'
Error : The condition 'Contains(value2)' is not satisfied.
(div "attr1"="value1") | (div "attr1"="Contains(value2)")
^^^^^^^^^^^^^^^^ |"""