fabro/lib/crates/fabro-cli/tests/it/cmd/preflight.rs
Bryan Helmkamp 7e64bf8b69
feat(cli): render fatal errors with miette
Wrap root CLI errors at the main boundary so fatal diagnostics use miette's styled renderer while preserving existing telemetry, exit codes, and auth help hints.
2026-04-24 15:35:57 -04:00

82 lines
3 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use fabro_test::{fabro_snapshot, test_context};
use serde_json::Value;
use super::support::fixture;
#[test]
fn help() {
let context = test_context!();
let mut cmd = context.command();
cmd.args(["preflight", "--help"]);
fabro_snapshot!(context.filters(), cmd, @"
success: true
exit_code: 0
----- stdout -----
Validate run configuration without executing
Usage: fabro preflight [OPTIONS] <WORKFLOW>
Arguments:
<WORKFLOW> Path to a .fabro workflow file or .toml task config
Options:
--json Output as JSON [env: FABRO_JSON=]
--server <SERVER> Fabro server target: http(s) URL or absolute Unix socket path [env: FABRO_SERVER=]
--debug Enable DEBUG-level logging (default is INFO) [env: FABRO_DEBUG=]
--goal <GOAL> Override the workflow goal (available as {{ goal }} in prompts)
--goal-file <GOAL_FILE> Read the workflow goal from a file
--no-upgrade-check Disable automatic upgrade check [env: FABRO_NO_UPGRADE_CHECK=true]
--model <MODEL> Override default LLM model
--quiet Suppress non-essential output [env: FABRO_QUIET=]
--provider <PROVIDER> Override default LLM provider
-v, --verbose Enable verbose output
--sandbox <SANDBOX> Sandbox for agent tools [possible values: local, docker, daytona]
-h, --help Print help
----- stderr -----
");
}
#[test]
fn preflight_invalid_workflow_fails_with_validation_output() {
let context = test_context!();
let workflow = fixture("invalid.fabro");
let mut cmd = context.command();
cmd.args(["preflight", workflow.to_str().unwrap()]);
fabro_snapshot!(context.filters(), cmd, @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
Workflow: Invalid (2 nodes, 1 edges)
Graph: [FIXTURES]/invalid.fabro
error: Pipeline must have exactly one start node (shape=Mdiamond or id start/Start) (start_node)
error [node: exit]: Exit node 'exit' has 1 outgoing edge(s) but must have none (exit_no_outgoing)
× Validation failed
");
}
#[test]
fn preflight_invalid_workflow_json_emits_diagnostics() {
let context = test_context!();
let workflow = fixture("invalid.fabro");
let output = context
.command()
.args(["--json", "preflight", workflow.to_str().unwrap()])
.output()
.expect("command should run");
assert!(!output.status.success());
let value: Value =
serde_json::from_slice(&output.stdout).expect("preflight --json should parse");
assert_eq!(value["workflow"]["name"], "Invalid");
assert!(
value["workflow"]["diagnostics"]
.as_array()
.is_some_and(|diagnostics| !diagnostics.is_empty())
);
assert_eq!(value["checks"]["title"], "Run Preflight");
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("Validation failed"));
}