Skip to content

Commit fd8ec9f

Browse files
authored
fix --unreferenced=auto clearing new pending snapshots (#762)
closes #751
1 parent f781958 commit fd8ec9f

File tree

6 files changed

+384
-242
lines changed

6 files changed

+384
-242
lines changed

CHANGELOG.md

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33
All notable changes to insta and cargo-insta are documented here.
44

5-
## Unreleased
5+
## 1.43.0
66

7+
- Add uppercase keyboard shortcuts for bulk operations in `cargo insta review`:
8+
`A` to accept all, `R` to reject all, and `S` to skip all remaining snapshots.
9+
#745
10+
- `--unreferenced=auto` (or other relevant values) no longer cleans up pending
11+
snapshots. A bug where `cargo insta test --unreferenced=auto` would
12+
incorrectly pass on new pending snapshots has been fixed.
713
- Support specifying `cargo-nextest` bin with `INSTA_CARGO_NEXTEST_BIN`. #721 (Louis Fruleux)
814
- Allow setting `INSTA_WORKSPACE_ROOT` at compile time. This is useful for reproducible binaries
915
so they don't contain references to `CARGO_MANIFEST_DIR`. #726 (Pascal Bach)
1016
- Qualify all references in macros to avoid name clashes. #729 (Austin Schey)
1117
- Remove `linked-hash-map` and `pin-project` dependencies. #742, #741, #738
12-
- Add uppercase keyboard shortcuts for bulk operations in `cargo insta review`:
13-
`A` to accept all, `R` to reject all, and `S` to skip all remaining snapshots.
14-
#745
1518
- `cargo insta review` fails with a helpful error message when run in a non-TTY environment.
1619

1720
## 1.42.2

cargo-insta/src/cli.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ fn handle_unreferenced_snapshots(
877877
UnreferencedSnapshots::Ignore => return Ok(()),
878878
};
879879

880-
let files = fs::read_to_string(snapshot_ref_path)
880+
let snapshot_files_from_test = fs::read_to_string(snapshot_ref_path)
881881
.map(|s| {
882882
s.lines()
883883
.filter_map(|line| fs::canonicalize(line).ok())
@@ -910,19 +910,14 @@ fn handle_unreferenced_snapshots(
910910
.filter_map(|e| e.path().canonicalize().ok())
911911
// The path isn't in the list which the tests wrote to, so it's
912912
// unreferenced.
913-
//
914-
// TODO: note that this will include _all_ `.pending-snap` files,
915-
// regardless of whether or not a test was run, since we don't record
916-
// those in the snapshot references file. We can make that change, but
917-
// also we'd like to unify file & inline snapshot handling; if we do
918-
// that it'll fix this smaller issue too.
913+
.filter(|path| !snapshot_files_from_test.contains(path))
914+
// we don't want to delete the new or pending-snap files, partly because
915+
// we use their presence to determine if a test created a snapshot and
916+
// so `insta test` should fail
919917
.filter(|path| {
920-
// We also check for the pending path
921-
let pending_path = path.with_file_name(format!(
922-
"{}.new",
923-
path.file_name().unwrap().to_string_lossy()
924-
));
925-
!files.contains(path) && !files.contains(&pending_path)
918+
path.extension()
919+
.map(|x| x != "new" && x != "pending-snap")
920+
.unwrap_or(true)
926921
});
927922

928923
for path in unreferenced_snapshots {

cargo-insta/tests/functional/binary.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,10 @@ fn test_binary_snapshot() {
177177
)
178178
.create_project();
179179

180-
assert!(!&test_project
180+
// create the snapshot
181+
assert!(&test_project
181182
.insta_cmd()
182-
.args(["test"])
183+
.args(["test", "--accept", "--", "--nocapture"])
183184
.output()
184185
.unwrap()
185186
.status

cargo-insta/tests/functional/delete_pending.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn test_snapshot_file() {
2424
)
2525
.create_project();
2626

27+
// initially it'll fail
2728
assert!(!&test_project
2829
.insta_cmd()
2930
.args(["test", "--", "--nocapture"])
@@ -32,18 +33,26 @@ fn test_snapshot_file() {
3233
.status
3334
.success());
3435

36+
// then it'll pass with `--accept`
37+
assert!(&test_project
38+
.insta_cmd()
39+
.args(["test", "--accept", "--", "--nocapture"])
40+
.output()
41+
.unwrap()
42+
.status
43+
.success());
44+
3545
assert_snapshot!(test_project.file_tree_diff(), @r"
3646
--- Original file tree
3747
+++ Updated file tree
38-
@@ -1,4 +1,8 @@
48+
@@ -1,4 +1,7 @@
3949
4050
+ Cargo.lock
4151
Cargo.toml
4252
src
43-
+ src/.lib.rs.pending-snap
4453
src/lib.rs
4554
+ src/snapshots
46-
+ src/snapshots/delete_unreferenced__snapshot_file.snap.new
55+
+ src/snapshots/delete_unreferenced__snapshot_file.snap
4756
");
4857

4958
// Now remove the tests; the pending snapshots should be deleted when

cargo-insta/tests/functional/main.rs

+1-220
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ use tempfile::TempDir;
7171
mod binary;
7272
mod delete_pending;
7373
mod inline;
74+
mod unreferenced;
7475
mod workspace;
7576

7677
/// Wraps a formatting function to be used as a `Stdio`
@@ -617,92 +618,6 @@ fn foo_always_missing() {
617618
// Check for the name clash error message
618619
assert!(error_output.contains("Insta snapshot name clash detected between 'foo_always_missing' and 'test_foo_always_missing' in 'snapshot_name_clash_test'. Rename one function."));
619620
}
620-
621-
#[test]
622-
fn test_unreferenced_delete() {
623-
let test_project = TestFiles::new()
624-
.add_cargo_toml("test_unreferenced_delete")
625-
.add_file(
626-
"src/lib.rs",
627-
r#"
628-
#[test]
629-
fn test_snapshot() {
630-
insta::assert_snapshot!("Hello, world!");
631-
}
632-
"#
633-
.to_string(),
634-
)
635-
.create_project();
636-
637-
// Run tests to create snapshots
638-
let output = test_project
639-
.insta_cmd()
640-
.args(["test", "--accept"])
641-
.output()
642-
.unwrap();
643-
644-
assert!(&output.status.success());
645-
646-
// Manually add an unreferenced snapshot
647-
let unreferenced_snapshot_path = test_project
648-
.workspace_dir
649-
.join("src/snapshots/test_unreferenced_delete__unused_snapshot.snap");
650-
std::fs::create_dir_all(unreferenced_snapshot_path.parent().unwrap()).unwrap();
651-
std::fs::write(
652-
&unreferenced_snapshot_path,
653-
r#"---
654-
source: src/lib.rs
655-
expression: "Unused snapshot"
656-
---
657-
Unused snapshot
658-
"#,
659-
)
660-
.unwrap();
661-
662-
assert_snapshot!(test_project.file_tree_diff(), @r"
663-
--- Original file tree
664-
+++ Updated file tree
665-
@@ -1,4 +1,8 @@
666-
667-
+ Cargo.lock
668-
Cargo.toml
669-
src
670-
src/lib.rs
671-
+ src/snapshots
672-
+ src/snapshots/test_unreferenced_delete__snapshot.snap
673-
+ src/snapshots/test_unreferenced_delete__unused_snapshot.snap
674-
");
675-
676-
// Run cargo insta test with --unreferenced=delete
677-
let output = test_project
678-
.insta_cmd()
679-
.args([
680-
"test",
681-
"--unreferenced=delete",
682-
"--accept",
683-
"--",
684-
"--nocapture",
685-
])
686-
.output()
687-
.unwrap();
688-
689-
assert!(&output.status.success());
690-
691-
// We should now see the unreferenced snapshot deleted
692-
assert_snapshot!(test_project.file_tree_diff(), @r"
693-
--- Original file tree
694-
+++ Updated file tree
695-
@@ -1,4 +1,7 @@
696-
697-
+ Cargo.lock
698-
Cargo.toml
699-
src
700-
src/lib.rs
701-
+ src/snapshots
702-
+ src/snapshots/test_unreferenced_delete__snapshot.snap
703-
");
704-
}
705-
706621
#[test]
707622
fn test_hidden_snapshots() {
708623
let test_project = TestFiles::new()
@@ -889,137 +804,3 @@ src/
889804
stderr
890805
);
891806
}
892-
893-
#[test]
894-
fn test_unreferenced_config_reject() {
895-
// This test verifies that the `test.unreferenced: reject` setting in insta.yaml
896-
// is respected when no command-line argument is provided.
897-
//
898-
// Specifically, it tests the fix for issue #757, which ensures that:
899-
// 1. Config file settings are properly applied when not overridden by command-line flags
900-
// 2. Error handling for unreferenced snapshots properly updates the success flag
901-
let test_project = TestFiles::new()
902-
.add_cargo_toml("test_unreferenced_config_reject")
903-
.add_file(
904-
"src/lib.rs",
905-
r#"
906-
#[test]
907-
fn test_snapshot() {
908-
insta::assert_snapshot!("Hello, world!");
909-
}
910-
"#
911-
.to_string(),
912-
)
913-
.create_project();
914-
915-
// Run tests to create snapshots first (without the config file)
916-
let output = test_project
917-
.insta_cmd()
918-
.args(["test", "--accept"])
919-
.output()
920-
.unwrap();
921-
922-
assert!(output.status.success());
923-
924-
// Now add the config file after snapshot is created
925-
test_project.update_file(
926-
"insta.yaml",
927-
r#"
928-
test:
929-
unreferenced: reject
930-
"#
931-
.to_string(),
932-
);
933-
934-
// Manually add an unreferenced snapshot
935-
let unreferenced_snapshot_path = test_project
936-
.workspace_dir
937-
.join("src/snapshots/test_unreferenced_config_reject__unused_snapshot.snap");
938-
std::fs::create_dir_all(unreferenced_snapshot_path.parent().unwrap()).unwrap();
939-
std::fs::write(
940-
&unreferenced_snapshot_path,
941-
r#"---
942-
source: src/lib.rs
943-
expression: "Unused snapshot"
944-
---
945-
Unused snapshot
946-
"#,
947-
)
948-
.unwrap();
949-
950-
// Verify files exist
951-
let snapshot_path = test_project
952-
.workspace_dir
953-
.join("src/snapshots/test_unreferenced_config_reject__snapshot.snap");
954-
let unreferenced_path = test_project
955-
.workspace_dir
956-
.join("src/snapshots/test_unreferenced_config_reject__unused_snapshot.snap");
957-
958-
assert!(snapshot_path.exists(), "Normal snapshot file should exist");
959-
assert!(
960-
unreferenced_path.exists(),
961-
"Unreferenced snapshot file should exist"
962-
);
963-
964-
// First verify explicitly passing --unreferenced=reject does fail correctly
965-
let output = test_project
966-
.insta_cmd()
967-
.args(["test", "--unreferenced=reject", "--", "--nocapture"])
968-
.stderr(Stdio::piped())
969-
.output()
970-
.unwrap();
971-
972-
// The test should fail with explicit flag
973-
assert!(
974-
!output.status.success(),
975-
"Command should fail with explicit --unreferenced=reject flag"
976-
);
977-
978-
let stderr = String::from_utf8_lossy(&output.stderr);
979-
assert!(
980-
stderr.contains("encountered unreferenced snapshots"),
981-
"Expected error message about unreferenced snapshots, got: {}",
982-
stderr
983-
);
984-
985-
// Now run without flags - this should also fail due to the config file setting
986-
let output = test_project
987-
.insta_cmd()
988-
.args(["test", "--", "--nocapture"])
989-
.stderr(Stdio::piped())
990-
.output()
991-
.unwrap();
992-
993-
// The command should fail because of the config file setting
994-
assert!(
995-
!output.status.success(),
996-
"Command should fail when config file has test.unreferenced: reject"
997-
);
998-
999-
// Verify the error message mentions unreferenced snapshots
1000-
let stderr = String::from_utf8_lossy(&output.stderr);
1001-
assert!(
1002-
stderr.contains("encountered unreferenced snapshots"),
1003-
"Expected error message about unreferenced snapshots, got: {}",
1004-
stderr
1005-
);
1006-
1007-
// Run with --unreferenced=delete to clean up
1008-
let output = test_project
1009-
.insta_cmd()
1010-
.args(["test", "--unreferenced=delete", "--", "--nocapture"])
1011-
.output()
1012-
.unwrap();
1013-
1014-
assert!(output.status.success());
1015-
1016-
// Verify the unreferenced snapshot was deleted
1017-
assert!(
1018-
snapshot_path.exists(),
1019-
"Normal snapshot file should still exist"
1020-
);
1021-
assert!(
1022-
!unreferenced_path.exists(),
1023-
"Unreferenced snapshot file should have been deleted"
1024-
);
1025-
}

0 commit comments

Comments
 (0)