diff --git a/lib/crates/fabro-cli/tests/it/cmd/config.rs b/lib/crates/fabro-cli/tests/it/cmd/config.rs index d124ab232..920f9a787 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/config.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/config.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use fabro_config::FabroSettings; use fabro_config::mcp::McpTransport; #[cfg(feature = "server")] @@ -64,22 +66,14 @@ fn show_help() { // Helpers // --------------------------------------------------------------------------- -#[allow(deprecated)] -fn arc() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.arg("--no-upgrade-check"); - cmd -} - fn parse_config_show(stdout: &[u8]) -> FabroSettings { serde_yaml::from_slice(stdout).expect("stdout should be valid YAML FabroSettings") } -fn setup_config_show_fixture() -> (tempfile::TempDir, tempfile::TempDir) { - let home = tempfile::tempdir().unwrap(); - let project = tempfile::tempdir().unwrap(); - - let home_fabro = home.path().join(".fabro"); +/// Set up home config and project config for config show tests. +/// Uses `context.home_dir` for the home directory. Returns project tempdir. +fn setup_config_show_fixture(context: &fabro_test::TestContext) -> tempfile::TempDir { + let home_fabro = context.home_dir.join(".fabro"); std::fs::create_dir_all(&home_fabro).unwrap(); std::fs::write( home_fabro.join("user.toml"), @@ -119,6 +113,7 @@ SHARED = "cli" ) .unwrap(); + let project = tempfile::tempdir().unwrap(); std::fs::write( project.path().join("fabro.toml"), r#" @@ -195,15 +190,17 @@ SHARED = "run" ) .unwrap(); - (home, project) + project } -fn setup_external_workflow_fixture() -> (tempfile::TempDir, tempfile::TempDir, std::path::PathBuf) { - let home = tempfile::tempdir().unwrap(); - let project = tempfile::tempdir().unwrap(); - let storage_dir = home.path().join("fabro-data"); +/// Set up an external workflow fixture with a custom storage_dir in user.toml. +/// Returns (project_tempdir, storage_dir_path). +fn setup_external_workflow_fixture( + context: &fabro_test::TestContext, +) -> (tempfile::TempDir, PathBuf) { + let storage_dir = context.home_dir.join("fabro-data"); - let home_fabro = home.path().join(".fabro"); + let home_fabro = context.home_dir.join(".fabro"); std::fs::create_dir_all(&home_fabro).unwrap(); std::fs::write( home_fabro.join("user.toml"), @@ -220,6 +217,7 @@ commands = ["cli-setup"] ) .unwrap(); + let project = tempfile::tempdir().unwrap(); std::fs::write( project.path().join("fabro.toml"), r#" @@ -262,7 +260,7 @@ commands = ["workflow-setup"] ) .unwrap(); - (home, project, storage_dir) + (project, storage_dir) } // --------------------------------------------------------------------------- @@ -271,10 +269,11 @@ commands = ["workflow-setup"] #[test] fn config_show_merges_cli_and_project_defaults() { - let (home, project) = setup_config_show_fixture(); + let context = test_context!(); + let project = setup_config_show_fixture(&context); - let output = arc() - .env("HOME", home.path()) + let output = context + .command() .current_dir(project.path()) .args(["config", "show"]) .assert() @@ -307,10 +306,11 @@ fn config_show_merges_cli_and_project_defaults() { #[test] fn config_show_workflow_name_applies_run_overlay_and_deep_merges() { - let (home, project) = setup_config_show_fixture(); + let context = test_context!(); + let project = setup_config_show_fixture(&context); - let output = arc() - .env("HOME", home.path()) + let output = context + .command() .current_dir(project.path()) .args(["config", "show", "demo"]) .assert() @@ -382,12 +382,15 @@ fn config_show_workflow_name_applies_run_overlay_and_deep_merges() { #[test] fn config_show_explicit_workflow_path_uses_workflow_project_layers() { - let (home, project, _storage_dir) = setup_external_workflow_fixture(); + let context = test_context!(); + let (project, _storage_dir) = setup_external_workflow_fixture(&context); let cwd = tempfile::tempdir().unwrap(); let workflow = project.path().join("workflow.toml"); - let output = arc() - .env("HOME", home.path()) + // Remove FABRO_STORAGE_DIR so the CLI uses storage_dir from user.toml + let output = context + .command() + .env_remove("FABRO_STORAGE_DIR") .current_dir(cwd.path()) .args(["config", "show", workflow.to_str().unwrap()]) .assert() @@ -414,13 +417,16 @@ fn config_show_explicit_workflow_path_uses_workflow_project_layers() { #[test] fn create_explicit_workflow_path_uses_project_config_relative_to_workflow() { - let (home, project, storage_dir) = setup_external_workflow_fixture(); + let context = test_context!(); + let (project, storage_dir) = setup_external_workflow_fixture(&context); let cwd = tempfile::tempdir().unwrap(); let workflow = project.path().join("workflow.toml"); let run_id = "01ARZ3NDEKTSV4RRFFQ69G5FB8"; - arc() - .env("HOME", home.path()) + // Remove FABRO_STORAGE_DIR so the CLI uses storage_dir from user.toml + context + .command() + .env_remove("FABRO_STORAGE_DIR") .current_dir(cwd.path()) .args([ "create", @@ -475,10 +481,11 @@ fn create_explicit_workflow_path_uses_project_config_relative_to_workflow() { #[test] fn config_show_fabro_path_matches_ambient_defaults() { - let (home, project) = setup_config_show_fixture(); + let context = test_context!(); + let project = setup_config_show_fixture(&context); - let ambient = arc() - .env("HOME", home.path()) + let ambient = context + .command() .current_dir(project.path()) .args(["config", "show"]) .assert() @@ -486,8 +493,8 @@ fn config_show_fabro_path_matches_ambient_defaults() { .get_output() .stdout .clone(); - let graph = arc() - .env("HOME", home.path()) + let graph = context + .command() .current_dir(project.path()) .args(["config", "show", "standalone.fabro"]) .assert() @@ -501,10 +508,11 @@ fn config_show_fabro_path_matches_ambient_defaults() { #[test] fn config_show_missing_run_config_errors() { - let (home, project) = setup_config_show_fixture(); + let context = test_context!(); + let project = setup_config_show_fixture(&context); - arc() - .env("HOME", home.path()) + context + .command() .current_dir(project.path()) .args(["config", "show", "missing.toml"]) .assert() @@ -514,10 +522,10 @@ fn config_show_missing_run_config_errors() { #[test] fn config_show_legacy_cli_config_warns_and_ignores_it() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); let project = tempfile::tempdir().unwrap(); - let home_fabro = home.path().join(".fabro"); + let home_fabro = context.home_dir.join(".fabro"); std::fs::create_dir_all(&home_fabro).unwrap(); std::fs::write( home_fabro.join("cli.toml"), @@ -530,8 +538,8 @@ model = "legacy-model" ) .unwrap(); - let assert = arc() - .env("HOME", home.path()) + let assert = context + .command() .current_dir(project.path()) .args(["config", "show"]) .assert() @@ -546,9 +554,10 @@ model = "legacy-model" #[test] fn config_show_user_config_wins_over_legacy_cli_config() { - let (home, project) = setup_config_show_fixture(); + let context = test_context!(); + let project = setup_config_show_fixture(&context); std::fs::write( - home.path().join(".fabro").join("cli.toml"), + context.home_dir.join(".fabro").join("cli.toml"), r#" [llm] model = "legacy-model" @@ -559,8 +568,8 @@ shared = "legacy" ) .unwrap(); - let assert = arc() - .env("HOME", home.path()) + let assert = context + .command() .current_dir(project.path()) .args(["config", "show"]) .assert() @@ -581,8 +590,9 @@ shared = "legacy" #[test] #[cfg(feature = "server")] fn config_show_server_url_overrides_cli_defaults() { - let (home, project) = setup_config_show_fixture(); - let user_toml = home.path().join(".fabro").join("user.toml"); + let context = test_context!(); + let project = setup_config_show_fixture(&context); + let user_toml = context.home_dir.join(".fabro").join("user.toml"); std::fs::write( &user_toml, format!( @@ -592,8 +602,8 @@ fn config_show_server_url_overrides_cli_defaults() { ) .unwrap(); - let output = arc() - .env("HOME", home.path()) + let output = context + .command() .current_dir(project.path()) .args(["--server-url", "https://cli.example.com", "config", "show"]) .assert() diff --git a/lib/crates/fabro-cli/tests/it/cmd/doctor.rs b/lib/crates/fabro-cli/tests/it/cmd/doctor.rs index bf8f45c55..6e694850c 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/doctor.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/doctor.rs @@ -1,20 +1,6 @@ use fabro_test::{fabro_snapshot, test_context}; use predicates::prelude::*; -#[allow(deprecated)] -fn arc() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.arg("--no-upgrade-check"); - cmd -} - -#[allow(deprecated)] -fn fabro() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.env("NO_COLOR", "1"); - cmd -} - #[test] fn help() { let context = test_context!(); @@ -80,15 +66,16 @@ fn dry_run_flag() { #[ignore = "scenario: requires ANTHROPIC_API_KEY"] fn live_doctor() { dotenvy::dotenv().ok(); - fabro().args(["doctor"]).assert().success(); + let context = test_context!(); + context.doctor().assert().success(); } #[test] fn doctor_no_color_when_no_color_set() { - arc() - .args(["doctor", "--dry-run"]) - .env_clear() - .env("NO_COLOR", "1") - .assert() - .stdout(predicate::str::contains("\x1b[").not()); + let context = test_context!(); + let mut cmd = context.doctor(); + cmd.arg("--dry-run"); + cmd.env_clear(); + cmd.env("NO_COLOR", "1"); + cmd.assert().stdout(predicate::str::contains("\x1b[").not()); } diff --git a/lib/crates/fabro-cli/tests/it/cmd/exec.rs b/lib/crates/fabro-cli/tests/it/cmd/exec.rs index a5c1e32ac..a7149a385 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/exec.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/exec.rs @@ -1,13 +1,6 @@ use fabro_test::{fabro_snapshot, test_context}; use predicates::prelude::*; -#[allow(deprecated)] -fn arc() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.arg("--no-upgrade-check"); - cmd -} - #[test] fn invalid_permissions() { let context = test_context!(); @@ -44,13 +37,13 @@ fn no_prompt() { #[test] fn exec_missing_api_key_exits_with_error() { - let tmp = tempfile::tempdir().expect("tempdir"); - arc() - .args(["exec", "test prompt"]) - .env_clear() - .env("HOME", tmp.path().to_str().unwrap()) - .current_dir(tmp.path()) - .assert() + let context = test_context!(); + let mut cmd = context.exec_cmd(); + cmd.arg("test prompt"); + cmd.env_clear(); + cmd.env("HOME", &context.home_dir); + cmd.current_dir(&context.temp_dir); + cmd.assert() .failure() .stderr(predicate::str::contains("API key not set")); } @@ -59,10 +52,10 @@ fn exec_missing_api_key_exits_with_error() { #[ignore = "requires API key"] fn exec_creates_file() { dotenvy::dotenv().ok(); - let tmp = tempfile::tempdir().expect("tempdir"); - arc() + let context = test_context!(); + context + .exec_cmd() .args([ - "exec", "--auto-approve", "--permissions", "full", @@ -72,11 +65,11 @@ fn exec_creates_file() { "claude-haiku-4-5", "Create a file called hello.txt containing exactly 'Hello'", ]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); - let path = tmp.path().join("hello.txt"); + let path = context.temp_dir.join("hello.txt"); assert!(path.exists(), "hello.txt should have been created"); let content = std::fs::read_to_string(&path).expect("read hello.txt"); assert!( @@ -89,10 +82,10 @@ fn exec_creates_file() { #[ignore = "requires API key"] fn exec_shell_command() { dotenvy::dotenv().ok(); - let tmp = tempfile::tempdir().expect("tempdir"); - arc() + let context = test_context!(); + context + .exec_cmd() .args([ - "exec", "--auto-approve", "--permissions", "full", @@ -102,7 +95,7 @@ fn exec_shell_command() { "claude-haiku-4-5", "Run the shell command `echo arc_test_marker_42` and tell me what it printed", ]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); @@ -112,10 +105,10 @@ fn exec_shell_command() { #[ignore = "requires API key"] fn exec_read_only_blocks_write() { dotenvy::dotenv().ok(); - let tmp = tempfile::tempdir().expect("tempdir"); - arc() + let context = test_context!(); + context + .exec_cmd() .args([ - "exec", "--auto-approve", "--permissions", "read-only", @@ -125,12 +118,12 @@ fn exec_read_only_blocks_write() { "claude-haiku-4-5", "Create a file called forbidden.txt containing 'should not exist'", ]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); assert!( - !tmp.path().join("forbidden.txt").exists(), + !context.temp_dir.join("forbidden.txt").exists(), "forbidden.txt should NOT exist under read-only permissions" ); } @@ -139,10 +132,10 @@ fn exec_read_only_blocks_write() { #[ignore = "requires API key"] fn exec_json_output_format() { dotenvy::dotenv().ok(); - let tmp = tempfile::tempdir().expect("tempdir"); - let output = arc() + let context = test_context!(); + let output = context + .exec_cmd() .args([ - "exec", "--auto-approve", "--permissions", "full", @@ -154,7 +147,7 @@ fn exec_json_output_format() { "claude-haiku-4-5", "Create a file called test.txt containing 'test'", ]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success() @@ -178,11 +171,11 @@ fn exec_json_output_format() { #[ignore = "requires API key"] fn exec_read_and_edit() { dotenvy::dotenv().ok(); - let tmp = tempfile::tempdir().expect("tempdir"); - std::fs::write(tmp.path().join("data.txt"), "old content").expect("write data.txt"); - arc() + let context = test_context!(); + std::fs::write(context.temp_dir.join("data.txt"), "old content").expect("write data.txt"); + context + .exec_cmd() .args([ - "exec", "--auto-approve", "--permissions", "full", @@ -192,11 +185,12 @@ fn exec_read_and_edit() { "claude-haiku-4-5", "Read data.txt then replace its entire content with 'new content'", ]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); - let content = std::fs::read_to_string(tmp.path().join("data.txt")).expect("read data.txt"); + let content = + std::fs::read_to_string(context.temp_dir.join("data.txt")).expect("read data.txt"); assert!( content.contains("new content"), "Expected 'new content' in data.txt, got: {content}" diff --git a/lib/crates/fabro-cli/tests/it/cmd/llm.rs b/lib/crates/fabro-cli/tests/it/cmd/llm.rs index eb74a880f..d95f762df 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/llm.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/llm.rs @@ -1,13 +1,6 @@ use fabro_test::{fabro_snapshot, test_context}; use predicates::prelude::*; -#[allow(deprecated)] -fn arc() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.arg("--no-upgrade-check"); - cmd -} - #[test] fn prompt_bad_option() { let context = test_context!(); @@ -64,8 +57,10 @@ fn prompt_schema_invalid() { #[test] fn prompt_reads_from_stdin() { - let result = arc() - .args(["llm", "prompt", "--no-stream", "-m", "test-model"]) + let context = test_context!(); + let result = context + .llm() + .args(["prompt", "--no-stream", "-m", "test-model"]) .write_stdin("hello from stdin") .assert() .failure(); @@ -76,9 +71,10 @@ fn prompt_reads_from_stdin() { #[test] fn prompt_concatenates_stdin_and_arg() { - let result = arc() + let context = test_context!(); + let result = context + .llm() .args([ - "llm", "prompt", "--no-stream", "-m", @@ -95,9 +91,11 @@ fn prompt_concatenates_stdin_and_arg() { #[test] #[ignore = "requires API key"] fn prompt_no_stream_generates_response() { - arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + context + .llm() .args([ - "llm", "prompt", "--no-stream", "-m", @@ -112,9 +110,11 @@ fn prompt_no_stream_generates_response() { #[test] #[ignore = "requires API key"] fn prompt_stream_generates_response() { - arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + context + .llm() .args([ - "llm", "prompt", "-m", "claude-sonnet-4-5", @@ -128,9 +128,11 @@ fn prompt_stream_generates_response() { #[test] #[ignore = "requires API key"] fn prompt_usage_shows_tokens() { - arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + context + .llm() .args([ - "llm", "prompt", "--no-stream", "-u", @@ -146,9 +148,12 @@ fn prompt_usage_shows_tokens() { #[test] #[ignore = "requires API key"] fn prompt_schema_no_stream_generates_json() { - let assert = arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + let assert = context + .llm() .args([ - "llm", "prompt", "--no-stream", "-m", "claude-sonnet-4-5", + "prompt", "--no-stream", "-m", "claude-sonnet-4-5", "--schema", r#"{"type":"object","properties":{"greeting":{"type":"string"}},"required":["greeting"]}"#, "Return a JSON object with a greeting field set to hello", ]) @@ -167,9 +172,12 @@ fn prompt_schema_no_stream_generates_json() { #[test] #[ignore = "requires API key"] fn prompt_schema_stream_generates_json() { - let assert = arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + let assert = context + .llm() .args([ - "llm", "prompt", "-m", "claude-sonnet-4-5", + "prompt", "-m", "claude-sonnet-4-5", "--schema", r#"{"type":"object","properties":{"greeting":{"type":"string"}},"required":["greeting"]}"#, "Return a JSON object with a greeting field set to hello", ]) @@ -188,7 +196,10 @@ fn prompt_schema_stream_generates_json() { #[test] #[ignore = "requires API key"] fn chat_multi_turn_with_system_prompt() { - let assert = arc() + dotenvy::dotenv().ok(); + let context = test_context!(); + let assert = context + .command() .args([ "llm", "chat", diff --git a/lib/crates/fabro-cli/tests/it/cmd/repo.rs b/lib/crates/fabro-cli/tests/it/cmd/repo.rs index 585f630e2..f11057a43 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/repo.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/repo.rs @@ -1,13 +1,6 @@ use fabro_test::{fabro_snapshot, test_context}; use predicates; -#[allow(deprecated)] -fn fabro() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.env("NO_COLOR", "1"); - cmd -} - fn init_git_repo(path: &std::path::Path) { std::process::Command::new("git") .args(["init"]) @@ -55,37 +48,39 @@ fn help() { #[test] fn test_repo_deinit_removes_fabro_toml_and_dir() { - let tmp = tempfile::tempdir().unwrap(); - init_git_repo(tmp.path()); - init_fabro_project(tmp.path()); + let context = test_context!(); + init_git_repo(&context.temp_dir); + init_fabro_project(&context.temp_dir); - assert!(tmp.path().join("fabro.toml").exists()); - assert!(tmp.path().join("fabro").exists()); + assert!(context.temp_dir.join("fabro.toml").exists()); + assert!(context.temp_dir.join("fabro").exists()); - fabro() - .args(["repo", "deinit"]) - .current_dir(tmp.path()) + context + .repo() + .arg("deinit") + .current_dir(&context.temp_dir) .assert() .success(); assert!( - !tmp.path().join("fabro.toml").exists(), + !context.temp_dir.join("fabro.toml").exists(), "fabro.toml should be removed" ); assert!( - !tmp.path().join("fabro").exists(), + !context.temp_dir.join("fabro").exists(), "fabro/ directory should be removed" ); } #[test] fn test_repo_deinit_fails_when_not_initialized() { - let tmp = tempfile::tempdir().unwrap(); - init_git_repo(tmp.path()); + let context = test_context!(); + init_git_repo(&context.temp_dir); - fabro() - .args(["repo", "deinit"]) - .current_dir(tmp.path()) + context + .repo() + .arg("deinit") + .current_dir(&context.temp_dir) .assert() .failure() .stderr(predicates::str::contains("not initialized")); @@ -93,17 +88,20 @@ fn test_repo_deinit_fails_when_not_initialized() { #[test] fn test_repo_init_skill_installs_skill_files() { - let tmp = tempfile::tempdir().unwrap(); - init_git_repo(tmp.path()); + let context = test_context!(); + init_git_repo(&context.temp_dir); - fabro() - .args(["repo", "init", "--skill"]) - .current_dir(tmp.path()) + context + .repo() + .args(["init", "--skill"]) + .current_dir(&context.temp_dir) .assert() .success(); // Skill files should be installed under .claude/skills/fabro-create-workflow/ - let skill_dir = tmp.path().join(".claude/skills/fabro-create-workflow"); + let skill_dir = context + .temp_dir + .join(".claude/skills/fabro-create-workflow"); assert!(skill_dir.join("SKILL.md").exists(), "SKILL.md should exist"); assert!( skill_dir.join("references/dot-language.md").exists(), @@ -113,7 +111,8 @@ fn test_repo_init_skill_installs_skill_files() { #[test] fn test_repo_init_help_does_not_show_skill() { - let out = fabro().args(["repo", "init", "--help"]).assert().success(); + let context = test_context!(); + let out = context.repo().args(["init", "--help"]).assert().success(); let stdout = String::from_utf8(out.get_output().stdout.clone()).unwrap(); assert!( !stdout.contains("--skill"), diff --git a/lib/crates/fabro-cli/tests/it/cmd/run.rs b/lib/crates/fabro-cli/tests/it/cmd/run.rs index e02815982..447d8dd57 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/run.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/run.rs @@ -19,26 +19,6 @@ fn fixture(name: &str) -> std::path::PathBuf { std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join(format!("../../../test/{name}")) } -#[allow(deprecated)] -fn arc() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.arg("--no-upgrade-check"); - cmd -} - -fn init_cli_home(storage_dir: &Path) -> tempfile::TempDir { - let home = tempfile::tempdir().unwrap(); - let home_fabro = home.path().join(".fabro"); - std::fs::create_dir_all(&home_fabro).unwrap(); - let storage_dir = serde_json::to_string(&storage_dir.to_string_lossy().into_owned()).unwrap(); - std::fs::write( - home_fabro.join("user.toml"), - format!("storage_dir = {storage_dir}\n"), - ) - .unwrap(); - home -} - fn list_metadata_run_ids(repo_dir: &Path) -> BTreeSet { let repo = Repository::discover(repo_dir).unwrap(); repo.references() @@ -217,12 +197,12 @@ fn latest_metadata_checkpoint(repo_dir: &Path, run_id: &str) -> Checkpoint { /// Helper: create a minimal run directory that `resolve_run` can find. /// Sets up run.json, status.json, and progress.jsonl. fn setup_run_dir( - home: &std::path::Path, + storage_dir: &std::path::Path, run_id: &str, spec_overrides: serde_json::Value, progress_lines: &[&str], ) -> std::path::PathBuf { - let run_dir = home.join(".fabro").join("runs").join(run_id); + let run_dir = storage_dir.join("runs").join(run_id); std::fs::create_dir_all(&run_dir).unwrap(); // Build defaults, then merge overrides @@ -282,8 +262,8 @@ fn setup_run_dir( run_dir } -fn find_run_dir(home: &std::path::Path, run_id: &str) -> std::path::PathBuf { - let runs_dir = home.join(".fabro").join("runs"); +fn find_run_dir(storage_dir: &std::path::Path, run_id: &str) -> std::path::PathBuf { + let runs_dir = storage_dir.join("runs"); std::fs::read_dir(&runs_dir) .unwrap() .flatten() @@ -535,23 +515,21 @@ fn dry_run_legacy_tool() { #[test] fn dry_run_writes_jsonl_and_live_json() { - let tmp = tempfile::tempdir().unwrap(); - let storage_dir = tmp.path().join("fabro-data"); + let context = test_context!(); - arc() + context + .command() .args([ "run", "--dry-run", "--auto-approve", - "--storage-dir", - storage_dir.to_str().unwrap(), "../../../test/simple.fabro", ]) .assert() .success(); // Find the single run directory under storage_dir/runs/ - let runs_base = storage_dir.join("runs"); + let runs_base = context.storage_dir.join("runs"); assert!(runs_base.exists(), "runs/ directory should exist"); let entries: Vec<_> = std::fs::read_dir(&runs_base) .unwrap() @@ -605,19 +583,17 @@ fn dry_run_writes_jsonl_and_live_json() { #[test] fn run_id_passthrough_uses_provided_ulid() { - let tmp = tempfile::tempdir().unwrap(); - let storage_dir = tmp.path().join("fabro-data"); let my_ulid = "01ARZ3NDEKTSV4RRFFQ69G5FAV"; + let context = test_context!(); - arc() + context + .command() .args([ "run", "--dry-run", "--auto-approve", "--run-id", my_ulid, - "--storage-dir", - storage_dir.to_str().unwrap(), "../../../test/simple.fabro", ]) .assert() @@ -629,7 +605,9 @@ fn run_id_passthrough_uses_provided_ulid() { #[test] fn detach_flag_appears_in_help() { - arc() + let context = test_context!(); + context + .command() .args(["run", "--help"]) .assert() .success() @@ -638,7 +616,9 @@ fn detach_flag_appears_in_help() { #[test] fn detach_prints_ulid_and_exits() { - let output = arc() + let context = test_context!(); + let output = context + .command() .args([ "run", "--detach", @@ -664,17 +644,15 @@ fn detach_prints_ulid_and_exits() { #[test] fn detach_creates_run_dir_with_detach_log() { - let tmp = tempfile::tempdir().unwrap(); - let storage_dir = tmp.path().join("fabro-data"); + let context = test_context!(); - let output = arc() + let output = context + .command() .args([ "run", "--detach", "--dry-run", "--auto-approve", - "--storage-dir", - storage_dir.to_str().unwrap(), "../../../test/simple.fabro", ]) .assert() @@ -689,7 +667,7 @@ fn detach_creates_run_dir_with_detach_log() { // Run dir should have been created under storage_dir/runs/ and the launcher // log should live under storage_dir/launchers/. - let runs_base = storage_dir.join("runs"); + let runs_base = context.storage_dir.join("runs"); assert!(runs_base.exists(), "runs/ directory should exist"); let entries: Vec<_> = std::fs::read_dir(&runs_base) .unwrap() @@ -698,7 +676,8 @@ fn detach_creates_run_dir_with_detach_log() { assert_eq!(entries.len(), 1, "should have exactly one run directory"); let run_dir = entries[0].path(); assert!( - storage_dir + context + .storage_dir .join("launchers") .join(format!("{ulid}.log")) .exists(), @@ -711,7 +690,9 @@ fn detach_creates_run_dir_with_detach_log() { #[test] fn resume_help_shows_expected_args() { - arc() + let context = test_context!(); + context + .command() .args(["resume", "--help"]) .assert() .success() @@ -722,12 +703,15 @@ fn resume_help_shows_expected_args() { #[test] fn resume_requires_run_arg() { - arc().args(["resume"]).assert().failure(); + let context = test_context!(); + context.command().args(["resume"]).assert().failure(); } #[test] fn run_help_no_longer_shows_resume_or_run_branch() { - arc() + let context = test_context!(); + context + .command() .args(["run", "--help"]) .assert() .success() @@ -737,16 +721,14 @@ fn run_help_no_longer_shows_resume_or_run_branch() { #[test] fn rewind_and_fork_recover_missing_metadata_from_store() { - let storage_root = tempfile::tempdir().unwrap(); - let storage_dir = storage_root.path().join("fabro-data"); - let configured_home = init_cli_home(&storage_dir); + let context = test_context!(); let repo_dir = tempfile::tempdir().unwrap(); Repository::init(repo_dir.path()).unwrap(); let source_run_id = "01ARZ3NDEKTSV4RRFFQ69G5FAW"; let expected_shas = seed_run_branch(repo_dir.path(), source_run_id, &["start", "build"]); Runtime::new().unwrap().block_on(seed_durable_run( - &storage_dir, + &context.storage_dir, repo_dir.path(), source_run_id, )); @@ -756,9 +738,8 @@ fn rewind_and_fork_recover_missing_metadata_from_store() { "metadata branch should start missing" ); - let rewind_list = arc() - .env("HOME", configured_home.path()) - .env("NO_COLOR", "1") + let rewind_list = context + .command() .current_dir(repo_dir.path()) .args(["rewind", source_run_id, "--list"]) .timeout(Duration::from_secs(15)) @@ -793,9 +774,8 @@ fn rewind_and_fork_recover_missing_metadata_from_store() { ); let before_child = list_metadata_run_ids(repo_dir.path()); - arc() - .env("HOME", configured_home.path()) - .env("NO_COLOR", "1") + context + .command() .current_dir(repo_dir.path()) .args(["fork", source_run_id, "--no-push"]) .timeout(Duration::from_secs(15)) @@ -812,9 +792,8 @@ fn rewind_and_fork_recover_missing_metadata_from_store() { Some(expected_shas[1].as_str()) ); - let child_rewind = arc() - .env("HOME", configured_home.path()) - .env("NO_COLOR", "1") + let child_rewind = context + .command() .current_dir(repo_dir.path()) .args(["rewind", child_run_id, "@1", "--no-push"]) .timeout(Duration::from_secs(15)) @@ -834,9 +813,8 @@ fn rewind_and_fork_recover_missing_metadata_from_store() { ); let before_grandchild = after_child; - arc() - .env("HOME", configured_home.path()) - .env("NO_COLOR", "1") + context + .command() .current_dir(repo_dir.path()) .args(["fork", child_run_id, "--no-push"]) .timeout(Duration::from_secs(15)) @@ -854,7 +832,7 @@ fn rewind_and_fork_recover_missing_metadata_from_store() { #[test] fn completed_run_preserves_workflow_slug_for_lookup() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); let project = tempfile::tempdir().unwrap(); let workflow_dir = project.path().join("workflows").join("sluggy"); std::fs::create_dir_all(&workflow_dir).unwrap(); @@ -871,8 +849,8 @@ digraph BarBaz { ) .unwrap(); - arc() - .env("HOME", home.path()) + context + .command() .current_dir(project.path()) .args([ "create", @@ -885,30 +863,30 @@ digraph BarBaz { .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .current_dir(project.path()) .args(["start", "sluggy"]) .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .current_dir(project.path()) .args(["attach", "01ARZ3NDEKTSV4RRFFQ69G5FAX"]) .timeout(std::time::Duration::from_secs(10)) .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .current_dir(project.path()) .args(["attach", "sluggy"]) .timeout(std::time::Duration::from_secs(10)) .assert() .success(); - let run_dir = find_run_dir(home.path(), "01ARZ3NDEKTSV4RRFFQ69G5FAX"); + let run_dir = find_run_dir(&context.storage_dir, "01ARZ3NDEKTSV4RRFFQ69G5FAX"); let run_record: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(run_dir.join("run.json")).unwrap()).unwrap(); assert_eq!(run_record["graph"]["name"].as_str(), Some("BarBaz")); @@ -917,7 +895,7 @@ digraph BarBaz { #[test] fn standalone_file_run_uses_file_stem_slug_for_lookup() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); let workflow_dir = tempfile::tempdir().unwrap(); let workflow_path = workflow_dir.path().join("alpha.fabro"); std::fs::write( @@ -932,8 +910,8 @@ digraph FooWorkflow { ) .unwrap(); - arc() - .env("HOME", home.path()) + context + .command() .args([ "create", "--dry-run", @@ -945,20 +923,20 @@ digraph FooWorkflow { .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .args(["start", "alpha"]) .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .args(["attach", "alpha"]) .timeout(std::time::Duration::from_secs(10)) .assert() .success(); - let run_dir = find_run_dir(home.path(), "01ARZ3NDEKTSV4RRFFQ69G5FAY"); + let run_dir = find_run_dir(&context.storage_dir, "01ARZ3NDEKTSV4RRFFQ69G5FAY"); let run_record: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(run_dir.join("run.json")).unwrap()).unwrap(); assert_eq!(run_record["graph"]["name"].as_str(), Some("FooWorkflow")); @@ -967,11 +945,11 @@ digraph FooWorkflow { #[test] fn dry_run_create_start_attach_works_with_default_run_lookup() { - let home = tempfile::tempdir().unwrap(); let run_id = "01ARZ3NDEKTSV4RRFFQ69G5FAZ"; + let context = test_context!(); - arc() - .env("HOME", home.path()) + context + .command() .args([ "create", "--dry-run", @@ -984,20 +962,16 @@ fn dry_run_create_start_attach_works_with_default_run_lookup() { .success() .stdout(predicate::str::contains(run_id)); - let run_dir = find_run_dir(home.path(), run_id); + let run_dir = find_run_dir(&context.storage_dir, run_id); assert!( run_dir.join("run.json").exists(), "create should persist run.json so the run is discoverable" ); - arc() - .env("HOME", home.path()) - .args(["start", run_id]) - .assert() - .success(); + context.command().args(["start", run_id]).assert().success(); - arc() - .env("HOME", home.path()) + context + .command() .args(["attach", run_id]) .timeout(std::time::Duration::from_secs(10)) .assert() @@ -1008,11 +982,11 @@ fn dry_run_create_start_attach_works_with_default_run_lookup() { #[test] fn dry_run_detach_attach_works_with_default_run_lookup() { - let home = tempfile::tempdir().unwrap(); let run_id = "01ARZ3NDEKTSV4RRFFQ69G5FB0"; + let context = test_context!(); - arc() - .env("HOME", home.path()) + context + .command() .args([ "run", "--detach", @@ -1026,8 +1000,8 @@ fn dry_run_detach_attach_works_with_default_run_lookup() { .success() .stdout(predicate::str::contains(run_id)); - arc() - .env("HOME", home.path()) + context + .command() .args(["attach", run_id]) .timeout(std::time::Duration::from_secs(10)) .assert() @@ -1036,10 +1010,9 @@ fn dry_run_detach_attach_works_with_default_run_lookup() { #[test] fn start_by_workflow_name_prefers_newly_created_submitted_run() { - let home = tempfile::tempdir().unwrap(); - let old_run_dir = home - .path() - .join(".fabro") + let context = test_context!(); + let old_run_dir = context + .storage_dir .join("runs") .join("01ARZ3NDEKTSV4RRFFQ69G5FB1"); std::fs::create_dir_all(&old_run_dir).unwrap(); @@ -1068,8 +1041,8 @@ fn start_by_workflow_name_prefers_newly_created_submitted_run() { .unwrap(); let run_id = "01ARZ3NDEKTSV4RRFFQ69G5FB2"; - arc() - .env("HOME", home.path()) + context + .command() .args([ "create", "--dry-run", @@ -1082,20 +1055,20 @@ fn start_by_workflow_name_prefers_newly_created_submitted_run() { .success() .stdout(predicate::str::contains(run_id)); - arc() - .env("HOME", home.path()) + context + .command() .args(["start", "smoke"]) .assert() .success(); - arc() - .env("HOME", home.path()) + context + .command() .args(["attach", run_id]) .timeout(std::time::Duration::from_secs(10)) .assert() .success(); - let new_run_dir = find_run_dir(home.path(), run_id); + let new_run_dir = find_run_dir(&context.storage_dir, run_id); let status = std::fs::read_to_string(new_run_dir.join("status.json")).unwrap(); assert!( status.contains("\"status\": \"succeeded\""), @@ -1108,9 +1081,11 @@ fn start_by_workflow_name_prefers_newly_created_submitted_run() { // the engine should read the snapshot saved at create time. #[test] fn bug2_detached_uses_cached_graph_not_original_path() { - let dir = tempfile::tempdir().unwrap(); - let storage_dir = dir.path().join("storage"); - let run_dir = storage_dir.join("runs").join("01ARZ3NDEKTSV4RRFFQ69G5FB3"); + let context = test_context!(); + let run_dir = context + .storage_dir + .join("runs") + .join("01ARZ3NDEKTSV4RRFFQ69G5FB3"); std::fs::create_dir_all(&run_dir).unwrap(); let dot = "\ @@ -1153,19 +1128,20 @@ digraph G { std::fs::write(run_dir.join("graph.fabro"), dot).unwrap(); // __detached should use graph.fabro and never reference the deleted file. - let output = arc() + let output = context + .command() .args([ "__detached", "--run-dir", run_dir.to_str().unwrap(), "--launcher-path", - storage_dir + context + .storage_dir .join("launchers") .join("01ARZ3NDEKTSV4RRFFQ69G5FB3.json") .to_str() .unwrap(), ]) - .env("NO_COLOR", "1") .timeout(std::time::Duration::from_secs(15)) .output() .expect("process should start"); @@ -1180,9 +1156,8 @@ digraph G { #[test] fn bug4_detached_resume_rejects_completed_run_without_mutating_it() { - let home = tempfile::tempdir().unwrap(); - let project = tempfile::tempdir().unwrap(); - let workflow_path = project.path().join("workflow.fabro"); + let context = test_context!(); + let workflow_path = context.temp_dir.join("workflow.fabro"); std::fs::write( &workflow_path, "\ @@ -1195,9 +1170,9 @@ digraph Test { ) .unwrap(); - let run = arc() - .env("HOME", home.path()) - .current_dir(project.path()) + let run = context + .command() + .current_dir(&context.temp_dir) .args([ "run", "--dry-run", @@ -1213,15 +1188,15 @@ digraph Test { .trim() .to_string(); - arc() - .env("HOME", home.path()) + context + .command() .args(["wait", &run_id]) .timeout(std::time::Duration::from_secs(10)) .assert() .success(); - let inspect_before = arc() - .env("HOME", home.path()) + let inspect_before = context + .command() .args(["inspect", &run_id]) .assert() .success(); @@ -1237,15 +1212,15 @@ digraph Test { .unwrap() .to_string(); - let storage_dir = home.path().join(".fabro"); - arc() - .env("HOME", home.path()) + context + .command() .args([ "__detached", "--run-dir", &run_dir, "--launcher-path", - storage_dir + context + .storage_dir .join("launchers") .join(format!("{run_id}.json")) .to_str() @@ -1257,8 +1232,8 @@ digraph Test { .failure() .stderr(predicate::str::contains("nothing to resume")); - let inspect_after = arc() - .env("HOME", home.path()) + let inspect_after = context + .command() .args(["inspect", &run_id]) .assert() .success(); @@ -1277,10 +1252,9 @@ digraph Test { #[test] fn bug5_detached_uses_snapshotted_app_id_for_github_credentials() { - let storage_dir = tempfile::tempdir().unwrap(); - let home = init_cli_home(storage_dir.path()); - let run_dir = storage_dir - .path() + let context = test_context!(); + let run_dir = context + .storage_dir .join("runs") .join("01ARZ3NDEKTSV4RRFFQ69G5FB4"); std::fs::create_dir_all(&run_dir).unwrap(); @@ -1324,16 +1298,16 @@ digraph G { .unwrap(); std::fs::write(run_dir.join("graph.fabro"), dot).unwrap(); - arc() - .env("HOME", home.path()) + context + .command() .env("GITHUB_APP_PRIVATE_KEY", "%%%not-base64%%%") .args([ "__detached", "--run-dir", run_dir.to_str().unwrap(), "--launcher-path", - storage_dir - .path() + context + .storage_dir .join("launchers") .join("01ARZ3NDEKTSV4RRFFQ69G5FB4.json") .to_str() @@ -1351,10 +1325,10 @@ digraph G { // engine consumes interview_response.json, so reattach remains safe. #[test] fn bug3_attach_leaves_interview_request_until_engine_consumes_response() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); let run_dir = setup_run_dir( - home.path(), + &context.storage_dir, "01ARZ3NDEKTSV4RRFFQ69G5FB5", serde_json::json!({}), &[ @@ -1390,9 +1364,8 @@ fn bug3_attach_leaves_interview_request_until_engine_consumes_response() { .unwrap(); // Pipe "y\n" so ConsoleInterviewer doesn't block on stdin - let _ = arc() - .env("HOME", home.path()) - .env("NO_COLOR", "1") + let _ = context + .command() .args(["attach", "01ARZ3NDEKTSV4RRFFQ69G5FB5"]) .write_stdin("y\n") .timeout(std::time::Duration::from_secs(5)) @@ -1414,10 +1387,10 @@ fn bug3_attach_leaves_interview_request_until_engine_consumes_response() { #[test] fn attach_closed_stdin_keeps_interview_pending() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); let run_dir = setup_run_dir( - home.path(), + &context.storage_dir, "01ARZ3NDEKTSV4RRFFQ69G5FB6", serde_json::json!({}), &[ @@ -1449,9 +1422,8 @@ fn attach_closed_stdin_keeps_interview_pending() { ) .unwrap(); - let assert = arc() - .env("HOME", home.path()) - .env("NO_COLOR", "1") + let assert = context + .command() .args(["attach", "01ARZ3NDEKTSV4RRFFQ69G5FB6"]) .timeout(std::time::Duration::from_secs(5)) .assert() @@ -1480,13 +1452,13 @@ fn attach_closed_stdin_keeps_interview_pending() { // Currently ProgressUI is created with verbose=false regardless of config. #[test] fn bug4_attach_respects_verbose_from_spec() { - let home = tempfile::tempdir().unwrap(); + let context = test_context!(); // Use pre-rename field names so handle_json_line can parse them // (isolates this test from bug 1). With 2 turns and 1 tool call, // verbose mode should display "(2 turns, 1 tools, ...)" in the output. let run_dir = setup_run_dir( - home.path(), + &context.storage_dir, "01ARZ3NDEKTSV4RRFFQ69G5FB7", serde_json::json!({"verbose": true}), &[ @@ -1519,9 +1491,8 @@ fn bug4_attach_respects_verbose_from_spec() { ) .unwrap(); - let output = arc() - .env("HOME", home.path()) - .env("NO_COLOR", "1") + let output = context + .command() .args(["attach", "01ARZ3NDEKTSV4RRFFQ69G5FB7"]) .timeout(std::time::Duration::from_secs(10)) .output() diff --git a/lib/crates/fabro-cli/tests/it/cmd/secret.rs b/lib/crates/fabro-cli/tests/it/cmd/secret.rs index 48524eb2d..add564f2d 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/secret.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/secret.rs @@ -1,13 +1,6 @@ use fabro_test::{fabro_snapshot, test_context}; use predicates; -#[allow(deprecated)] -fn fabro() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.env("NO_COLOR", "1"); - cmd -} - #[test] fn help() { let context = test_context!(); @@ -41,58 +34,54 @@ fn help() { #[test] fn test_secret_lifecycle() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - let secret = |args: &[&str]| -> assert_cmd::assert::Assert { - fabro().env("HOME", tmp.path()).args(args).assert() - }; + let secret = + |args: &[&str]| -> assert_cmd::assert::Assert { context.secret().args(args).assert() }; // 1. set FOO=bar - secret(&["secret", "set", "FOO", "bar"]).success(); + secret(&["set", "FOO", "bar"]).success(); // 2. get FOO -> stdout is "bar\n" - secret(&["secret", "get", "FOO"]).success().stdout("bar\n"); + secret(&["get", "FOO"]).success().stdout("bar\n"); // 3. list -> contains FOO - secret(&["secret", "list"]) + secret(&["list"]) .success() .stdout(predicates::str::contains("FOO")); // 4. update FOO - secret(&["secret", "set", "FOO", "updated"]).success(); + secret(&["set", "FOO", "updated"]).success(); // 5. get FOO -> "updated\n" - secret(&["secret", "get", "FOO"]) - .success() - .stdout("updated\n"); + secret(&["get", "FOO"]).success().stdout("updated\n"); // 6. rm FOO - secret(&["secret", "rm", "FOO"]).success(); + secret(&["rm", "FOO"]).success(); // 7. get FOO -> fails - secret(&["secret", "get", "FOO"]).failure(); + secret(&["get", "FOO"]).failure(); } #[test] fn test_secret_list_show_values() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - let secret = |args: &[&str]| -> assert_cmd::assert::Assert { - fabro().env("HOME", tmp.path()).args(args).assert() - }; + let secret = + |args: &[&str]| -> assert_cmd::assert::Assert { context.secret().args(args).assert() }; - secret(&["secret", "set", "A", "1"]).success(); - secret(&["secret", "set", "B", "2"]).success(); + secret(&["set", "A", "1"]).success(); + secret(&["set", "B", "2"]).success(); // Without --show-values: just keys - let out = secret(&["secret", "list"]).success(); + let out = secret(&["list"]).success(); let stdout = String::from_utf8(out.get_output().stdout.clone()).unwrap(); assert!(stdout.contains("A")); assert!(stdout.contains("B")); assert!(!stdout.contains("A=1")); // With --show-values: KEY=VALUE - secret(&["secret", "list", "--show-values"]) + secret(&["list", "--show-values"]) .success() .stdout(predicates::str::contains("A=1")) .stdout(predicates::str::contains("B=2")); @@ -100,17 +89,13 @@ fn test_secret_list_show_values() { #[test] fn test_secret_list_alias_ls() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "set", "X", "y"]) - .assert() - .success(); + context.secret().args(["set", "X", "y"]).assert().success(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "ls"]) + context + .secret() + .args(["ls"]) .assert() .success() .stdout(predicates::str::contains("X")); @@ -118,11 +103,11 @@ fn test_secret_list_alias_ls() { #[test] fn test_secret_get_missing_key() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "get", "NOPE"]) + context + .secret() + .args(["get", "NOPE"]) .assert() .failure() .stderr(predicates::str::contains("secret not found")); @@ -130,11 +115,11 @@ fn test_secret_get_missing_key() { #[test] fn test_secret_rm_missing_key() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "rm", "NOPE"]) + context + .secret() + .args(["rm", "NOPE"]) .assert() .failure() .stderr(predicates::str::contains("secret not found")); @@ -142,17 +127,17 @@ fn test_secret_rm_missing_key() { #[test] fn test_secret_value_with_equals() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "set", "URL", "https://x.com?a=1&b=2"]) + context + .secret() + .args(["set", "URL", "https://x.com?a=1&b=2"]) .assert() .success(); - fabro() - .env("HOME", tmp.path()) - .args(["secret", "get", "URL"]) + context + .secret() + .args(["get", "URL"]) .assert() .success() .stdout("https://x.com?a=1&b=2\n"); diff --git a/lib/crates/fabro-cli/tests/it/cmd/workflow.rs b/lib/crates/fabro-cli/tests/it/cmd/workflow.rs index 76bc65fc2..4e63f5c6c 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/workflow.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/workflow.rs @@ -1,19 +1,13 @@ +use fabro_test::test_context; use predicates; -#[allow(deprecated)] -fn fabro() -> assert_cmd::Command { - let mut cmd = assert_cmd::Command::cargo_bin("fabro").unwrap(); - cmd.env("NO_COLOR", "1"); - cmd -} - #[test] fn list() { - let tmp = tempfile::tempdir().unwrap(); + let context = test_context!(); // Minimal project structure: fabro.toml + a workflow - std::fs::write(tmp.path().join("fabro.toml"), "version = 1\n").unwrap(); - let wf_dir = tmp.path().join("workflows/my_test_wf"); + std::fs::write(context.temp_dir.join("fabro.toml"), "version = 1\n").unwrap(); + let wf_dir = context.temp_dir.join("workflows/my_test_wf"); std::fs::create_dir_all(&wf_dir).unwrap(); std::fs::write( wf_dir.join("workflow.toml"), @@ -21,9 +15,10 @@ fn list() { ) .unwrap(); - fabro() + context + .command() .args(["workflow", "list"]) - .current_dir(tmp.path()) + .current_dir(&context.temp_dir) .assert() .success() // workflow list prints to stderr