from __future__ import annotations import knoe.ui.screens.cluster_nodes as cluster_nodes from knoe.ui.screens.cluster_nodes import ClusterNodesScreenMixin def test_render_cluster_nodes_page_topology_messages_are_scrollable(monkeypatch): class _DummyWidget: def __init__(self, *_args, **_kwargs): pass def destroy(self): return None def place_forget(self): return None def configure(self, **_kwargs): return None def pack(self, *_args, **_kwargs): return None def grid(self, *_args, **_kwargs): return None class _DummyFrame(_DummyWidget): def winfo_children(self): return [_DummyWidget()] def winfo_reqheight(self): return 0 def update_idletasks(self): return None def grid_slaves(self, *_args, **_kwargs): return [_DummyWidget()] class _DummyScrollbar(_DummyWidget): instances: list["_DummyScrollbar"] = [] def __init__(self, *_args, **kwargs): super().__init__() self.command = kwargs.get("command") _DummyScrollbar.instances.append(self) def pack(self, *_args, **_kwargs): return None def set(self, *_args, **_kwargs): return None def configure(self, **kwargs): if "command" in kwargs: self.command = kwargs["command"] class _DummyText(_DummyWidget): instances: list["_DummyText"] = [] def __init__(self, *_args, **kwargs): super().__init__() self.yscrollcommand = kwargs.get("yscrollcommand") self.contents = "" self.state = "normal" _DummyText.instances.append(self) def pack(self, *_args, **_kwargs): return None def insert(self, _idx: str, text: str): self.contents += text def see(self, *_args, **_kwargs): return None def configure(self, **kwargs): if "state" in kwargs: self.state = kwargs["state"] def yview(self, *_args, **_kwargs): return None monkeypatch.setattr(cluster_nodes.tk, "Frame", _DummyFrame) monkeypatch.setattr(cluster_nodes.tk, "Scrollbar", _DummyScrollbar) monkeypatch.setattr(cluster_nodes.tk, "Text", _DummyText) monkeypatch.setattr(cluster_nodes.tk, "Button", _DummyWidget) monkeypatch.setattr(cluster_nodes.tk, "Label", _DummyWidget) class _DummyCanvas: def __init__(self): self._next_id = 1 def create_text(self, *_args, **_kwargs): item = self._next_id self._next_id += 1 return item def create_window(self, *_args, **_kwargs): item = self._next_id self._next_id += 1 return item class _DummyApp(ClusterNodesScreenMixin): def __init__(self): self.bg_canvas = _DummyCanvas() self._canvas_items: list[int] = [] self._overlay_widgets: list[object] = [] self._cluster_nodes_topology_state = { "phase": "complete", "messages": [f"line-{i}" for i in range(1, 7)], "topology": None, "topology_path": "", "selected": set(), "busy": True, "expanded": None, } def _clear_canvas_page(self): return None def _should_show_cluster_nodes_screen(self): return True def _render_title(self, *_args, **_kwargs): return None def _render_paragraph(self, *_args, **_kwargs): return None def _cluster_nodes_start_discovery(self, force: bool = False): return None def _cluster_nodes_render_summary_cards(self, _topology, _x, y): return y def _cluster_nodes_render_table(self, _topology, _x, y): return y app = _DummyApp() app._render_cluster_nodes_page() assert _DummyScrollbar.instances assert _DummyText.instances assert _DummyText.instances[0].state == "disabled" assert "line-1" in _DummyText.instances[0].contents assert "line-6" in _DummyText.instances[0].contents assert _DummyScrollbar.instances[0].command is not None