diff --git a/lib/crates/fabro-cli/tests/it/cmd/attach.rs b/lib/crates/fabro-cli/tests/it/cmd/attach.rs index 633868d66..0bf4777c7 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/attach.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/attach.rs @@ -103,7 +103,6 @@ fn attach_before_completion_streams_to_finished_state() { let gate = write_gated_workflow(&context.temp_dir.join("slow.fabro"), "slow", "Run slowly"); let mut run_cmd = context.command(); - run_cmd.current_dir(&context.temp_dir); run_cmd.env("OPENAI_API_KEY", "test"); run_cmd.args([ "run", @@ -136,7 +135,6 @@ fn attach_before_completion_streams_to_finished_state() { gate.release(); }); let mut attach_cmd = context.command(); - attach_cmd.current_dir(&context.temp_dir); attach_cmd.args(["attach", &run_id]); let (snapshot, _output) = run_and_format(&mut attach_cmd, &filters); release_gate.join().expect("gate releaser should join"); @@ -176,7 +174,6 @@ fn attach_json_errors_without_prompting_for_human_input() { let run_output = context .command() - .current_dir(&context.temp_dir) .env("OPENAI_API_KEY", "test") .args([ "run", diff --git a/lib/crates/fabro-cli/tests/it/cmd/detached.rs b/lib/crates/fabro-cli/tests/it/cmd/detached.rs index a71bf51b2..e201f5912 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/detached.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/detached.rs @@ -187,7 +187,6 @@ digraph Test { let run = context .command() - .current_dir(&context.temp_dir) .args([ "run", "--dry-run", diff --git a/lib/crates/fabro-cli/tests/it/cmd/exec.rs b/lib/crates/fabro-cli/tests/it/cmd/exec.rs index 67404a174..19146ce82 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/exec.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/exec.rs @@ -75,7 +75,6 @@ fn exec_missing_api_key_exits_with_error() { cmd.arg("test prompt"); cmd.env_clear(); cmd.env("HOME", &context.home_dir); - cmd.current_dir(&context.temp_dir); fabro_snapshot!(context.filters(), cmd, @" success: false exit_code: 1 @@ -99,7 +98,6 @@ fn exec_uses_user_config_defaults() { cmd.env("HOME", &context.home_dir); cmd.env("FABRO_STORAGE_DIR", &context.storage_dir); cmd.env("FABRO_NO_UPGRADE_CHECK", "true"); - cmd.current_dir(&context.temp_dir); fabro_snapshot!(context.filters(), cmd, @" success: false @@ -125,7 +123,6 @@ fn exec_creates_file() { "claude-haiku-4-5", "Create a file called hello.txt containing exactly 'Hello'", ]) - .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); @@ -153,7 +150,6 @@ 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(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); @@ -174,7 +170,6 @@ fn exec_read_only_blocks_write() { "claude-haiku-4-5", "Create a file called forbidden.txt containing 'should not exist'", ]) - .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); @@ -201,7 +196,6 @@ fn exec_json_output_format() { "claude-haiku-4-5", "Create a file called test.txt containing 'test'", ]) - .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success() @@ -237,7 +231,6 @@ fn exec_read_and_edit() { "claude-haiku-4-5", "Read data.txt then replace its entire content with 'new content'", ]) - .current_dir(&context.temp_dir) .timeout(std::time::Duration::from_secs(120)) .assert() .success(); diff --git a/lib/crates/fabro-cli/tests/it/cmd/fork.rs b/lib/crates/fabro-cli/tests/it/cmd/fork.rs index 4947aab15..989492c6d 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/fork.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/fork.rs @@ -42,7 +42,6 @@ fn help() { fn fork_outside_git_repo_errors() { let context = test_context!(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["fork", "01ARZ3NDEKTSV4RRFFQ69G5FAW"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/cmd/parse.rs b/lib/crates/fabro-cli/tests/it/cmd/parse.rs index 5fcfdf7fa..ea720e917 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/parse.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/parse.rs @@ -36,7 +36,6 @@ fn parse_valid_workflow_prints_ast_json() { "digraph Tiny {\n graph [goal=\"Parse a tiny workflow\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n main [label=\"Main\", prompt=\"Do the thing\"]\n start -> main -> exit\n}\n", ); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["parse", "tiny.fabro"]); fabro_snapshot!(context.filters(), cmd, @r###" @@ -125,7 +124,6 @@ fn parse_invalid_dot_fails_cleanly() { "digraph Bad {\n start [shape=Mdiamond]\n exit [shape=Msquare]\n start -> exit\n", ); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["parse", "bad.fabro"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/cmd/preflight.rs b/lib/crates/fabro-cli/tests/it/cmd/preflight.rs index a3878f3c9..01a07f9ce 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/preflight.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/preflight.rs @@ -49,7 +49,7 @@ fn preflight_invalid_workflow_fails_with_validation_output() { ----- stdout ----- ----- stderr ----- Workflow: Invalid (2 nodes, 1 edges) - Graph: ../../../test/invalid.fabro + 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) error: Validation failed diff --git a/lib/crates/fabro-cli/tests/it/cmd/repo.rs b/lib/crates/fabro-cli/tests/it/cmd/repo.rs index 8ab8a2625..1f0074fed 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/repo.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/repo.rs @@ -46,12 +46,7 @@ fn test_repo_deinit_removes_fabro_toml_and_dir() { assert!(context.temp_dir.join("fabro.toml").exists()); assert!(context.temp_dir.join("fabro").exists()); - context - .repo() - .arg("deinit") - .current_dir(&context.temp_dir) - .assert() - .success(); + context.repo().arg("deinit").assert().success(); assert!( !context.temp_dir.join("fabro.toml").exists(), @@ -70,7 +65,6 @@ fn test_repo_deinit_fails_when_not_initialized() { let mut cmd = context.repo(); cmd.arg("deinit"); - cmd.current_dir(&context.temp_dir); fabro_snapshot!(context.filters(), cmd, @" success: false exit_code: 1 @@ -85,12 +79,7 @@ fn test_repo_init_skill_installs_skill_files() { let context = test_context!(); context.git_init(); - context - .repo() - .args(["init", "--skill"]) - .current_dir(&context.temp_dir) - .assert() - .success(); + context.repo().args(["init", "--skill"]).assert().success(); // Skill files should be installed under .claude/skills/fabro-create-workflow/ let skill_dir = context diff --git a/lib/crates/fabro-cli/tests/it/cmd/repo_init.rs b/lib/crates/fabro-cli/tests/it/cmd/repo_init.rs index 789e6dd13..d6110dbea 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/repo_init.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/repo_init.rs @@ -33,7 +33,6 @@ fn repo_init_creates_fabro_toml_and_hello_workflow() { context.git_init(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["repo", "init"]); fabro_snapshot!(context.filters(), cmd, @" @@ -111,7 +110,6 @@ fn repo_init_rejects_already_initialized_repo() { std::fs::write(context.temp_dir.join("fabro.toml"), "version = 1\n").unwrap(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["repo", "init"]); fabro_snapshot!(context.filters(), cmd, @" @@ -127,7 +125,6 @@ fn repo_init_rejects_already_initialized_repo() { fn repo_init_errors_outside_git_repo() { let context = test_context!(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["repo", "init"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/cmd/rewind.rs b/lib/crates/fabro-cli/tests/it/cmd/rewind.rs index db15f0cfe..2e1f186c3 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/rewind.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/rewind.rs @@ -42,7 +42,6 @@ fn help() { fn rewind_outside_git_repo_errors() { let context = test_context!(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["rewind", "01ARZ3NDEKTSV4RRFFQ69G5FAW", "--list"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/cmd/run.rs b/lib/crates/fabro-cli/tests/it/cmd/run.rs index acd2f6662..60fb64374 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/run.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/run.rs @@ -56,7 +56,7 @@ fn dry_run_simple() { ----- stdout ----- ----- stderr ----- Workflow: Simple (4 nodes, 3 edges) - Graph: ../../../test/simple.fabro + Graph: [FIXTURES]/simple.fabro Goal: Run tests and report results Sandbox: local (ready in [TIME]) @@ -80,11 +80,9 @@ fn dry_run_simple() { fn dry_run_writes_jsonl_and_live_json() { let context = test_context!(); let run_id = "01ARZ3NDEKTSV4RRFFQ69G5FB8"; - let workflow = example_fixture("simple.fabro"); context .command() - .current_dir(&context.temp_dir) .args([ "run", "--dry-run", @@ -93,7 +91,7 @@ fn dry_run_writes_jsonl_and_live_json() { "local", "--run-id", run_id, - workflow.to_str().unwrap(), + example_fixture("simple.fabro").to_str().unwrap(), ]) .assert() .success(); @@ -427,7 +425,7 @@ fn run_id_passthrough_uses_provided_ulid() { "--auto-approve", "--run-id", run_id, - "../../../test/simple.fabro", + example_fixture("simple.fabro").to_str().unwrap(), ]) .assert() .success(); @@ -461,7 +459,6 @@ fn json_run_implies_auto_approve_for_human_gates() { let output = context .command() - .current_dir(&context.temp_dir) .args([ "--json", "run", @@ -811,7 +808,7 @@ fn detach_prints_ulid_and_exits() { "--detach", "--dry-run", "--auto-approve", - "../../../test/simple.fabro", + example_fixture("simple.fabro").to_str().unwrap(), ]); fabro_snapshot!(context.filters(), cmd, @" success: true @@ -835,7 +832,7 @@ fn detach_creates_run_dir_with_detach_log() { "--auto-approve", "--run-id", run_id, - "../../../test/simple.fabro", + example_fixture("simple.fabro").to_str().unwrap(), ]) .assert() .success(); diff --git a/lib/crates/fabro-cli/tests/it/cmd/start.rs b/lib/crates/fabro-cli/tests/it/cmd/start.rs index 7f7a85503..f0e967068 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/start.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/start.rs @@ -163,7 +163,6 @@ fn start_rejects_already_active_or_completed_run() { let gate = write_gated_workflow(&context.temp_dir.join("slow.fabro"), "slow", "Run slowly"); let mut create_cmd = context.command(); - create_cmd.current_dir(&context.temp_dir); create_cmd.env("OPENAI_API_KEY", "test"); create_cmd.args([ "create", @@ -185,7 +184,6 @@ fn start_rejects_already_active_or_completed_run() { let run = resolve_run(&context, &run_id); let mut start_cmd = context.command(); - start_cmd.current_dir(&context.temp_dir); start_cmd.env("OPENAI_API_KEY", "test"); start_cmd.args(["start", &run_id]); start_cmd.assert().success(); @@ -193,7 +191,6 @@ fn start_rejects_already_active_or_completed_run() { wait_for_status(&run.run_dir, &["running"]); let mut active_cmd = context.command(); - active_cmd.current_dir(&context.temp_dir); active_cmd.args(["start", &run_id]); fabro_snapshot!(context.filters(), active_cmd, @" success: false @@ -207,7 +204,6 @@ fn start_rejects_already_active_or_completed_run() { wait_for_status(&run.run_dir, &["succeeded"]); let mut completed_cmd = context.command(); - completed_cmd.current_dir(&context.temp_dir); completed_cmd.args(["start", &run_id]); fabro_snapshot!(context.filters(), completed_cmd, @" success: false diff --git a/lib/crates/fabro-cli/tests/it/cmd/support.rs b/lib/crates/fabro-cli/tests/it/cmd/support.rs index fad14c496..0a6d5ab36 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/support.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/support.rs @@ -41,7 +41,10 @@ enum GitWorkflowKind { } pub(crate) fn fixture(name: &str) -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join(format!("../../../test/{name}")) + Path::new(env!("CARGO_MANIFEST_DIR")) + .join(format!("../../../test/{name}")) + .canonicalize() + .expect("fixture path should exist") } pub(crate) fn output_stderr(output: &Output) -> String { diff --git a/lib/crates/fabro-cli/tests/it/cmd/validate.rs b/lib/crates/fabro-cli/tests/it/cmd/validate.rs index f11e18d8d..1b2ae519c 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/validate.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/validate.rs @@ -1,7 +1,10 @@ use fabro_test::{fabro_snapshot, test_context}; fn fixture(name: &str) -> std::path::PathBuf { - std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join(format!("../../../test/{name}")) + std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join(format!("../../../test/{name}")) + .canonicalize() + .expect("fixture path should exist") } #[test] @@ -43,7 +46,7 @@ fn simple() { ----- stdout ----- ----- stderr ----- Workflow: Simple (4 nodes, 3 edges) - Graph: ../../../test/simple.fabro + Graph: [FIXTURES]/simple.fabro Validation: OK "); } @@ -59,7 +62,7 @@ fn branching() { ----- stdout ----- ----- stderr ----- Workflow: Branch (6 nodes, 6 edges) - Graph: ../../../test/branching.fabro + Graph: [FIXTURES]/branching.fabro warning [node: implement]: Node 'implement' has goal_gate=true but no retry_target or fallback_retry_target (goal_gate_has_retry) Validation: OK "); @@ -76,7 +79,7 @@ fn conditions() { ----- stdout ----- ----- stderr ----- Workflow: Conditions (5 nodes, 5 edges) - Graph: ../../../test/conditions.fabro + Graph: [FIXTURES]/conditions.fabro Validation: OK "); } @@ -92,7 +95,7 @@ fn parallel() { ----- stdout ----- ----- stderr ----- Workflow: Parallel (7 nodes, 7 edges) - Graph: ../../../test/parallel.fabro + Graph: [FIXTURES]/parallel.fabro Validation: OK "); } @@ -108,7 +111,7 @@ fn styled() { ----- stdout ----- ----- stderr ----- Workflow: Styled (5 nodes, 4 edges) - Graph: ../../../test/styled.fabro + Graph: [FIXTURES]/styled.fabro Validation: OK "); } @@ -124,7 +127,7 @@ fn legacy_tool() { ----- stdout ----- ----- stderr ----- Workflow: LegacyTool (3 nodes, 2 edges) - Graph: ../../../test/legacy_tool.fabro + Graph: [FIXTURES]/legacy_tool.fabro Validation: OK "); } @@ -140,7 +143,7 @@ fn invalid() { ----- stdout ----- ----- stderr ----- Workflow: Invalid (2 nodes, 1 edges) - Graph: ../../../test/invalid.fabro + 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) error: Validation failed diff --git a/lib/crates/fabro-cli/tests/it/cmd/workflow.rs b/lib/crates/fabro-cli/tests/it/cmd/workflow.rs index 3199e1a7a..bf1cd1a05 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/workflow.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/workflow.rs @@ -43,7 +43,6 @@ fn list() { let mut cmd = context.command(); cmd.args(["workflow", "list"]); - cmd.current_dir(&context.temp_dir); fabro_snapshot!(context.filters(), cmd, @" success: true exit_code: 0 diff --git a/lib/crates/fabro-cli/tests/it/cmd/workflow_create.rs b/lib/crates/fabro-cli/tests/it/cmd/workflow_create.rs index 2a494ebfc..9857b4cd9 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/workflow_create.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/workflow_create.rs @@ -147,7 +147,6 @@ fn workflow_create_rejects_existing_workflow() { fn workflow_create_errors_without_project_config() { let context = test_context!(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["workflow", "create", "hello-world"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/cmd/workflow_list.rs b/lib/crates/fabro-cli/tests/it/cmd/workflow_list.rs index 8edeb73b6..00f4f84d0 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/workflow_list.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/workflow_list.rs @@ -31,7 +31,6 @@ fn help() { fn workflow_list_errors_without_project_config() { let context = test_context!(); let mut cmd = context.command(); - cmd.current_dir(&context.temp_dir); cmd.args(["workflow", "list"]); fabro_snapshot!(context.filters(), cmd, @" diff --git a/lib/crates/fabro-cli/tests/it/scenario/exec.rs b/lib/crates/fabro-cli/tests/it/scenario/exec.rs index d12e43ae0..fba7ca76c 100644 --- a/lib/crates/fabro-cli/tests/it/scenario/exec.rs +++ b/lib/crates/fabro-cli/tests/it/scenario/exec.rs @@ -17,7 +17,6 @@ fn test_exec_creates_file() { "claude-haiku-4-5", "Create a file called hello.txt containing exactly 'Hello from exec scenario'", ]); - cmd.current_dir(&context.temp_dir); cmd.timeout(Duration::from_secs(120)); cmd.assert().success(); diff --git a/lib/crates/fabro-cli/tests/it/scenario/lifecycle.rs b/lib/crates/fabro-cli/tests/it/scenario/lifecycle.rs index 17a11aac6..f00e8c41f 100644 --- a/lib/crates/fabro-cli/tests/it/scenario/lifecycle.rs +++ b/lib/crates/fabro-cli/tests/it/scenario/lifecycle.rs @@ -2,7 +2,7 @@ use fabro_test::test_context; use serde_json::Value; use super::{fixture, read_json, timeout_for}; -use crate::support::fabro_json_snapshot; +use crate::support::{example_fixture, fabro_json_snapshot}; #[fabro_macros::e2e_test()] fn local_run_lifecycle() { @@ -112,7 +112,7 @@ fn dry_run_create_start_attach_works_with_default_run_lookup() { "--auto-approve", "--run-id", run_id, - "../../../test/simple.fabro", + example_fixture("simple.fabro").to_str().unwrap(), ]) .assert() .success(); @@ -155,7 +155,7 @@ fn dry_run_detach_attach_works_with_default_run_lookup() { "--auto-approve", "--run-id", run_id, - "../../../test/simple.fabro", + example_fixture("simple.fabro").to_str().unwrap(), ]) .assert() .success(); diff --git a/lib/crates/fabro-cli/tests/it/support/mod.rs b/lib/crates/fabro-cli/tests/it/support/mod.rs index 797759ba0..067afb449 100644 --- a/lib/crates/fabro-cli/tests/it/support/mod.rs +++ b/lib/crates/fabro-cli/tests/it/support/mod.rs @@ -32,7 +32,10 @@ macro_rules! fabro_json_snapshot { pub(crate) use fabro_json_snapshot; pub(crate) fn example_fixture(name: &str) -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join(format!("../../../test/{name}")) + Path::new(env!("CARGO_MANIFEST_DIR")) + .join(format!("../../../test/{name}")) + .canonicalize() + .expect("fixture path should exist") } pub(crate) fn read_json(path: impl AsRef) -> Value { diff --git a/lib/crates/fabro-cli/tests/it/workflow/dry_run_examples.rs b/lib/crates/fabro-cli/tests/it/workflow/dry_run_examples.rs index d3fa94488..98b0ac3e1 100644 --- a/lib/crates/fabro-cli/tests/it/workflow/dry_run_examples.rs +++ b/lib/crates/fabro-cli/tests/it/workflow/dry_run_examples.rs @@ -14,7 +14,7 @@ fn dry_run_branching() { ----- stdout ----- ----- stderr ----- Workflow: Branch (6 nodes, 6 edges) - Graph: ../../../test/branching.fabro + Graph: [FIXTURES]/branching.fabro Goal: Implement and validate a feature warning [node: implement]: Node 'implement' has goal_gate=true but no retry_target or fallback_retry_target (goal_gate_has_retry) @@ -49,7 +49,7 @@ fn dry_run_conditions() { ----- stdout ----- ----- stderr ----- Workflow: Conditions (5 nodes, 5 edges) - Graph: ../../../test/conditions.fabro + Graph: [FIXTURES]/conditions.fabro Goal: Test condition evaluation with OR and parentheses Sandbox: local (ready in [TIME]) @@ -81,7 +81,7 @@ fn dry_run_parallel() { ----- stdout ----- ----- stderr ----- Workflow: Parallel (7 nodes, 7 edges) - Graph: ../../../test/parallel.fabro + Graph: [FIXTURES]/parallel.fabro Goal: Test parallel and fan-in execution Sandbox: local (ready in [TIME]) @@ -114,7 +114,7 @@ fn dry_run_styled() { ----- stdout ----- ----- stderr ----- Workflow: Styled (5 nodes, 4 edges) - Graph: ../../../test/styled.fabro + Graph: [FIXTURES]/styled.fabro Goal: Build a styled pipeline Sandbox: local (ready in [TIME]) @@ -147,7 +147,7 @@ fn dry_run_legacy_tool() { ----- stdout ----- ----- stderr ----- Workflow: LegacyTool (3 nodes, 2 edges) - Graph: ../../../test/legacy_tool.fabro + Graph: [FIXTURES]/legacy_tool.fabro Goal: Verify backwards compatibility with old tool naming Sandbox: local (ready in [TIME]) diff --git a/lib/crates/fabro-test/src/lib.rs b/lib/crates/fabro-test/src/lib.rs index 7656f253d..f2429198e 100644 --- a/lib/crates/fabro-test/src/lib.rs +++ b/lib/crates/fabro-test/src/lib.rs @@ -1,9 +1,21 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Output; use assert_cmd::Command; use regex::Regex; +/// Walk up from `start` to find the repo-level `test/` fixtures directory. +pub fn find_test_fixtures_dir(start: &Path) -> Option { + let mut dir = start; + loop { + let candidate = dir.join("test"); + if candidate.is_dir() { + return candidate.canonicalize().ok(); + } + dir = dir.parent()?; + } +} + /// Static filters applied to every snapshot. static INSTA_FILTERS: &[(&str, &str)] = &[ (r"fabro \d+\.\d+\.\d+", "fabro [VERSION]"), @@ -127,6 +139,12 @@ impl TestContext { } } + /// Register a custom filter (regex pattern → replacement). + pub fn add_filter(&mut self, pattern: &str, replacement: &str) { + self.filters + .push((regex::escape(pattern), replacement.to_string())); + } + /// Returns the combined static + context-specific filters. pub fn filters(&self) -> Vec<(String, String)> { let mut filters = self.filters.clone(); @@ -139,8 +157,14 @@ impl TestContext { } /// Build a base `Command` with all isolation env vars set. + /// + /// The working directory defaults to `self.temp_dir` (a non-git temp + /// directory) so tests never accidentally interact with the real repo. + /// Tests that need a specific working directory can override this with + /// a subsequent `.current_dir(path)` call. pub fn command(&self) -> Command { let mut cmd = Command::new(&self.fabro_bin); + cmd.current_dir(&self.temp_dir); cmd.env("NO_COLOR", "1"); cmd.env("HOME", &self.home_dir); cmd.env("FABRO_NO_UPGRADE_CHECK", "true"); @@ -399,11 +423,21 @@ pub fn apply_filters(snapshot: &str, filters: &[(String, String)]) -> String { } /// Create a `TestContext` using the `fabro` binary built by cargo. +/// +/// Automatically registers a `[FIXTURES]` snapshot filter for the `test/` +/// directory at the repository root (found by walking up from `CARGO_MANIFEST_DIR`). #[macro_export] macro_rules! test_context { - () => { - $crate::TestContext::new(std::path::PathBuf::from(env!("CARGO_BIN_EXE_fabro"))) - }; + () => {{ + let mut ctx = + $crate::TestContext::new(std::path::PathBuf::from(env!("CARGO_BIN_EXE_fabro"))); + if let Some(fixtures_dir) = + $crate::find_test_fixtures_dir(std::path::Path::new(env!("CARGO_MANIFEST_DIR"))) + { + ctx.add_filter(fixtures_dir.to_str().unwrap(), "[FIXTURES]"); + } + ctx + }}; } /// Snapshot test macro that runs a command and compares output using insta.