I can show and hide the columns comanger
This commit is contained in:
@@ -16,194 +16,250 @@ def cleanup_db():
|
||||
|
||||
class TestPanelBehaviour:
|
||||
"""Tests for Panel behavior and logic."""
|
||||
|
||||
|
||||
# 1. Creation and initialization
|
||||
|
||||
|
||||
def test_i_can_create_panel_with_default_config(self, root_instance):
|
||||
"""Test that a Panel can be created with default configuration."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
|
||||
assert panel is not None
|
||||
assert panel.conf.left is False
|
||||
assert panel.conf.right is True
|
||||
|
||||
|
||||
def test_i_can_create_panel_with_custom_config(self, root_instance):
|
||||
"""Test that a Panel accepts a custom PanelConf."""
|
||||
custom_conf = PanelConf(left=False, right=True)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
|
||||
|
||||
assert panel.conf.left is False
|
||||
assert panel.conf.right is True
|
||||
|
||||
|
||||
def test_panel_has_default_state_after_creation(self, root_instance):
|
||||
"""Test that _state has correct initial values."""
|
||||
panel = Panel(root_instance)
|
||||
state = panel._state
|
||||
|
||||
|
||||
assert state.left_visible is True
|
||||
assert state.right_visible is True
|
||||
assert state.left_width == 250
|
||||
assert state.right_width == 250
|
||||
|
||||
|
||||
def test_panel_creates_commands_instance(self, root_instance):
|
||||
"""Test that panel.commands exists and is of type Commands."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
|
||||
assert panel.commands is not None
|
||||
assert panel.commands.__class__.__name__ == "Commands"
|
||||
|
||||
|
||||
# 2. Content management
|
||||
|
||||
|
||||
def test_i_can_set_main_content(self, root_instance):
|
||||
"""Test that set_main() stores content in _main."""
|
||||
panel = Panel(root_instance)
|
||||
content = Div("Main content")
|
||||
|
||||
|
||||
panel.set_main(content)
|
||||
|
||||
|
||||
assert panel._main == content
|
||||
|
||||
|
||||
def test_set_main_returns_self(self, root_instance):
|
||||
"""Test that set_main() returns self for method chaining."""
|
||||
panel = Panel(root_instance)
|
||||
content = Div("Main content")
|
||||
|
||||
|
||||
result = panel.set_main(content)
|
||||
|
||||
|
||||
assert result is panel
|
||||
|
||||
|
||||
def test_i_can_set_left_content(self, root_instance):
|
||||
"""Test that set_left() stores content in _left."""
|
||||
panel = Panel(root_instance)
|
||||
content = Div("Left content")
|
||||
|
||||
|
||||
panel.set_left(content)
|
||||
|
||||
|
||||
assert panel._left == content
|
||||
|
||||
|
||||
def test_i_can_set_right_content(self, root_instance):
|
||||
"""Test that set_right() stores content in _right."""
|
||||
panel = Panel(root_instance)
|
||||
content = Div("Right content")
|
||||
|
||||
|
||||
panel.set_right(content)
|
||||
|
||||
|
||||
assert panel._right == content
|
||||
|
||||
|
||||
# 3. Toggle visibility
|
||||
|
||||
|
||||
def test_i_can_hide_left_panel(self, root_instance):
|
||||
"""Test that toggle_side('left', False) sets _state.left_visible to False."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
panel.toggle_side("left", False)
|
||||
|
||||
|
||||
panel.set_side_visible("left", False)
|
||||
|
||||
assert panel._state.left_visible is False
|
||||
|
||||
|
||||
def test_i_can_show_left_panel(self, root_instance):
|
||||
"""Test that toggle_side('left', True) sets _state.left_visible to True."""
|
||||
panel = Panel(root_instance)
|
||||
panel._state.left_visible = False
|
||||
|
||||
panel.toggle_side("left", True)
|
||||
|
||||
|
||||
panel.set_side_visible("left", True)
|
||||
|
||||
assert panel._state.left_visible is True
|
||||
|
||||
|
||||
def test_i_can_hide_right_panel(self, root_instance):
|
||||
"""Test that toggle_side('right', False) sets _state.right_visible to False."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
panel.toggle_side("right", False)
|
||||
|
||||
|
||||
panel.set_side_visible("right", False)
|
||||
|
||||
assert panel._state.right_visible is False
|
||||
|
||||
|
||||
def test_i_can_show_right_panel(self, root_instance):
|
||||
"""Test that toggle_side('right', True) sets _state.right_visible to True."""
|
||||
panel = Panel(root_instance)
|
||||
panel._state.right_visible = False
|
||||
|
||||
panel.toggle_side("right", True)
|
||||
|
||||
|
||||
panel.set_side_visible("right", True)
|
||||
|
||||
assert panel._state.right_visible is True
|
||||
|
||||
|
||||
def test_set_side_visible_returns_panel_and_icon(self, root_instance):
|
||||
"""Test that set_side_visible() returns a tuple (panel_element, show_icon_element)."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
result = panel.set_side_visible("left", False)
|
||||
|
||||
assert isinstance(result, tuple)
|
||||
assert len(result) == 2
|
||||
|
||||
@pytest.mark.parametrize("side, initial_visible, expected_visible", [
|
||||
("left", True, False), # left visible → hidden
|
||||
("left", False, True), # left hidden → visible
|
||||
("right", True, False), # right visible → hidden
|
||||
("right", False, True), # right hidden → visible
|
||||
])
|
||||
def test_i_can_toggle_panel_visibility(self, root_instance, side, initial_visible, expected_visible):
|
||||
"""Test that toggle_side() inverts the visibility state."""
|
||||
panel = Panel(root_instance)
|
||||
if side == "left":
|
||||
panel._state.left_visible = initial_visible
|
||||
else:
|
||||
panel._state.right_visible = initial_visible
|
||||
|
||||
panel.toggle_side(side)
|
||||
|
||||
if side == "left":
|
||||
assert panel._state.left_visible is expected_visible
|
||||
else:
|
||||
assert panel._state.right_visible is expected_visible
|
||||
|
||||
def test_toggle_side_returns_panel_and_icon(self, root_instance):
|
||||
"""Test that toggle_side() returns a tuple (panel_element, show_icon_element)."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
result = panel.toggle_side("left", False)
|
||||
|
||||
|
||||
result = panel.toggle_side("left")
|
||||
|
||||
assert isinstance(result, tuple)
|
||||
assert len(result) == 2
|
||||
|
||||
|
||||
# 4. Width management
|
||||
|
||||
|
||||
def test_i_can_update_left_panel_width(self, root_instance):
|
||||
"""Test that update_side_width('left', 300) sets _state.left_width to 300."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
|
||||
panel.update_side_width("left", 300)
|
||||
|
||||
|
||||
assert panel._state.left_width == 300
|
||||
|
||||
|
||||
def test_i_can_update_right_panel_width(self, root_instance):
|
||||
"""Test that update_side_width('right', 400) sets _state.right_width to 400."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
|
||||
panel.update_side_width("right", 400)
|
||||
|
||||
|
||||
assert panel._state.right_width == 400
|
||||
|
||||
|
||||
def test_update_width_returns_panel_element(self, root_instance):
|
||||
"""Test that update_side_width() returns a panel element."""
|
||||
panel = Panel(root_instance)
|
||||
|
||||
|
||||
result = panel.update_side_width("right", 300)
|
||||
|
||||
|
||||
assert result is not None
|
||||
|
||||
|
||||
# 5. Configuration
|
||||
|
||||
|
||||
def test_disabled_left_panel_returns_none(self, root_instance):
|
||||
"""Test that _mk_panel('left') returns None when conf.left=False."""
|
||||
custom_conf = PanelConf(left=False, right=True)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
|
||||
|
||||
result = panel._mk_panel("left")
|
||||
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_disabled_right_panel_returns_none(self, root_instance):
|
||||
"""Test that _mk_panel('right') returns None when conf.right=False."""
|
||||
custom_conf = PanelConf(left=True, right=False)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
|
||||
|
||||
result = panel._mk_panel("right")
|
||||
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_disabled_panel_show_icon_returns_none(self, root_instance):
|
||||
"""Test that _mk_show_icon() returns None when the panel is disabled."""
|
||||
custom_conf = PanelConf(left=False, right=True)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
|
||||
|
||||
result = panel._mk_show_icon("left")
|
||||
|
||||
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.parametrize("side, conf_kwargs", [
|
||||
("left", {"show_display_left": False}),
|
||||
("right", {"show_display_right": False}),
|
||||
])
|
||||
def test_show_icon_returns_none_when_show_display_disabled(self, root_instance, side, conf_kwargs):
|
||||
"""Test that _mk_show_icon() returns None when show_display is disabled."""
|
||||
custom_conf = PanelConf(left=True, right=True, **conf_kwargs)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
|
||||
result = panel._mk_show_icon(side)
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestPanelRender:
|
||||
"""Tests for Panel HTML rendering."""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def panel(self, root_instance):
|
||||
panel = Panel(root_instance, PanelConf(True, True))
|
||||
"""Panel with titles (default behavior)."""
|
||||
panel = Panel(root_instance, PanelConf(left=True, right=True))
|
||||
panel.set_main(Div("Main content"))
|
||||
panel.set_left(Div("Left content"))
|
||||
panel.set_right(Div("Right content"))
|
||||
return panel
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def panel_no_title(self, root_instance):
|
||||
"""Panel without titles (legacy behavior)."""
|
||||
panel = Panel(root_instance, PanelConf(
|
||||
left=True, right=True,
|
||||
show_left_title=False, show_right_title=False
|
||||
))
|
||||
panel.set_main(Div("Main content"))
|
||||
panel.set_left(Div("Left content"))
|
||||
panel.set_right(Div("Right content"))
|
||||
return panel
|
||||
|
||||
# 1. Global structure (UTR-11.1 - FIRST TEST)
|
||||
|
||||
|
||||
def test_i_can_render_panel_with_default_state(self, panel):
|
||||
"""Test that Panel renders with correct global structure.
|
||||
|
||||
@@ -220,32 +276,68 @@ class TestPanelRender:
|
||||
id=panel._id,
|
||||
cls="mf-panel"
|
||||
)
|
||||
|
||||
|
||||
assert matches(panel.render(), expected)
|
||||
|
||||
|
||||
# 2. Left panel
|
||||
|
||||
def test_left_panel_renders_with_correct_structure(self, panel):
|
||||
"""Test that left panel has content div before resizer.
|
||||
|
||||
def test_left_panel_renders_with_title_structure(self, panel):
|
||||
"""Test that left panel with title has header + scrollable content.
|
||||
|
||||
Why these elements matter:
|
||||
- Order (content then resizer): Critical for positioning resizer on the right side
|
||||
- id: Required for HTMX targeting during toggle/resize operations
|
||||
- cls Contains "mf-panel-left": CSS class for left panel styling
|
||||
- mf-panel-body: Grid container for header + content layout
|
||||
- mf-panel-header: Contains title and hide icon
|
||||
- mf-panel-content: Scrollable content area
|
||||
- mf-panel-with-title: Removes default padding-top
|
||||
"""
|
||||
left_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("left")))
|
||||
|
||||
# Step 1: Validate left panel global structure
|
||||
|
||||
expected = Div(
|
||||
TestIcon("subtract20_regular"),
|
||||
Div(id=panel.get_ids().left), # content div, tested in detail later
|
||||
Div(cls=Contains("mf-panel-body")), # body with header + content
|
||||
Div(cls=Contains("mf-resizer-left")), # resizer
|
||||
id=panel.get_ids().panel("left"),
|
||||
cls=Contains("mf-panel-left", "mf-panel-with-title")
|
||||
)
|
||||
|
||||
assert matches(left_panel, expected)
|
||||
|
||||
def test_left_panel_header_contains_title_and_icon(self, panel):
|
||||
"""Test that left panel header has title and hide icon.
|
||||
|
||||
Why these elements matter:
|
||||
- Title: Displays the panel title (left aligned)
|
||||
- Hide icon: Allows user to collapse the panel (right aligned)
|
||||
"""
|
||||
left_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("left")))
|
||||
header = find_one(left_panel, Div(cls=Contains("mf-panel-header")))
|
||||
|
||||
expected = Div(
|
||||
Div("Left"), # title
|
||||
Div(cls=Contains("mf-panel-hide-icon")), # hide icon
|
||||
cls="mf-panel-header"
|
||||
)
|
||||
|
||||
assert matches(header, expected)
|
||||
|
||||
def test_left_panel_renders_without_title_structure(self, panel_no_title):
|
||||
"""Test that left panel without title has legacy structure.
|
||||
|
||||
Why these elements matter:
|
||||
- Order (hide icon, content, resizer): Legacy layout without header
|
||||
- No mf-panel-with-title class
|
||||
"""
|
||||
left_panel = find_one(panel_no_title.render(), Div(id=panel_no_title.get_ids().panel("left")))
|
||||
|
||||
expected = Div(
|
||||
TestIcon("subtract20_regular"),
|
||||
Div(id=panel_no_title.get_ids().left),
|
||||
Div(cls=Contains("mf-resizer-left")),
|
||||
id=panel_no_title.get_ids().panel("left"),
|
||||
cls=Contains("mf-panel-left")
|
||||
)
|
||||
|
||||
|
||||
assert matches(left_panel, expected)
|
||||
|
||||
|
||||
def test_left_panel_has_mf_hidden_class_when_not_visible(self, panel):
|
||||
"""Test that left panel has 'mf-hidden' class when not visible.
|
||||
|
||||
@@ -254,11 +346,11 @@ class TestPanelRender:
|
||||
"""
|
||||
panel._state.left_visible = False
|
||||
left_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("left")))
|
||||
|
||||
|
||||
expected = Div(cls=Contains("mf-hidden"))
|
||||
|
||||
|
||||
assert matches(left_panel, expected)
|
||||
|
||||
|
||||
def test_left_panel_does_not_render_when_disabled(self, panel):
|
||||
"""Test that render() does not contain left panel when conf.left=False.
|
||||
|
||||
@@ -267,34 +359,70 @@ class TestPanelRender:
|
||||
"""
|
||||
panel.conf.left = False
|
||||
rendered = panel.render()
|
||||
|
||||
|
||||
# Verify left panel is not present
|
||||
left_panels = find(rendered, Div(id=panel.get_ids().panel("left")))
|
||||
assert len(left_panels) == 0, "Left panel should not be present when conf.left=False"
|
||||
|
||||
|
||||
# 3. Right panel
|
||||
|
||||
def test_right_panel_renders_with_correct_structure(self, panel):
|
||||
"""Test that right panel has resizer before content div.
|
||||
|
||||
def test_right_panel_renders_with_title_structure(self, panel):
|
||||
"""Test that right panel with title has header + scrollable content.
|
||||
|
||||
Why these elements matter:
|
||||
- Order (resizer then hide icon then content): Critical for positioning resizer on the left side
|
||||
- id: Required for HTMX targeting during toggle/resize operations
|
||||
- cls Contains "mf-panel-right": CSS class for right panel styling
|
||||
- mf-panel-body: Grid container for header + content layout
|
||||
- mf-panel-header: Contains title and hide icon
|
||||
- mf-panel-content: Scrollable content area
|
||||
- mf-panel-with-title: Removes default padding-top
|
||||
"""
|
||||
right_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("right")))
|
||||
|
||||
# Step 1: Validate right panel global structure
|
||||
|
||||
expected = Div(
|
||||
Div(cls=Contains("mf-resizer-right")), # resizer
|
||||
TestIcon("subtract20_regular"), # hide icon
|
||||
Div(id=panel.get_ids().right), # content div, tested in detail later
|
||||
Div(cls=Contains("mf-panel-body")), # body with header + content
|
||||
id=panel.get_ids().panel("right"),
|
||||
cls=Contains("mf-panel-right", "mf-panel-with-title")
|
||||
)
|
||||
|
||||
assert matches(right_panel, expected)
|
||||
|
||||
def test_right_panel_header_contains_title_and_icon(self, panel):
|
||||
"""Test that right panel header has title and hide icon.
|
||||
|
||||
Why these elements matter:
|
||||
- Title: Displays the panel title (left aligned)
|
||||
- Hide icon: Allows user to collapse the panel (right aligned)
|
||||
"""
|
||||
right_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("right")))
|
||||
header = find_one(right_panel, Div(cls=Contains("mf-panel-header")))
|
||||
|
||||
expected = Div(
|
||||
Div("Right"), # title
|
||||
Div(cls=Contains("mf-panel-hide-icon")), # hide icon
|
||||
cls="mf-panel-header"
|
||||
)
|
||||
|
||||
assert matches(header, expected)
|
||||
|
||||
def test_right_panel_renders_without_title_structure(self, panel_no_title):
|
||||
"""Test that right panel without title has legacy structure.
|
||||
|
||||
Why these elements matter:
|
||||
- Order (resizer, hide icon, content): Legacy layout without header
|
||||
- No mf-panel-with-title class
|
||||
"""
|
||||
right_panel = find_one(panel_no_title.render(), Div(id=panel_no_title.get_ids().panel("right")))
|
||||
|
||||
expected = Div(
|
||||
Div(cls=Contains("mf-resizer-right")),
|
||||
TestIcon("subtract20_regular"),
|
||||
Div(id=panel_no_title.get_ids().right),
|
||||
id=panel_no_title.get_ids().panel("right"),
|
||||
cls=Contains("mf-panel-right")
|
||||
)
|
||||
|
||||
|
||||
assert matches(right_panel, expected)
|
||||
|
||||
|
||||
def test_right_panel_has_mf_hidden_class_when_not_visible(self, panel):
|
||||
"""Test that right panel has 'mf-hidden' class when not visible.
|
||||
|
||||
@@ -303,11 +431,11 @@ class TestPanelRender:
|
||||
"""
|
||||
panel._state.right_visible = False
|
||||
right_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("right")))
|
||||
|
||||
|
||||
expected = Div(cls=Contains("mf-hidden"))
|
||||
|
||||
|
||||
assert matches(right_panel, expected)
|
||||
|
||||
|
||||
def test_right_panel_does_not_render_when_disabled(self, panel):
|
||||
"""Test that render() does not contain right panel when conf.right=False.
|
||||
|
||||
@@ -316,13 +444,13 @@ class TestPanelRender:
|
||||
"""
|
||||
panel.conf.right = False
|
||||
rendered = panel.render()
|
||||
|
||||
|
||||
# Verify right panel is not present
|
||||
right_panels = find(rendered, Div(id=panel.get_ids().panel("right")))
|
||||
assert len(right_panels) == 0, "Right panel should not be present when conf.right=False"
|
||||
|
||||
|
||||
# 4. Resizers
|
||||
|
||||
|
||||
def test_left_panel_has_resizer_with_correct_attributes(self, panel):
|
||||
"""Test that left panel resizer has required attributes.
|
||||
|
||||
@@ -334,16 +462,16 @@ class TestPanelRender:
|
||||
"""
|
||||
left_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("left")))
|
||||
resizer = find_one(left_panel, Div(cls=Contains("mf-resizer-left")))
|
||||
|
||||
|
||||
expected = Div(
|
||||
data_side="left",
|
||||
cls=Contains("mf-resizer", "mf-resizer-left")
|
||||
)
|
||||
|
||||
|
||||
assert matches(resizer, expected)
|
||||
# Verify data-command-id exists (value is dynamic, HTML uses hyphens)
|
||||
assert "data-command-id" in resizer.attrs
|
||||
|
||||
|
||||
def test_right_panel_has_resizer_with_correct_attributes(self, panel):
|
||||
"""Test that right panel resizer has required attributes.
|
||||
|
||||
@@ -355,58 +483,75 @@ class TestPanelRender:
|
||||
"""
|
||||
right_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("right")))
|
||||
resizer = find_one(right_panel, Div(cls=Contains("mf-resizer-right")))
|
||||
|
||||
|
||||
expected = Div(
|
||||
data_side="right",
|
||||
cls=Contains("mf-resizer", "mf-resizer-right")
|
||||
)
|
||||
|
||||
|
||||
assert matches(resizer, expected)
|
||||
# Verify data-command-id exists (value is dynamic, HTML uses hyphens)
|
||||
assert "data-command-id" in resizer.attrs
|
||||
|
||||
|
||||
# 5. Icons
|
||||
|
||||
def test_hide_icon_in_left_panel_has_correct_command(self, panel):
|
||||
"""Test that hide icon in left panel triggers toggle_side command.
|
||||
|
||||
def test_hide_icon_in_left_panel_header(self, panel):
|
||||
"""Test that hide icon in left panel header has correct structure.
|
||||
|
||||
Why these elements matter:
|
||||
- TestIconNotStr("subtract20_regular"): Verify correct icon is used for hiding
|
||||
- cls Contains "mf-panel-hide-icon": CSS class for hide icon positioning
|
||||
- cls Contains "mf-panel-hide-icon": CSS class for hide icon styling
|
||||
- Icon is inside header when title is shown
|
||||
"""
|
||||
left_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("left")))
|
||||
|
||||
# Find the hide icon (should be wrapped by mk.icon)
|
||||
hide_icons = find(left_panel, Div(cls=Contains("mf-panel-hide-icon")))
|
||||
assert len(hide_icons) == 1, "Left panel should contain exactly one hide icon"
|
||||
|
||||
# Verify it contains the subtract icon
|
||||
header = find_one(left_panel, Div(cls=Contains("mf-panel-header")))
|
||||
|
||||
hide_icons = find(header, Div(cls=Contains("mf-panel-hide-icon")))
|
||||
assert len(hide_icons) == 1, "Header should contain exactly one hide icon"
|
||||
|
||||
expected = Div(
|
||||
TestIconNotStr("subtract20_regular"),
|
||||
cls=Contains("mf-panel-hide-icon")
|
||||
)
|
||||
assert matches(hide_icons[0], expected)
|
||||
|
||||
def test_hide_icon_in_right_panel_has_correct_command(self, panel):
|
||||
"""Test that hide icon in right panel triggers toggle_side command.
|
||||
|
||||
def test_hide_icon_in_right_panel_header(self, panel):
|
||||
"""Test that hide icon in right panel header has correct structure.
|
||||
|
||||
Why these elements matter:
|
||||
- TestIconNotStr("subtract20_regular"): Verify correct icon is used for hiding
|
||||
- cls Contains "mf-panel-hide-icon": CSS class for hide icon positioning
|
||||
- cls Contains "mf-panel-hide-icon": CSS class for hide icon styling
|
||||
- Icon is inside header when title is shown
|
||||
"""
|
||||
right_panel = find_one(panel.render(), Div(id=panel.get_ids().panel("right")))
|
||||
|
||||
# Find the hide icon (should be wrapped by mk.icon)
|
||||
hide_icons = find(right_panel, Div(cls=Contains("mf-panel-hide-icon")))
|
||||
assert len(hide_icons) == 1, "Right panel should contain exactly one hide icon"
|
||||
|
||||
# Verify it contains the subtract icon
|
||||
header = find_one(right_panel, Div(cls=Contains("mf-panel-header")))
|
||||
|
||||
hide_icons = find(header, Div(cls=Contains("mf-panel-hide-icon")))
|
||||
assert len(hide_icons) == 1, "Header should contain exactly one hide icon"
|
||||
|
||||
expected = Div(
|
||||
TestIconNotStr("subtract20_regular"),
|
||||
cls=Contains("mf-panel-hide-icon")
|
||||
)
|
||||
assert matches(hide_icons[0], expected)
|
||||
|
||||
def test_hide_icon_in_panel_without_title(self, panel_no_title):
|
||||
"""Test that hide icon is at root level when no title.
|
||||
|
||||
Why these elements matter:
|
||||
- Hide icon should be direct child of panel (legacy behavior)
|
||||
"""
|
||||
left_panel = find_one(panel_no_title.render(), Div(id=panel_no_title.get_ids().panel("left")))
|
||||
|
||||
hide_icons = find(left_panel, Div(cls=Contains("mf-panel-hide-icon")))
|
||||
assert len(hide_icons) == 1, "Panel should contain exactly one hide icon"
|
||||
|
||||
expected = Div(
|
||||
TestIconNotStr("subtract20_regular"),
|
||||
cls=Contains("mf-panel-hide-icon")
|
||||
)
|
||||
assert matches(hide_icons[0], expected)
|
||||
|
||||
def test_show_icon_left_is_hidden_when_panel_visible(self, panel):
|
||||
"""Test that show icon has 'hidden' class when left panel is visible.
|
||||
|
||||
@@ -415,14 +560,14 @@ class TestPanelRender:
|
||||
- id: Required for HTMX swap-oob targeting
|
||||
"""
|
||||
show_icon = find_one(panel.render(), Div(id=f"{panel._id}_show_left"))
|
||||
|
||||
|
||||
expected = Div(
|
||||
cls=Contains("hidden"),
|
||||
id=f"{panel._id}_show_left"
|
||||
)
|
||||
|
||||
|
||||
assert matches(show_icon, expected)
|
||||
|
||||
|
||||
def test_show_icon_left_is_visible_when_panel_hidden(self, panel):
|
||||
"""Test that show icon is positioned left when left panel is hidden.
|
||||
|
||||
@@ -432,15 +577,15 @@ class TestPanelRender:
|
||||
"""
|
||||
panel._state.left_visible = False
|
||||
show_icon = find_one(panel.render(), Div(id=f"{panel._id}_show_left"))
|
||||
|
||||
|
||||
expected = Div(
|
||||
TestIconNotStr("more_horizontal20_regular"),
|
||||
cls=Contains("mf-panel-show-icon-left"),
|
||||
id=f"{panel._id}_show_left"
|
||||
)
|
||||
|
||||
|
||||
assert matches(show_icon, expected)
|
||||
|
||||
|
||||
def test_show_icon_right_is_visible_when_panel_hidden(self, panel):
|
||||
"""Test that show icon is positioned right when right panel is hidden.
|
||||
|
||||
@@ -450,17 +595,37 @@ class TestPanelRender:
|
||||
"""
|
||||
panel._state.right_visible = False
|
||||
show_icon = find_one(panel.render(), Div(id=f"{panel._id}_show_right"))
|
||||
|
||||
|
||||
expected = Div(
|
||||
TestIconNotStr("more_horizontal20_regular"),
|
||||
cls=Contains("mf-panel-show-icon-right"),
|
||||
id=f"{panel._id}_show_right"
|
||||
)
|
||||
|
||||
|
||||
assert matches(show_icon, expected)
|
||||
|
||||
@pytest.mark.parametrize("side, conf_kwargs", [
|
||||
("left", {"show_display_left": False}),
|
||||
("right", {"show_display_right": False}),
|
||||
])
|
||||
def test_show_icon_not_in_main_panel_when_show_display_disabled(self, root_instance, side, conf_kwargs):
|
||||
"""Test that show icon is not rendered when show_display is disabled.
|
||||
|
||||
Why these elements matter:
|
||||
- Absence of show icon: When show_display_* is False, the icon should not exist
|
||||
- This prevents users from showing the panel via UI (only programmatically)
|
||||
"""
|
||||
custom_conf = PanelConf(left=True, right=True, **conf_kwargs)
|
||||
panel = Panel(root_instance, conf=custom_conf)
|
||||
panel.set_main(Div("Main content"))
|
||||
|
||||
rendered = panel.render()
|
||||
show_icons = find(rendered, Div(id=f"{panel._id}_show_{side}"))
|
||||
|
||||
assert len(show_icons) == 0, f"Show icon for {side} should not be present when show_display_{side}=False"
|
||||
|
||||
# 6. Main panel
|
||||
|
||||
|
||||
def test_main_panel_contains_show_icons_and_content(self, panel):
|
||||
"""Test that main panel contains show icons and content in correct order.
|
||||
|
||||
@@ -473,10 +638,10 @@ class TestPanelRender:
|
||||
# Find all Divs with cls="mf-panel-main" (there are 2: outer wrapper and inner content)
|
||||
main_panels = find(panel.render(), Div(cls=Contains("mf-panel-main")))
|
||||
assert len(main_panels) == 2, "Should find outer wrapper and inner content div"
|
||||
|
||||
|
||||
# The outer wrapper is the first one (depth-first search)
|
||||
main_panel = main_panels[0]
|
||||
|
||||
|
||||
# Step 1: Validate main panel structure
|
||||
expected = Div(
|
||||
Div(id=f"{panel._id}_show_left"), # show icon left
|
||||
@@ -484,11 +649,11 @@ class TestPanelRender:
|
||||
Div(id=f"{panel._id}_show_right"), # show icon right
|
||||
cls="mf-panel-main"
|
||||
)
|
||||
|
||||
|
||||
assert matches(main_panel, expected)
|
||||
|
||||
|
||||
# 7. Script
|
||||
|
||||
|
||||
def test_init_resizer_script_is_present(self, panel):
|
||||
"""Test that initResizer script is present with correct panel ID.
|
||||
|
||||
@@ -496,7 +661,7 @@ class TestPanelRender:
|
||||
- Script content: Must call initResizer with panel ID for resize functionality
|
||||
"""
|
||||
script = find_one(panel.render(), Script())
|
||||
|
||||
|
||||
expected = TestScript(f"initResizer('{panel._id}');")
|
||||
|
||||
|
||||
assert matches(script, expected)
|
||||
|
||||
Reference in New Issue
Block a user