from __future__ import annotations from typer.testing import CliRunner from wf_cli.app import app runner = CliRunner() def test_wf_help_lists_lifecycle_groups() -> None: result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "cap" in result.output assert "draft" in result.output assert "artifact" in result.output assert "deploy" in result.output assert "run" in result.output assert "source" in result.output assert "admin" in result.output assert "docs" in result.output assert "schema" in result.output assert "explain" in result.output def test_wf_main_loads_dotenv_before_invoking_app(monkeypatch) -> None: import wf_cli.app as mod calls: list[str] = [] monkeypatch.setattr(mod, "load_dotenv", lambda: calls.append("dotenv")) monkeypatch.setattr(mod, "app", lambda: calls.append("app")) mod.main() assert calls == ["dotenv", "app"] def test_wf_run_group_help_exists() -> None: result = runner.invoke(app, ["run", "--help"]) assert result.exit_code == 0 assert "Run workflow deployments" in result.output def test_root_config_flag_accepted_before_subcommand() -> None: result = runner.invoke(app, ["--config", "custom.json", "run", "--help"]) assert result.exit_code == 0 assert "Run workflow deployments" in result.output def test_wf_deploy_validate_help_exists() -> None: result = runner.invoke(app, ["deploy", "validate", "--help"]) assert result.exit_code == 0 assert "Validate one saved workflow deployment" in result.output def test_wf_run_start_help_exists() -> None: result = runner.invoke(app, ["run", "start", "--help"]) assert result.exit_code == 0 assert "--input-file" in result.output def test_wf_explain_help_shows_input_modes() -> None: result = runner.invoke(app, ["explain", "--help"]) assert result.exit_code == 0 assert "--input-file" in result.output assert "--stdin" in result.output assert "--list" in result.output def test_wf_cap_list_help_exists() -> None: result = runner.invoke(app, ["cap", "list", "--help"]) assert result.exit_code == 0 assert "--format" in result.output def test_wf_schema_help_describes_catalog_and_verbose_output() -> None: result = runner.invoke(app, ["schema", "--help"]) assert result.exit_code == 0 output = result.output.lower() assert "compact workflow schema outline" in output assert "--verbose" in output assert "draft" in output assert "raw" in output assert "core" in output def test_wf_source_list_help_exists() -> None: result = runner.invoke(app, ["source", "list", "--help"]) assert result.exit_code == 0 assert "--format" in result.output assert "--limit" in result.output def test_wf_admin_connections_help_exists() -> None: result = runner.invoke(app, ["admin", "connections", "--help"]) assert result.exit_code == 0 assert "--format" in result.output def test_wf_artifact_list_help_exists() -> None: result = runner.invoke(app, ["artifact", "list", "--help"]) assert result.exit_code == 0 assert "--format" in result.output def test_wf_deploy_save_help_exists() -> None: result = runner.invoke(app, ["deploy", "save", "--help"]) assert result.exit_code == 0 assert "--binding" in result.output def test_wf_draft_create_help_accepts_capability_option() -> None: result = runner.invoke(app, ["draft", "create", "--help"]) assert result.exit_code == 0 output = " ".join(result.output.split()) assert "--capability" in output assert "--title" in output def test_wf_draft_help_does_not_list_old_create_from_capability() -> None: result = runner.invoke(app, ["draft", "--help"]) assert result.exit_code == 0 assert "create-from-capability" not in result.output def test_wf_draft_map_help_explains_replace_merge_and_validate() -> None: input_result = runner.invoke(app, ["draft", "set-input", "--help"]) output_result = runner.invoke(app, ["draft", "set-output", "--help"]) workflow_output_result = runner.invoke( app, ["draft", "set-workflow-output", "--help"] ) assert input_result.exit_code == 0 assert output_result.exit_code == 0 assert workflow_output_result.exit_code == 0 input_help = " ".join(input_result.output.split()) output_help = " ".join(output_result.output.split()) workflow_output_help = " ".join(workflow_output_result.output.split()) assert "replaces the full input map" in input_help assert "Use --merge only" in input_help assert "draft validate" in input_help assert "input.text=text" in input_help assert "input.text=local.text" in input_help assert "replaces the full output map" in output_help assert "Use --merge only" in output_help assert "draft validate" in output_help assert "replaces the full workflow output map" in workflow_output_help assert "Use --merge only" in workflow_output_help assert "GRAPH_SOURCE=OUTPUT_FIELD" in workflow_output_help assert "output_schema fields are projected" in workflow_output_help assert "draft validate" in workflow_output_help def test_wf_draft_bind_help_explains_direction() -> None: result = runner.invoke(app, ["draft", "bind", "--help"]) assert result.exit_code == 0 help_text = " ".join(result.output.split()) assert "--from" in help_text assert "--to" in help_text assert "validate" in help_text assert "project missing schema" in help_text assert "set-input --merge" in help_text def test_wf_draft_add_step_help_explains_explicit_wiring() -> None: result = runner.invoke(app, ["draft", "add-step", "--help"]) assert result.exit_code == 0 output = " ".join(result.output.split()) assert "--capability" in output assert "--from-step" in output assert "--bind-output" in output assert "does not guess" in output assert "Repeat the flag" in output assert "--input state.title=title --input state.summary=summary" in output assert ( "--bind-output title=state.title --bind-output summary=state.summary" in output ) def test_wf_draft_help_does_not_list_old_add_step_from_capability() -> None: result = runner.invoke(app, ["draft", "--help"]) assert result.exit_code == 0 assert "add-step-from-capability" not in result.output def test_wf_draft_remove_commands_help_mentions_options() -> None: route_result = runner.invoke(app, ["draft", "remove-route", "--help"]) step_result = runner.invoke(app, ["draft", "remove-step", "--help"]) binding_result = runner.invoke(app, ["draft", "remove-binding", "--help"]) assert route_result.exit_code == 0 assert "--step" in route_result.output assert "--outcome" in route_result.output assert step_result.exit_code == 0 assert "--step" in step_result.output assert binding_result.exit_code == 0 assert "--input" in binding_result.output assert "--output" in binding_result.output assert "status: invalid" in binding_result.output def test_wf_draft_route_flags_reject_duplicate_outcomes() -> None: add_result = runner.invoke( app, [ "draft", "add-step", "ws", "--revision", "1", "--step", "call", "--capability", "demo.call", "--route", "ok=call", "--route", "ok=__end__", ], ) branch_result = runner.invoke( app, [ "draft", "branch", "ws", "--revision", "1", "--step", "call", "--route", "ok=call", "--route", "ok=__end__", ], ) assert add_result.exit_code == 2 assert branch_result.exit_code == 2 assert "duplicate --route for 'ok'" in add_result.output assert "duplicate --route for 'ok'" in branch_result.output def test_wf_run_resume_help_exists() -> None: result = runner.invoke(app, ["run", "resume", "--help"]) assert result.exit_code == 0 assert "resume payload" in result.output.lower() assert "schema" in result.output.lower() def test_wf_draft_set_input_rejects_local_prefixed_target() -> None: result = runner.invoke( app, [ "draft", "set-input", "report_ws", "--revision", "1", "--step", "render", "--map", "input.text=local.text", ], ) assert result.exit_code == 2 output = " ".join(result.output.split()) assert "bare local field" in output assert "input.text=text" in output assert "input.text=local.text" in output