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 Html( 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: != \nactual=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: != \nactual=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"