Files
MyManagingTools/tests/test_helpers.py

441 lines
14 KiB
Python

import pytest
from fasthtml.components import *
from components.datagrid.DataGrid import DataGrid
from components.debugger.components.JsonViewer import JsonViewer
from helpers import *
@pytest.fixture
def sample_structure():
"""
A pytest fixture to provide a sample tree structure for testing.
"""
return Div(
Header(cls="first-class"),
Body(
"hello world",
Div(
Span(cls="highlight"),
Span(id="inner", name="child"),
id="content"),
),
Footer(),
)
@pytest.mark.parametrize("value, expected, expected_error", [
(Div(), "value",
"The types are different: <class 'fastcore.xml.FT'> != <class 'str'>\nactual=<div></div>\nexpected=value."),
(Div(), A(),
"The elements are different: 'div' != 'a'."),
(Div(Div()), Div(A()),
"Path 'div':\n\tThe elements are different: 'div' != 'a'."),
(Div(A(Span())), Div(A("element")),
"Path 'div.a':\n\tThe types are different: <class 'fastcore.xml.FT'> != <class 'str'>\nactual=<span></span>\nexpected=element."),
(Div(attr="one"), Div(attr="two"),
"Path 'div':\n\tThe values are different for 'attr' : 'one' != 'two'."),
(Div(A(attr="alpha")), Div(A(attr="beta")),
"Path 'div.a':\n\tThe values are different for 'attr' : 'alpha' != 'beta'."),
(Div(Div(), A()), Div(Div(), Span()),
"Path 'div':\n\tThe elements are different: 'a' != 'span'."),
(Div(A()), Div(A(attr="beta")),
"Path 'div.a':\n\tAttribute 'attr' is not found (with expected value: 'beta'). actual='{}'."),
(Div(id="one"), Div(id="two"),
"Path 'div#one':\n\tThe values are different for 'id' : 'one' != 'two'."),
(Div(id="same_id", attr="one"), Div(id="same_id", attr="two"),
"Path 'div#same_id':\n\tThe values are different for 'attr' : 'one' != 'two'."),
(Div(name="same_name", attr="one"), Div(name="same_name", attr="two"),
"Path 'div[name=same_name]':\n\tThe values are different for 'attr' : 'one' != 'two'."),
(Div(cls="same_class", attr="one"), Div(cls="same_class", attr="two"),
"Path 'div[class=same_class]':\n\tThe values are different for 'attr' : 'one' != 'two'."),
(Div(attr="value"), Div(Empty),
"Empty element expected, but found attributes {'attr': 'value'}."),
(Div(Div()), Div(Empty),
"Empty element expected, but found children (div((),{}),)."),
(Div(cls="a long attr"), Div(cls=StartsWith("different start")),
"Path 'div[class=a long attr]':\n\tAttribute 'class' does not start with 'different start': actual='a long attr', expected ='different start'."),
(Div(cls="a long attr"), Div(cls=Contains("not included")),
"Path 'div[class=a long attr]':\n\tAttribute 'class' does not contain 'not included': actual='a long attr', expected ='not included'."),
])
def test_matches_error_expected(value, expected, expected_error):
with pytest.raises(AssertionError) as error:
matches(value, expected)
assert error.value.args[0] == expected_error
@pytest.mark.parametrize("value, expected", [
(Div(), Div()),
(Div(A()), Div(A())),
(Div(id='do_not_validate'), Div(id='do_not_validate')),
(Div(A()), Div()), # children of actual are not selected
(Div(A(), Span(id="validate_please"), A(id="do_not_care")), Div(A(), Span(id="validate_please"))),
(Div(), Div(Empty)),
(Div(cls="a long attr"), Div(cls=StartsWith("a long"))),
(Div(cls="a long attr"), Div(cls=Contains("long"))),
])
def test_matches_success_expected(value, expected):
assert matches(value, expected)
def test_i_can_search_elements_by_name():
to_find = Table()
res = search_elements_by_name(to_find, "table")
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_name(ft, "table")
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "table")
assert res == [to_find]
ft = Div(to_find, Span(to_find))
res = search_elements_by_name(ft, "table")
assert res == [to_find, to_find]
def test_i_can_search_not_str_by_name():
to_find = NotStr("Hello World")
res = search_elements_by_name(to_find, "NotStr")
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_name(ft, "NotStr")
assert res == [to_find]
def test_i_can_search_elements_by_name_with_attr_and_exact_compare():
to_find = Table(attr="value")
res = search_elements_by_name(to_find, None, {"attr": "value"})
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, None, {"attr": "value"})
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "table", {"attr": "value"})
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "other", {"attr": "value"})
assert res == []
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "table", {"attr": "value2"})
assert res == []
ft = Div(Span(Table()))
res = search_elements_by_name(ft, "table", {"attr": "value"})
assert res == []
def test_i_can_search_elements_by_name_with_attr_and_contains_compare():
to_find = Table(attr="value1 value2 value3")
res = search_elements_by_name(to_find, None, {"attr": "value"}, comparison_method="contains")
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, None, {"attr": "value"}, comparison_method="contains")
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "table", {"attr": "value"}, comparison_method="contains")
assert res == [to_find]
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "other", {"attr": "value"}, comparison_method="contains")
assert res == []
ft = Div(Span(), Span(to_find))
res = search_elements_by_name(ft, "table", {"attr": "value4"}, comparison_method="contains")
assert res == []
ft = Div(Span(Table()))
res = search_elements_by_name(ft, "table", {"attr": "value"}, comparison_method="contains")
assert res == []
def test_i_can_select_path():
to_find = Table(attr="value")
res = search_elements_by_path(to_find, "table", None)
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_path(ft, "div.span.table", None)
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_path(ft, "span.table", None)
assert res == [to_find]
def test_i_can_select_path_with_attr():
to_find = Table(attr="value")
res = search_elements_by_path(to_find, "table", {"attr": "value"})
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_path(ft, "div.span.table", {"attr": "value"})
assert res == [to_find]
ft = Div(Span(to_find))
res = search_elements_by_path(ft, "span.table", {"attr": "value"})
assert res == [to_find]
res = search_elements_by_path(to_find, "span.table", {"attr": "value2"})
assert res == []
def test_i_can_extract_table_values_from_ft():
df = pd.DataFrame({
'Name': ['Alice', 'Bob'],
'Age': [20, 25]
})
dg = DataGrid(df, id="testing_grid_id")
element = dg.__ft__()
assert extract_table_values(element) == OrderedDict({
'Name': ['Alice', 'Bob'],
'Age': ["20", "25"]
})
assert extract_table_values(element, header=False) == [
["Alice", "20"],
["Bob", "25"]
]
def test_i_can_extract_table_values_from_html():
df = pd.DataFrame({
'Name': ['Alice', 'Bob'],
'Age': [20, 25]
})
dg = DataGrid(df, id="testing_grid_id")
html = to_xml(dg.__ft__())
element = get_from_html(html)
assert extract_table_values(element) == OrderedDict({
'Name': ['Alice', 'Bob'],
'Age': ["20", "25"]
})
assert extract_table_values(element, header=False) == [
["Alice", "20"],
["Bob", "25"]
]
def test_i_can_extract_popup_content_from_ft():
df = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [20, 25, 30]
})
dg = DataGrid(df, id="testing_grid_id")
element = dg.mk_filter_popup_content("name")
assert extract_popup_content(element) == OrderedDict(
{'__filter_input__': '',
'Alice': False,
'Bob': False,
'Charlie': False,
}
)
def test_i_can_extract_popup_content_from_html():
df = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [20, 25, 30]
})
dg = DataGrid(df, id="testing_grid_id")
html = to_xml(dg.mk_filter_popup_content("name"))
element = get_from_html(html)
assert extract_popup_content(element) == OrderedDict(
{'__filter_input__': '',
'Alice': False,
'Bob': False,
'Charlie': False,
}
)
@pytest.mark.parametrize("path, expected_attributes", [
("div", {"tag": "div"}),
("div#my_id", {"tag": "div", "id": "my_id"}),
("div[class=my_class]", {"tag": "div", "class": "my_class"}),
("div#my_id[class=my_class]", {"tag": "div", "id": "my_id", "class": "my_class"}),
("div#my_id[a1=v1][a2=v2]", {"tag": "div", "id": "my_id", "a1": "v1", "a2": "v2"}),
("div#my_id[a1='v1']", {"tag": "div", "id": "my_id", "a1": "v1"}),
('div#my_id[a1="v1"]', {"tag": "div", "id": "my_id", "a1": "v1"}),
("div#my_id[a1='v-1']", {"tag": "div", "id": "my_id", "a1": "v-1"}),
("div#my_id[a1='v_1']", {"tag": "div", "id": "my_id", "a1": "v_1"}),
])
def test_i_can_get_path_attributes(path, expected_attributes):
assert get_path_attributes(path) == expected_attributes
def test_i_can_select_by_path():
# I can select the good one from a list
items = [Div(id='1'),
Div(id='2'),
Div(id='3')]
actual = find_first_match(items, "div#3")
assert actual == items[2]
# I can select using attribute
item = Div(Span(id="span_1"), Span(id="span_2"), id="div_1")
actual = find_first_match(item, "div.span#span_2")
assert actual == item.children[1]
# I can manage when no ft
items = [Div(Div("text")), Div(Div(Div(id="3"), id="2"), id="1")] # 'text' is not a ft, but there won't be any error
actual = find_first_match(items, "div.div.div")
assert actual.attrs["id"] == "3"
# None is returned when not found
assert find_first_match(item, "div.span#span_3") is None
@pytest.mark.parametrize("tag, attr, expected", [
("span", "class", ("span", "highlight")), # The tag and the attribute exist
("footer", "id", None), # The tag exists, but not the attribute
(None, "class", ("header", "first-class")), # First element with a given attribute
("p", "class", None), # The tag does not exist
("span", "id", ("span", "inner")), # Inner element
(None, "name", ("span", "child")), # Inner element
])
def test_i_can_search_first_with_attribute(tag, attr, expected, sample_structure):
result = search_first_with_attribute(sample_structure, tag, attr)
if expected is None:
assert result is None
else:
assert result.tag == expected[0]
assert attr in result.attrs
assert result.attrs[attr] == expected[1]
# Add tests for extract_jsonviewer_node
def test_extract_jsonviewer_node():
# Create a valid JsonViewer node element
element = Div(
span_icon("expanded"),
Span("key : "),
Span("value")
)
result = extract_jsonviewer_node(element)
assert result is not None
assert result.is_expanded is True
assert result.key == "key"
assert result.value == element.children[2]
assert result.debug_key == element.children[1]
assert result.debug_folding == element.children[0]
def test_extract_jsonviewer_node_collapsed():
# Create a collapsed JsonViewer node element
element = Div(
span_icon("collapsed"),
Span("key : "),
Span("value")
)
result = extract_jsonviewer_node(element)
assert result is not None
assert result.is_expanded is False
assert result.key == "key"
assert result.value == element.children[2]
def test_extract_jsonviewer_node_no_expansion_state():
# Create a JsonViewer node with no expansion state
element = Div(
Span(),
Span("key : "),
Span("value")
)
result = extract_jsonviewer_node(element)
assert result is not None
assert result.is_expanded is None
assert result.key == "key"
assert result.value == element.children[2]
def test_extract_jsonviewer_node_root_node():
# Create a root JsonViewer node (no key)
element = Div(
span_icon("expanded"),
None,
Span("value")
)
result = extract_jsonviewer_node(element)
assert result is not None
assert result.is_expanded is True
assert result.key is None
assert result.value == element.children[2]
def test_extract_jsonviewer_node_invalid_structure():
# Test with invalid node structure (not enough children)
element = Div(
span_icon("expanded"),
Span("key : ")
)
result = extract_jsonviewer_node(element)
assert result is None
# Test with element that has no children attribute
element = "not an element with children"
result = extract_jsonviewer_node(element)
assert result is None
def test_json_viewer_find():
value = {"a": [1, 2, 3], "b": {"x": "y", "z": True}}
jsonviewer = JsonViewer(None, None, None, None, value)
elements = jsonviewer.__ft__()
root_div = search_elements_by_name(elements, "div", attrs={"id": f"{jsonviewer.get_id()}-root"})[0]
first_level_div = root_div.children[0]
as_node = extract_jsonviewer_node(first_level_div)
child_b = as_node.find("b")
assert isinstance(child_b, JsonViewerNode)
assert child_b.key == "b"
def test_json_viewer_find_with_path():
value = {"a": {"x": None, "y": ["first", "second"], "z": True}}
jsonviewer = JsonViewer(None, None, None, None, value)
jsonviewer.set_folding_mode("expand")
elements = jsonviewer.__ft__()
root_div = search_elements_by_name(elements, "div", attrs={"id": f"{jsonviewer.get_id()}-root"})[0]
first_level_div = root_div.children[0]
as_node = extract_jsonviewer_node(first_level_div)
child = as_node.find("a.y.0")
assert isinstance(child, JsonViewerNode)
assert child.key == "0"