From b158f57b28046c044312b050412fd7dcdb542f2b Mon Sep 17 00:00:00 2001 From: George Phillips Date: Wed, 8 Apr 2026 20:49:45 +1200 Subject: [PATCH] Add --update (-u) flag to auto-accept snapshot changes Adds a new CLI flag matching the convention used by Jest, Vitest, and pytest snapshot tooling. When passed, changed snapshots are written to disk automatically without interactive review, and the test run reports them as passing. This makes toolproof usable in headless CI and AI runner environments where no TTY is available for interactive approval. --- toolproof/src/main.rs | 16 +++++++- toolproof/src/options.rs | 14 +++++++ .../test_suite/base/snapshot.toolproof.yml | 2 +- .../base/snapshot_update.toolproof.yml | 39 +++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 toolproof/test_suite/base/snapshot_update.toolproof.yml diff --git a/toolproof/src/main.rs b/toolproof/src/main.rs index 7acd8c4..1bdd178 100644 --- a/toolproof/src/main.rs +++ b/toolproof/src/main.rs @@ -558,6 +558,20 @@ async fn main_inner() -> Result<(), ()> { ); println!("{}", msg.green()); Ok(success) + } else if universe.ctx.params.update { + if let Err(e) = std::fs::write(&file.file_path, &output_doc) { + eprintln!("Unable to write updated snapshot to disk.\n{e}"); + return Err(HoldingError::TestFailure); + } + let msg = format!( + "{}{}{} {}", + "✓ ".green(), + dur.green().dimmed(), + &file.name.green(), + "(snapshot updated)".cyan() + ); + println!("{}", msg); + Ok(ToolproofTestSuccess::Passed { attempts: 0 }) } else { println!( "{}", @@ -577,7 +591,7 @@ async fn main_inner() -> Result<(), ()> { ); println!( "\n{}", - "Run in interactive mode (-i) to accept new snapshots\n" + "Run in interactive mode (-i) or with --update (-u) to accept new snapshots\n" .bright_red() .bold() ); diff --git a/toolproof/src/options.rs b/toolproof/src/options.rs index f7da561..46aea9d 100644 --- a/toolproof/src/options.rs +++ b/toolproof/src/options.rs @@ -105,6 +105,12 @@ fn get_cli_matches() -> ArgMatches { ) .action(clap::ArgAction::SetTrue), ) + .arg( + arg!( + -u --update ... "Automatically accept all snapshot changes" + ) + .action(clap::ArgAction::SetTrue), + ) .arg( arg!( -s --skiphooks ... "Skip running any hooks (e.g. before_all)" @@ -203,6 +209,10 @@ pub struct ToolproofParams { /// Run all tests when in interactive mode pub all: bool, + /// Automatically accept all snapshot changes + #[setting(env = "TOOLPROOF_UPDATE")] + pub update: bool, + /// Run a specific test #[setting(env = "TOOLPROOF_RUN_NAME")] pub run_name: Option, @@ -305,6 +315,10 @@ impl ToolproofParams { self.all = true; } + if cli_matches.get_flag("update") { + self.update = true; + } + if cli_matches.get_flag("skiphooks") { self.skip_hooks = true; } diff --git a/toolproof/test_suite/base/snapshot.toolproof.yml b/toolproof/test_suite/base/snapshot.toolproof.yml index dff02a6..435be0e 100644 --- a/toolproof/test_suite/base/snapshot.toolproof.yml +++ b/toolproof/test_suite/base/snapshot.toolproof.yml @@ -56,7 +56,7 @@ steps: ╎ ╎--- END SNAPSHOT CHANGE --- ╎ - ╎Run in interactive mode (-i) to accept new snapshots + ╎Run in interactive mode (-i) or with --update (-u) to accept new snapshots ╎ ╎ ╎Finished running tests diff --git a/toolproof/test_suite/base/snapshot_update.toolproof.yml b/toolproof/test_suite/base/snapshot_update.toolproof.yml new file mode 100644 index 0000000..617c561 --- /dev/null +++ b/toolproof/test_suite/base/snapshot_update.toolproof.yml @@ -0,0 +1,39 @@ +name: Snapshots can be auto-updated with --update flag + +steps: + - step: I have a "my_test.toolproof.yml" file with the content {yaml} + yaml: |- + name: Inner snapshot test with wrong content + + steps: + - I run 'echo "Aenean eu leo quam"' + - snapshot: stdout + snapshot_content: |- + ╎bad + - I run "%toolproof_path% --porcelain -u" + - snapshot: stdout + snapshot_content: |- + ╎ + ╎Running tests + ╎ + ╎✓ Inner snapshot test with wrong content (snapshot updated) + ╎ + ╎Finished running tests + ╎ + ╎Total passing tests: 1 + ╎Passed after retry: 0 + ╎Failing tests: 0 + ╎Skipped tests: 0 + ╎ + ╎All tests passed + - step: I have a "expected_updated.toolproof.yml" file with the content {yaml} + yaml: |- + name: Inner snapshot test with wrong content + + steps: + - I run 'echo "Aenean eu leo quam"' + - snapshot: stdout + snapshot_content: |- + ╎Aenean eu leo quam + - I run "diff my_test.toolproof.yml expected_updated.toolproof.yml" + - stderr should be empty