fix(tui): rename ActorSelectionOverlay._render to avoid shadowing Textual Widget._render
Add TDD regression test for issue #11039: verify that ActorSelectionOverlay does not define its own _render() method. The method was renamed to _refresh_display() to prevent shadowing the Textual Widget._render method which caused NoneType crashes during layout engine calls.
This commit is contained in:
@@ -488,3 +488,47 @@ def step_persona_bar_reflects_actor(context: object) -> None:
|
||||
assert "anthropic/claude-sonnet-4-20250514" in bar._text, (
|
||||
f"Expected actor in persona bar, got: {bar._text}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TDD regression: issue #11039 - no _render() shadowing Textual Widget._render
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@then("the overlay should not override Textual Widget._render")
|
||||
def step_overlay_no_render_override(context: object) -> None:
|
||||
"""Verify that ActorSelectionOverlay does NOT define its own ``_render``.
|
||||
|
||||
The Shadowing Bug (issue #11039): ActorSelectionOverlay once defined
|
||||
``def _render(self) -> None`` which returned ``None``, shadowing
|
||||
``textual.widgets.Static._render()`` (which returns a
|
||||
:class:`textual.strip.Strip`). This caused the Textual layout engine to
|
||||
crash with ``AttributeError: 'NoneType' object has no attribute
|
||||
'get_height'``.
|
||||
|
||||
The fix renamed the method to ``_refresh_display`` so that the inherited
|
||||
base-class ``_render`` is untouched and returns a proper renderable.
|
||||
"""
|
||||
from cleveragents.tui.widgets.actor_selection_overlay import (
|
||||
ActorSelectionOverlay,
|
||||
)
|
||||
|
||||
cls = ActorSelectionOverlay
|
||||
# The overlay should NOT define its own _render in its __dict__.
|
||||
# If it did, _render found on the class would resolve to this method
|
||||
# rather than the Textual base-class implementation.
|
||||
has_own_render = "_render" in cls.__dict__
|
||||
assert not has_own_render, (
|
||||
"ActorSelectionOverlay defines its own _render() which shadows "
|
||||
"Textual Widget._render. This is the bug from issue #11039."
|
||||
)
|
||||
|
||||
|
||||
@then("the overlay _refresh_display method should be callable")
|
||||
def step_overlay_refresh_display_callable(context: object) -> None:
|
||||
"""Verify ``_refresh_display`` exists and is callable after show()."""
|
||||
assert hasattr(
|
||||
context._overlay, "_refresh_display"
|
||||
), "Overlay must have _refresh_display method"
|
||||
refresh = context._overlay._refresh_display
|
||||
assert callable(refresh), "_refresh_display must be callable"
|
||||
|
||||
@@ -194,3 +194,21 @@ Feature: TUI first-run experience with actor selection overlay
|
||||
And I call _complete_first_run with actor "anthropic/claude-sonnet-4-20250514"
|
||||
Then the registry should contain a persona named "default"
|
||||
And the persona bar should reflect the new actor
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# TDD regression: issue #11039 - no _render() shadowing Textual Widget._render
|
||||
# -----------------------------------------------------------------------
|
||||
# The overlay formerly defined its own _render() returning None, which
|
||||
# shadowed textual.widgets.Static._render and caused layout-engine crashes.
|
||||
# This scenario ensures the rename to _refresh_display eliminated that bug.
|
||||
|
||||
@tdd_issue @tdd_issue_11039
|
||||
Scenario: ActorSelectionOverlay does not define its own _render method
|
||||
Given a new ActorSelectionOverlay
|
||||
Then the overlay should not override Textual Widget._render
|
||||
|
||||
@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
|
||||
|
||||
Reference in New Issue
Block a user