Feature: Output Rendering Framework — Registry, Renderer, and Capabilities # ================================================================ # RendererRegistry # ================================================================ Scenario: RendererRegistry registers and resolves built-in formats Given the default renderer registry Then the registry has format "plain" registered And the registry has format "color" registered And the registry has format "table" registered And the registry has format "rich" registered And the registry has format "json" registered And the registry has format "yaml" registered Scenario: RendererRegistry available_formats returns sorted list Given the default renderer registry Then the available formats are "color,json,plain,rich,table,yaml" Scenario: RendererRegistry is_registered returns False for unknown Given the default renderer registry Then the registry does not have format "csv" registered Scenario: RendererRegistry resolves plain format Given the default renderer registry When I resolve format "plain" from the registry Then the resolved renderer format name is "plain" Scenario: RendererRegistry resolves json format Given the default renderer registry When I resolve format "json" from the registry Then the resolved renderer format name is "json" Scenario: RendererRegistry resolve falls back from rich to plain on non-TTY Given the default renderer registry And a non-TTY terminal environment When I resolve format "rich" from the registry with terminal caps Then the resolved renderer format name is "plain" Scenario: RendererRegistry supports custom format registration Given a new empty renderer registry When I register a custom "csv" format in the registry Then the registry has format "csv" registered # ================================================================ # ElementRenderer protocol # ================================================================ Scenario: PlainElementRenderer renders panel element Given a PlainElementRenderer When I render a panel with title "Test" through the renderer Then the renderer output contains "Test" Scenario: PlainElementRenderer can_render always returns True Given a PlainElementRenderer Then the renderer can_render returns True for any terminal Scenario: ColorElementRenderer can_render requires ANSI Given a ColorElementRenderer Then the renderer can_render returns False without ANSI Scenario: RichElementRenderer can_render requires cursor movement Given a RichElementRenderer Then the renderer can_render returns False without cursor movement Scenario: JsonElementRenderer serializes output Given a JsonElementRenderer When I serialize a StructuredOutput through the renderer Then the serialized output is valid JSON Scenario: YamlElementRenderer serializes output with sorted keys Given a YamlElementRenderer When I serialize a StructuredOutput through the renderer Then the serialized output is valid YAML And the serialized output has sorted keys # ================================================================ # TerminalCapabilities extended fields # ================================================================ Scenario: TerminalCapabilities has all 11 spec fields When I create a full TerminalCapabilities Then the capabilities has width 120 And the capabilities has height 40 And the capabilities has supports_256_color True And the capabilities has supports_truecolor True And the capabilities has supports_unicode True And the capabilities has supports_alternate_screen True And the capabilities has no_color False And the capabilities has term_program "iTerm2" Scenario: TerminalCapabilities backward-compatible aliases work When I create a full TerminalCapabilities Then the capabilities supports_cursor property matches supports_cursor_movement And the capabilities term property matches term_program # ================================================================ # ColumnDef.type serialisation # ================================================================ Scenario: ColumnDef serialises type field as "type" in JSON Given an OutputSession with format "json" using JsonMaterializer When I create a table with ColumnDef objects "Name,Status" And I add a dict row with Name "Name" and Status "Alice" And I close the table handle And the session is closed Then the json output is valid JSON And the json output ColumnDef uses type key not col_type Scenario: ColumnDef accepts type alias in constructor When I create a ColumnDef with type alias "integer" Then the ColumnDef col_type is "integer" # ================================================================ # YAML sorted keys # ================================================================ Scenario: YAML output uses sorted keys Given an OutputSession with format "yaml" using YamlMaterializer When I create a panel handle with title "Sort Test" And I set entry "Zebra" to "last" And I set entry "Alpha" to "first" And I close the panel handle And the session is closed Then the yaml output is valid YAML # ================================================================ # Progress omitted from JSON output # ================================================================ Scenario: JSON output omits progress elements Given an OutputSession with format "json" using JsonMaterializer When I create a progress handle labelled "Building" with total 100 And I set progress to 50 of 100 And I close the progress handle And I create a panel handle with title "Info" And I set entry "Name" to "test" And I close the panel handle And the session is closed Then the json output is valid JSON And the json output does not contain element type "progress" And the json output contains element type "panel" # ================================================================ # MaterializationStrategy.bind() method # ================================================================ Scenario: PlainMaterializer has bind method Given a PlainMaterializer instance When I call bind on the materializer Then no error is raised Scenario: JsonMaterializer has bind method Given a JsonMaterializer instance When I call bind on the json materializer Then no error is raised # ================================================================ # Render dispatch — concrete renderer methods coverage # ================================================================ Scenario: PlainElementRenderer dispatches all element types via render_element Given a PlainElementRenderer When I call render_element with each element type Then no render dispatch error occurred Scenario: PlainElementRenderer serialize assembles rendered text Given a PlainElementRenderer When I call base serialize with a text element Then the base serialized output is a string Scenario: ColorElementRenderer dispatches all element types via render_element Given a ColorElementRenderer When I call render_element with each element type Then no render dispatch error occurred Scenario: ColorElementRenderer can_render returns True when ANSI is supported Given a ColorElementRenderer Then color renderer can_render is True with ANSI support Scenario: TableElementRenderer can_render checks is_tty flag Given a TableElementRenderer Then table renderer can_render is True on a TTY terminal And table renderer can_render is False on a non-TTY terminal Scenario: TableElementRenderer dispatches all element types via render_element Given a TableElementRenderer When I call render_element with each element type Then no render dispatch error occurred Scenario: RichElementRenderer dispatches all element types via render_element Given a RichElementRenderer When I call render_element with each element type Then no render dispatch error occurred Scenario: RichElementRenderer can_render returns True with cursor movement Given a RichElementRenderer Then rich renderer can_render is True with cursor movement Scenario: JsonElementRenderer dispatches all element types returning empty strings Given a JsonElementRenderer When I call render_element with each element type Then no render dispatch error occurred Scenario: YamlElementRenderer dispatches all element types returning empty strings Given a YamlElementRenderer When I call render_element with each element type Then no render dispatch error occurred # ================================================================ # RendererRegistry edge-case paths # ================================================================ Scenario: RendererRegistry resolve unknown format falls back to plain Given the default renderer registry When I resolve format "unregistered_format" from the registry Then the resolved renderer format name is "plain" Scenario: RendererRegistry resolve raises ValueError when no plain fallback exists Given a registry with no plain and a non-renderable format When I try to resolve the non-renderable format Then a ValueError is raised from resolve