Added TreeView and Panel

This commit is contained in:
2025-11-29 18:15:20 +01:00
parent ce5328fe34
commit 1d20fb8650
21 changed files with 2343 additions and 366 deletions

View File

@@ -3,361 +3,440 @@ 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
ErrorComparisonOutput, AttributeForbidden, AnyValue, NoChildren, TestObject
from myfasthtml.test.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"))),
(Div(attr1="value"), Div(attr1=AnyValue())),
(None, DoNotCheck()),
(123, DoNotCheck()),
(Div(), DoNotCheck()),
([Div(), Span()], DoNotCheck()),
(NotStr("123456"), NotStr("123")), # for NotStr, only the beginning is checked
(Div(), Div(Empty())),
(Div(), Div(NoChildren())),
(Div(attr1="value"), Div(NoChildren())),
(Div(attr1="value1"), Div(AttributeForbidden("attr2"))),
(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)
class Dummy:
def __init__(self, attr1, attr2=None):
self.attr1 = attr1
self.attr2 = attr2
@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)'"),
(Div(attr1=None), Div(attr1=AnyValue()), "'attr1' is not found in Actual"),
(Div(), Div(attr1=AnyValue()), "'attr1' is not found in Actual"),
(NotStr("456"), NotStr("123"), "Notstr values are different"),
(Div(attr="value"), Div(Empty()), "The condition 'Empty()' is not satisfied"),
(Div(Span()), Div(NoChildren()), "The condition 'NoChildren()' is not satisfied"),
(Div(120), Div(Empty()), "The condition 'Empty()' is not satisfied"),
(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(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(attr1="value1"), Div(AttributeForbidden("attr1")), "condition 'AttributeForbidden(attr1)' is not satisfied"),
])
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)
class Dummy2:
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
@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
class TestMatches:
with pytest.raises(AssertionError) as exc_info:
actual = _construct_test_element(element, "Actual")
expected = _construct_test_element(element, "Expected")
matches(actual, expected)
@pytest.mark.parametrize('actual, expected', [
(None, None),
(123, 123),
(Div(), Div()),
([Div(), Span()], [Div(), Span()]),
({"key": Div(attr="value")}, {"key": Div(attr="value")}),
({"key": Dummy(attr1="value")}, {"key": TestObject(Dummy, attr1="value")}),
(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"))),
(Div(attr1="value"), Div(attr1=AnyValue())),
(None, DoNotCheck()),
(123, DoNotCheck()),
(Div(), DoNotCheck()),
([Div(), Span()], DoNotCheck()),
(NotStr("123456"), NotStr("123")), # for NotStr, only the beginning is checked
(Div(), Div(Empty())),
(Div(), Div(NoChildren())),
(Div(attr1="value"), Div(NoChildren())),
(Div(attr1="value1"), Div(AttributeForbidden("attr2"))),
(Div(123), Div(123)),
(Div(Span(123)), Div(Span(123))),
(Div(Span(123)), Div(DoNotCheck())),
(Dummy(123, "value"), TestObject(Dummy, attr1=123, attr2="value")),
(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")),
])
def test_i_can_match(self, actual, expected):
assert 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():
"""I can display error when the condition predicate is not satisfied."""
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():
"""I can display error when the element has children"""
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_text():
"""I can display error when the children is not a FT"""
elt = Div("Hello world", 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"',
' "Hello world"',
' (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)
@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)'"),
(Div(attr1=None), Div(attr1=AnyValue()), "'attr1' is not found in Actual"),
(Div(), Div(attr1=AnyValue()), "'attr1' is not found in Actual"),
(NotStr("456"), NotStr("123"), "Notstr values are different"),
(Div(attr="value"), Div(Empty()), "The condition 'Empty()' is not satisfied"),
(Div(Span()), Div(NoChildren()), "The condition 'NoChildren()' is not satisfied"),
(Div(120), Div(Empty()), "The condition 'Empty()' is not satisfied"),
(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(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(attr1="value1"), Div(AttributeForbidden("attr1")), "condition 'AttributeForbidden(attr1)' is not satisfied"),
(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(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"),
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
])
def test_i_can_detect_errors(self, actual, expected, error_message):
with pytest.raises(AssertionError) as exc_info:
matches(actual, expected)
assert error_message in str(exc_info.value)
res = comparison_out.render()
@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(self, 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)
class TestErrorOutput:
def test_i_can_output_error_path(self):
"""The output follows the representation of the given 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 )']
assert "\n" + res == '''
def test_i_can_output_error_attribute(self):
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(self):
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(self):
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(self):
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(self):
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(self):
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(self):
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(self):
"""I can display error when the condition predicate is not satisfied."""
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(self):
"""I can display error when the element has children"""
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_text(self):
"""I can display error when the children is not a FT"""
elt = Div("Hello world", 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"',
' "Hello world"',
' (div "id"="child_1")',
' (div "id"="child_2")',
')',
]
def test_i_can_output_error_child_element_indicating_sub_children(self):
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(self):
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(self):
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_error_test_object(self):
elt = TestObject(Dummy, attr1=123, attr2="value2")
expected = elt
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == ['(Dummy "attr1"="123" "attr2"="value2")']
def test_i_can_output_error_test_object_wrong_type(self):
elt = Div(attr1=123, attr2="value2")
expected = TestObject(Dummy, attr1=123, attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == [
'(div "attr1"="123" "attr2"="value2")',
' ^^^ '
]
def test_i_can_output_error_test_object_wrong_type_2(self):
elt = Dummy2(attr1=123, attr2="value2")
expected = TestObject(Dummy, attr1=123, attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == [
'(Dummy2 "attr1"="123" "attr2"="value2")',
' ^^^^^^ '
]
def test_i_can_output_error_test_object_wrong_type_3(self):
elt = Div(attr1=123, attr2="value2")
expected = TestObject("Dummy", attr1=123, attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == [
'(div "attr1"="123" "attr2"="value2")',
' ^^^ '
]
def test_i_can_output_error_test_object_wrong_value(self):
elt = Dummy(attr1="456", attr2="value2")
expected = TestObject(Dummy, attr1="123", attr2="value2")
path = ""
error_output = ErrorOutput(path, elt, expected)
error_output.compute()
assert error_output.output == [
'(Dummy "attr1"="456" "attr2"="value2")',
' ^^^^^^^^^^^^^ '
]
class TestErrorComparisonOutput:
def test_i_can_output_comparison(self):
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 == '''
def test_i_can_output_comparison_with_path(self):
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 == '''
def test_i_can_output_comparison_when_missing_attributes(self):
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 == '''
def test_i_can_output_comparison_when_wrong_attributes(self):
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 == '''
def test_i_can_output_comparison_when_fewer_elements(self):
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 == """
def test_i_can_see_the_diff_when_matching(self):
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)")
^^^^^^^^^^^^^^^^ |"""
def test_i_can_see_the_diff_with_test_object_when_wrong_type(self):
actual = Div(attr1=123, attr2="value2")
expected = TestObject(Dummy, attr1=123, attr2="value2")
actual_out = ErrorOutput("dummy", actual, expected)
expected_out = ErrorOutput("div", expected, expected)
comparison_out = ErrorComparisonOutput(actual_out, expected_out)
res = comparison_out.render()
assert "\n" + res == '''
(div "attr1"="123" "attr2"="value2") | (Dummy "attr1"="123" "attr2"="value2")
^^^ |'''