Skip to content

Commit 71a33cd

Browse files
authored
Display diffs when snapshotting text files (#2205)
I haven't yet figured out how to test snapshots with snapshots, so you can run this to test interactively ```R test_that("expect_snapshot_file() show differences for text files", { path1 <- withr::local_tempfile(lines = sample(letters[1:10])) expect_snapshot_file(path1, "text-diff.txt") }) ``` Fixes #1593
1 parent 5d0d48d commit 71a33cd

File tree

5 files changed

+68
-15
lines changed

5 files changed

+68
-15
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# testthat (development version)
22

3+
* `expect_snapshot_file()` now considers `.json` to be a text file (#1593).
4+
* `expect_snapshot_file()` now shows differences for text files (#1593).
35
* The failure messages for all `expect_` functions have been rewritten to first state what was expected and then what was actually received (#2142).
46
* `test_file(desc = ...)` no longer loses snapshot results (#2066).
57
* In `R CMD check`, snapshots now only advise on how to resolve failures once (#2207).

R/expect-that.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ fail <- function(
4848

4949
snapshot_fail <- function(message, trace_env = caller_env()) {
5050
trace <- capture_trace(trace_env)
51+
message <- paste(message, collapse = "\n")
5152
expectation("failure", message, trace = trace, snapshot = TRUE)
5253
}
5354

R/snapshot-file.R

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ expect_snapshot_file <- function(
106106
transform = NULL,
107107
variant = NULL
108108
) {
109+
lab <- quo_label(enquo(path))
110+
109111
check_string(path)
110112
check_string(name)
111113
check_bool(cran)
@@ -125,6 +127,7 @@ expect_snapshot_file <- function(
125127
return(invisible())
126128
}
127129

130+
is_text <- is_text_file(name)
128131
if (!is_missing(binary)) {
129132
lifecycle::deprecate_soft(
130133
"3.0.3",
@@ -134,8 +137,6 @@ expect_snapshot_file <- function(
134137
compare <- if (binary) compare_file_binary else compare_file_text
135138
}
136139
if (is.null(compare)) {
137-
ext <- tools::file_ext(name)
138-
is_text <- ext %in% c("r", "R", "txt", "md", "Rmd")
139140
compare <- if (is_text) compare_file_text else compare_file_binary
140141
}
141142

@@ -145,7 +146,6 @@ expect_snapshot_file <- function(
145146
brio::write_lines(lines, path)
146147
}
147148

148-
lab <- quo_label(enquo(path))
149149
equal <- snapshotter$take_file_snapshot(
150150
name,
151151
path,
@@ -156,24 +156,46 @@ expect_snapshot_file <- function(
156156
return(equal)
157157
}
158158

159+
file <- snapshotter$file
159160
if (in_check_reporter()) {
160161
hint <- ""
161162
} else {
162-
hint <- snapshot_review_hint(snapshotter$file, name)
163+
hint <- snapshot_review_hint(file, name, is_text = is_text)
163164
}
164165

165166
if (!equal) {
166-
msg <- sprintf(
167-
"Snapshot of %s to '%s' has changed\n%s",
168-
lab,
169-
paste0(snapshotter$file, "/", name),
167+
if (is_text) {
168+
base <- paste0(c(snapshotter$snap_dir, file, variant), collapse = "/")
169+
old_path <- paste0(c(base, name), collapse = "/")
170+
new_path <- paste0(c(base, new_name(name)), collapse = "/")
171+
172+
comp <- waldo_compare(
173+
x = brio::read_lines(old_path),
174+
x_arg = "old",
175+
y = brio::read_lines(new_path),
176+
y_arg = "new",
177+
quote_strings = FALSE
178+
)
179+
comp <- c("Differences:", comp)
180+
} else {
181+
comp <- NULL
182+
}
183+
184+
msg <- c(
185+
sprintf("Snapshot of %s has changed.", lab),
186+
comp,
170187
hint
171188
)
172189
return(snapshot_fail(msg))
173190
}
174191
pass(NULL)
175192
}
176193

194+
is_text_file <- function(path) {
195+
ext <- tools::file_ext(path)
196+
ext %in% c("r", "R", "txt", "md", "Rmd", "qmd", "json")
197+
}
198+
177199
#' @rdname expect_snapshot_file
178200
#' @export
179201
announce_snapshot_file <- function(path, name = basename(path)) {
@@ -185,13 +207,25 @@ announce_snapshot_file <- function(path, name = basename(path)) {
185207
}
186208
}
187209

188-
snapshot_review_hint <- function(test, name, reset_output = TRUE) {
210+
snapshot_review_hint <- function(
211+
test,
212+
name,
213+
is_text = FALSE,
214+
reset_output = TRUE
215+
) {
189216
if (reset_output) {
190217
local_reporter_output()
191218
}
192219

193-
cli::format_inline(
194-
"* Run {.run testthat::snapshot_review('{test}/{name}')} to review the change."
220+
c(
221+
if (is_text) {
222+
cli::format_inline(
223+
"* Run {.run testthat::snapshot_accept('{test}/{name}')} to accept the change."
224+
)
225+
},
226+
cli::format_inline(
227+
"* Run {.run testthat::snapshot_review('{test}/{name}')} to review the change."
228+
)
195229
)
196230
}
197231

tests/testthat/_snaps/snapshot-file.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,18 @@
2525
# generates informative hint
2626

2727
Code
28-
cat(snapshot_review_hint("lala", "foo.r", reset_output = FALSE))
28+
base::writeLines(snapshot_review_hint("lala", "foo.R", reset_output = FALSE))
2929
Output
30-
* Run `testthat::snapshot_review('lala/foo.r')` to review the change.
30+
* Run `testthat::snapshot_review('lala/foo.R')` to review the change.
31+
32+
---
33+
34+
Code
35+
base::writeLines(snapshot_review_hint("lala", "foo.R", is_text = TRUE,
36+
reset_output = FALSE))
37+
Output
38+
* Run `testthat::snapshot_accept('lala/foo.R')` to accept the change.
39+
* Run `testthat::snapshot_review('lala/foo.R')` to review the change.
3140

3241
# expect_snapshot_file validates its inputs
3342

tests/testthat/test-snapshot-file.R

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,16 @@ test_that("split_path handles edge cases", {
163163
})
164164

165165
test_that("generates informative hint", {
166-
expect_snapshot(cat(snapshot_review_hint(
166+
expect_snapshot(base::writeLines(snapshot_review_hint(
167167
"lala",
168-
"foo.r",
168+
"foo.R",
169+
reset_output = FALSE
170+
)))
171+
172+
expect_snapshot(base::writeLines(snapshot_review_hint(
173+
"lala",
174+
"foo.R",
175+
is_text = TRUE,
169176
reset_output = FALSE
170177
)))
171178
})

0 commit comments

Comments
 (0)