fabro/lib/apps/fabro-cli/tests/it/cmd/graph.rs
Bryan Helmkamp c501c67185
Show each diagnostic's suggested fix in CLI output
Diagnostics have carried a `fix` field all along, but the CLI renderer
never printed it — the suggestion was only reachable through --json. The
actionable half of every validation failure was invisible to the person
running the command.

print_diagnostics now emits the fix as a dim-labelled continuation line
under any diagnostic that has one, at both error and warning severity.
Gating it behind --verbose would defeat the point, and printing it only
for errors would read as "this warning has no fix" — the warning
suggestions are useful on their own. Diagnostics that set no fix simply
omit the line.

The severity match moved into print_diagnostic so the fix line is
appended once in the loop rather than copied into all five arms; the
rest of the diff is reindentation.

print_diagnostics is shared by validate, preflight, graph, exec, and
dry-run, so this covers all five. Eleven inline snapshots across four
files gain a fix line; every change is additive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:06:31 -04:00

129 lines
3.6 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 super::support::{fixture, read_text};
#[test]
fn help() {
let context = test_context!();
let mut cmd = context.command();
cmd.args(["graph", "--help"]);
fabro_snapshot!(context.filters(), cmd, @"
success: true
exit_code: 0
----- stdout -----
Render a workflow graph as SVG
Usage: fabro graph [OPTIONS] <WORKFLOW>
Arguments:
<WORKFLOW>
Path to the .fabro workflow file, .toml task config, or project workflow name
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=]
--format <FORMAT>
Output format
[default: svg]
[possible values: svg]
--no-upgrade-check
Disable automatic upgrade check
[env: FABRO_NO_UPGRADE_CHECK=true]
-o, --output <OUTPUT>
Output file path (defaults to stdout)
-d, --direction <DIRECTION>
Graph layout direction (overrides the DOT file's rankdir)
Possible values:
- lr: Left to right
- tb: Top to bottom
--quiet
Suppress non-essential output
[env: FABRO_QUIET=]
--allow-invalid
Render even when workflow validation reports errors
--verbose
Enable verbose output
[env: FABRO_VERBOSE=]
-h, --help
Print help (see a summary with '-h')
----- stderr -----
");
}
#[test]
fn graph_allow_invalid_renders_after_diagnostics() {
let context = test_context!();
let workflow = fixture("invalid.fabro");
let output_path = context.temp_dir.join("invalid.svg");
let mut cmd = context.command();
cmd.args([
"graph",
"--allow-invalid",
"-o",
output_path.to_str().unwrap(),
workflow.to_str().unwrap(),
]);
fabro_snapshot!(context.filters(), cmd, @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
error: Pipeline must have exactly one start node (shape=Mdiamond or id start/Start) (start_node)
fix: Add a node with shape=Mdiamond or id 'start'
error [node: exit]: Exit node 'exit' has 1 outgoing edge(s) but must have none (exit_no_outgoing)
fix: Remove outgoing edges from the exit node
");
let svg = read_text(&output_path);
assert!(
svg.contains("<svg") && svg.contains("Invalid"),
"expected invalid workflow to render as SVG, got: {}",
&svg[..svg.len().min(200)]
);
}
#[test]
fn graph_invalid_workflow_fails_after_diagnostics() {
let context = test_context!();
let workflow = fixture("invalid.fabro");
let mut cmd = context.command();
cmd.args(["graph", workflow.to_str().unwrap()]);
fabro_snapshot!(context.filters(), cmd, @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Pipeline must have exactly one start node (shape=Mdiamond or id start/Start) (start_node)
fix: Add a node with shape=Mdiamond or id 'start'
error [node: exit]: Exit node 'exit' has 1 outgoing edge(s) but must have none (exit_no_outgoing)
fix: Remove outgoing edges from the exit node
× Validation failed
");
}