From 93f987a73c1a241e65d76dffa64f0eeb777554a2 Mon Sep 17 00:00:00 2001 From: "hamza.khyari" Date: Fri, 15 May 2026 11:18:04 +0000 Subject: [PATCH] test(tui): enhance TDD regression test for #11039 - Verify inherited Widget._render() returns non-None via MRO traversal - Actually invoke _refresh_display() and verify correct overlay content Refs: #11039 --- features/steps/tui_first_run_steps.py | 52 +++++++++++++++++++++++++++ features/tui_first_run.feature | 2 ++ 2 files changed, 54 insertions(+) diff --git a/features/steps/tui_first_run_steps.py b/features/steps/tui_first_run_steps.py index 1c2114b89..2d1a731be 100644 --- a/features/steps/tui_first_run_steps.py +++ b/features/steps/tui_first_run_steps.py @@ -532,3 +532,55 @@ def step_overlay_refresh_display_callable(context: object) -> None: ) refresh = context._overlay._refresh_display assert callable(refresh), "_refresh_display must be callable" + + +@then("the inherited Widget._render should return a proper renderable") +def step_inherited_render_returns_renderable(context: object) -> None: + """Verify the inherited ``Widget._render()`` returns a non-None renderable. + + Bug #11039: ``ActorSelectionOverlay`` defined its own ``_render() -> None`` + which returned ``None``, causing Textual's layout engine to crash. The + fix renamed it to ``_refresh_display()``. This assertion confirms that + when Textual IS available, calling the real inherited ``_render()`` + produces a proper renderable (not ``None``). When Textual is not + available (``_FallbackStatic`` has no ``_render``), the check passes + trivially since the fallback case cannot trigger the shadowing crash. + """ + + from cleveragents.tui.widgets.actor_selection_overlay import ( + ActorSelectionOverlay, + ) + + cls = ActorSelectionOverlay + overlay = context._overlay + + render_from_mro = None + for base in cls.__mro__[1:]: + if "_render" in base.__dict__: + render_from_mro = base.__dict__["_render"] + break + + if render_from_mro is None: + return + + result = render_from_mro(overlay) + assert result is not None, ( + "Bug #11039 regression: inherited Widget._render() returned None. " + "ActorSelectionOverlay may still be shadowing the base-class " + "_render method, which would cause a NoneType crash during " + "Textual layout in textual >=1.0." + ) + + +@then("_refresh_display should produce correct overlay content") +def step_refresh_display_produces_content(context: object) -> None: + """Invoke ``_refresh_display()`` and verify it renders correct content.""" + from typing import cast + + overlay = context._overlay + overlay._refresh_display() + content: str = cast(str, overlay._text) + assert content, "_refresh_display must produce non-empty rendered overlay content" + assert "Welcome to CleverAgents" in content, ( + "_refresh_display content must include the welcome header" + ) diff --git a/features/tui_first_run.feature b/features/tui_first_run.feature index c8646de05..b41ba2304 100644 --- a/features/tui_first_run.feature +++ b/features/tui_first_run.feature @@ -206,9 +206,11 @@ Feature: TUI first-run experience with actor selection overlay Scenario: ActorSelectionOverlay does not define its own _render method Given a new ActorSelectionOverlay Then the overlay should not override Textual Widget._render + And the inherited Widget._render should return a proper renderable @tdd_issue @tdd_issue_11039 Scenario: ActorSelectionOverlay has refresh_display callable instead of render Given a new ActorSelectionOverlay When I call show on the overlay Then the overlay _refresh_display method should be callable + And _refresh_display should produce correct overlay content