forked from cleveragents/cleveragents-core
f2be43dcc2
Centralize CLI output through shared renderers module with get_console() and get_err_console() accessors. Introduce ColumnSpec-based table rendering for plan list, resource list, and actor list commands. Add _FORMAT_HELP constant and fmt= parameter threading for consistent format handling. Includes Behave BDD tests for format output validation, Robot Framework integration tests for CLI formatting consistency, and CHANGELOG entry. ISSUES CLOSED: #210
279 lines
12 KiB
Gherkin
279 lines
12 KiB
Gherkin
Feature: CLI output formats parity
|
|
As a developer using the CleverAgents CLI
|
|
I want all action and plan commands to support --format json|yaml|plain|table|rich
|
|
So that I can integrate CLI output with external tooling
|
|
|
|
Background:
|
|
Given a CLI output format test runner
|
|
And a mocked lifecycle service for format tests
|
|
|
|
# Action list --format json
|
|
Scenario: Action list outputs valid JSON
|
|
Given there are actions for format testing
|
|
When I run action list with --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "namespaced_name"
|
|
|
|
# Action show --format yaml
|
|
Scenario: Action show outputs valid YAML
|
|
Given there is a single action for format testing
|
|
When I run action show with --format yaml
|
|
Then the output should be valid YAML
|
|
And the YAML should contain key "namespaced_name"
|
|
|
|
# Plan list --format json
|
|
Scenario: Plan lifecycle-list outputs valid JSON
|
|
Given there are plans for format testing
|
|
When I run plan lifecycle-list with --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "plan_id"
|
|
|
|
# Plan status --format json (single plan)
|
|
Scenario: Plan status single plan outputs valid JSON
|
|
Given there is a single plan for format testing
|
|
When I run plan status with plan id and --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "processing_state"
|
|
|
|
# Plan status --format plain (single plan)
|
|
Scenario: Plan status single plan outputs plain text
|
|
Given there is a single plan for format testing
|
|
When I run plan status with plan id and --format plain
|
|
Then the format output should contain "plan_id:"
|
|
And the format output should contain "processing_state:"
|
|
|
|
# Action list --format table
|
|
Scenario: Action list outputs table format
|
|
Given there are actions for format testing
|
|
When I run action list with --format table
|
|
Then the format output should contain "namespaced_name"
|
|
|
|
# Action list --format plain
|
|
Scenario: Action list outputs plain format
|
|
Given there are actions for format testing
|
|
When I run action list with --format plain
|
|
Then the format output should contain "namespaced_name:"
|
|
|
|
# Action archive --format json
|
|
Scenario: Action archive outputs valid JSON
|
|
Given there is an archivable action for format testing
|
|
When I run action archive with --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "archived"
|
|
|
|
# Plan status list all --format json
|
|
Scenario: Plan status no args outputs valid JSON for list
|
|
Given there are plans for format status listing
|
|
When I run plan status without id and --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "plan_id"
|
|
|
|
# Plan use --format json
|
|
Scenario: Plan use outputs valid JSON
|
|
Given there is an action for plan use format test
|
|
When I run plan use with --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "plan_id"
|
|
|
|
# Plan cancel --format json
|
|
Scenario: Plan cancel outputs valid JSON
|
|
Given there is a plan for cancel format test
|
|
When I run plan cancel with --format json
|
|
Then the output should be valid JSON
|
|
And the JSON should contain key "processing_state"
|
|
|
|
# Format consistency: same data, different renders
|
|
Scenario: JSON and YAML contain the same action keys
|
|
Given there is a single action for format testing
|
|
When I run action show with --format json
|
|
And I save the output keys as json_keys
|
|
And I run action show with --format yaml
|
|
And I save the output keys as yaml_keys
|
|
Then json_keys and yaml_keys should match
|
|
|
|
# Direct formatting module tests
|
|
Scenario: Format output handles all format types for dict
|
|
When I call format_output with a dict and format json
|
|
Then the format result should be valid JSON dict
|
|
When I call format_output with a dict and format yaml
|
|
Then the format result should be valid YAML dict
|
|
When I call format_output with a dict and format plain
|
|
Then the format result should contain plain key-value pairs
|
|
When I call format_output with a dict and format table
|
|
Then the format result should contain table output
|
|
When I call format_output with a dict and format rich
|
|
Then the format result should be valid JSON dict
|
|
|
|
Scenario: Format output handles list data
|
|
When I call format_output with a list and format plain
|
|
Then the format result should contain separator lines
|
|
|
|
Scenario: Serialize value handles enums and nested dicts
|
|
When I call serialize_value with enum and nested data
|
|
Then the serialized result should have string enum values
|
|
|
|
# -- Renderer consolidation tests (issue #210) --
|
|
|
|
Scenario: render_detail produces valid JSON for non-rich format
|
|
When I call render_detail with a sample dict and format json
|
|
Then the captured output should be valid JSON
|
|
And the captured JSON should contain field "name"
|
|
|
|
Scenario: render_detail produces valid YAML for non-rich format
|
|
When I call render_detail with a sample dict and format yaml
|
|
Then the captured output should be valid YAML
|
|
And the captured YAML should contain field "name"
|
|
|
|
Scenario: render_detail produces plain key-value for plain format
|
|
When I call render_detail with a sample dict and format plain
|
|
Then the captured plain output should contain "name:"
|
|
|
|
Scenario: render_list produces valid JSON with stable column order
|
|
When I call render_list with sample rows columns and format json
|
|
Then the captured output should be valid JSON list
|
|
And each JSON item should have keys in column order
|
|
|
|
Scenario: render_list produces valid YAML with stable column order
|
|
When I call render_list with sample rows columns and format yaml
|
|
Then the captured output should be valid YAML list
|
|
|
|
Scenario: render_list produces rich table for rich format
|
|
When I call render_list with sample rows columns and format rich
|
|
Then the captured output should contain a table header
|
|
|
|
Scenario: render_error writes to stderr with label and message
|
|
When I call render_error with label "NotFound" and message "missing item"
|
|
Then the stderr should contain "NotFound"
|
|
And the stderr should contain "missing item"
|
|
|
|
Scenario: render_error produces JSON envelope for json format
|
|
When I call render_error with label "NotFound" and message "missing" and format json
|
|
Then the stderr should be valid JSON
|
|
And the JSON should contain nested key "error.code"
|
|
|
|
Scenario: render_success produces green checkmark for rich format
|
|
When I call render_success with message "Done" and format rich
|
|
Then the captured output should contain "Done"
|
|
|
|
Scenario: render_success produces ASCII OK for plain format
|
|
When I call render_success with message "Done" and format plain
|
|
Then the captured output should contain "OK: Done"
|
|
|
|
Scenario: render_empty produces yellow message for rich format
|
|
When I call render_empty with entity "actions" and format rich
|
|
Then the captured output should contain "No actions found"
|
|
|
|
Scenario: render_empty produces JSON empty array for json format
|
|
When I call render_empty with entity "actions" and format json
|
|
Then the captured output should be valid JSON
|
|
And the JSON should be an empty list
|
|
|
|
Scenario: render_warning produces yellow message for rich format
|
|
When I call render_warning with message "Check config" and format rich
|
|
Then the captured output should contain "Check config"
|
|
|
|
Scenario: render_warning produces JSON for json format
|
|
When I call render_warning with message "Check config" and format json
|
|
Then the captured output should be valid JSON
|
|
And the captured JSON should contain field "status"
|
|
|
|
Scenario: render_warning produces YAML for yaml format
|
|
When I call render_warning with message "Check config" and format yaml
|
|
Then the captured output should be valid YAML
|
|
And the captured YAML should contain field "status"
|
|
|
|
Scenario: render_warning produces ASCII for plain format
|
|
When I call render_warning with message "Check config" and format plain
|
|
Then the captured plain output should contain "WARNING: Check config"
|
|
|
|
Scenario: render_success produces JSON for json format without data
|
|
When I call render_success with message "Done" and format json
|
|
Then the captured output should be valid JSON
|
|
And the captured JSON should contain field "status"
|
|
|
|
Scenario: Color format produces plain-like output for format_output
|
|
When I call format_output with a dict and format color
|
|
Then the format result should contain plain key-value pairs
|
|
|
|
Scenario: Plain format output is ASCII-only
|
|
When I call render_detail with unicode data and format plain
|
|
Then the captured plain output should be pure ASCII
|
|
|
|
Scenario: FORMAT_HELP constant is consistent
|
|
Then the FORMAT_HELP string should mention all six formats
|
|
|
|
# -- PR #787 regression tests (P2-5, P2-6, P2-7) --
|
|
|
|
Scenario: render_detail FieldSpec accessor returning zero displays "0" not blank
|
|
When I call render_detail with a FieldSpec accessor returning 0 and format rich
|
|
Then the captured output should contain "0"
|
|
|
|
Scenario: render_detail FieldSpec accessor returning False displays "False"
|
|
When I call render_detail with a FieldSpec accessor returning False and format rich
|
|
Then the captured output should contain "False"
|
|
|
|
Scenario: render_error plain format contains label and message without Rich markup
|
|
When I call render_error with label "Test Error" and message "Something failed" and format plain
|
|
Then the stderr should contain "Test Error"
|
|
And the stderr should contain "Something failed"
|
|
And the stderr should not contain Rich markup
|
|
|
|
Scenario: render_detail with FieldSpec fields and rich format produces output
|
|
When I call render_detail with FieldSpec fields and format rich
|
|
Then the captured output should contain "Item Detail"
|
|
And the captured output should contain "test-item"
|
|
|
|
# -- PR #787 additional coverage (T1-T9, M10-M12) --
|
|
|
|
Scenario: render_error with recovery and details produces JSON envelope with details
|
|
When I call render_error with details and recovery and format json
|
|
Then the stderr should be valid JSON
|
|
And the JSON should contain nested key "error.details"
|
|
And the JSON should contain nested key "error.recovery"
|
|
|
|
Scenario: render_error with empty details emits empty details object
|
|
When I call render_error with no details and format json
|
|
Then the stderr should be valid JSON
|
|
And the JSON should contain nested key "error.details"
|
|
|
|
Scenario: render_list with plain format outputs key-value pairs
|
|
When I call render_list with sample rows columns and format plain
|
|
Then the captured plain output should contain "name:"
|
|
|
|
Scenario: render_list with table format outputs table
|
|
When I call render_list with sample rows columns and format table
|
|
Then the captured plain output should contain "name"
|
|
|
|
Scenario: render_empty with plain format shows message
|
|
When I call render_empty with entity "items" and format plain
|
|
Then the captured plain output should contain "No items found"
|
|
|
|
Scenario: render_empty with yaml format shows empty list
|
|
When I call render_empty with entity "items" and format yaml
|
|
Then the captured output should be valid YAML
|
|
|
|
Scenario: render_empty with table format shows message
|
|
When I call render_empty with entity "items" and format table
|
|
Then the captured plain output should contain "No items found"
|
|
|
|
Scenario: render_success with yaml format produces structured output
|
|
When I call render_success with message "Done" and format yaml
|
|
Then the captured output should be valid YAML
|
|
And the captured YAML should contain field "status"
|
|
|
|
Scenario: render_detail with None accessor value shows empty string
|
|
When I call render_detail with a FieldSpec accessor returning None and format rich
|
|
Then the captured output should contain "Name"
|
|
|
|
Scenario: render_list with empty dict value shows empty cell
|
|
When I call render_list with None cell values and format rich
|
|
Then the captured output should contain "Results"
|
|
|
|
Scenario: render_warning with color format shows warning text
|
|
When I call render_warning with message "Heads up" and format color
|
|
Then the captured output should contain "Heads up"
|
|
|
|
Scenario: render_detail with color format produces output
|
|
When I call render_detail with a sample dict and format color
|
|
Then the captured plain output should contain "name:"
|