Skip to content

Commit e7e44a3

Browse files
authored
Include test path in snaphot hints (#2191)
If you're not testing the current directory/package. (Also includes a path bug fix and an improved error if the `path` doesn't exist) Fixes #1577
1 parent 6883737 commit e7e44a3

File tree

9 files changed

+103
-97
lines changed

9 files changed

+103
-97
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ S3method(print,comparison)
2424
S3method(print,expectation)
2525
S3method(print,mismatch_character)
2626
S3method(print,mismatch_numeric)
27+
S3method(print,testthat_hint)
2728
S3method(print,testthat_results)
2829
S3method(snapshot_replay,character)
2930
S3method(snapshot_replay,condition)

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+
* The hints generated by `expect_snapshot()` and `expect_snapshot_file()` now include the path to the package, if its not in the current working directory (#1577).
4+
* `expect_snapshot_file()` now clearly errors if the `path` doesnt exist (#2191).
35
* `expect_snapshot_file()` now considers `.json` to be a text file (#1593).
46
* `expect_snapshot_file()` now shows differences for text files (#1593).
57
* The failure messages for all `expect_` functions have been rewritten to first state what was expected and then what was actually received (#2142).

R/local.R

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,15 @@ local_test_directory <- function(path, package = NULL, .env = parent.frame()) {
177177
# Set edition before changing working directory in case path is relative
178178
local_edition(find_edition(path, package), .env = .env)
179179

180-
withr::local_dir(
181-
path,
182-
.local_envir = .env
183-
)
180+
# Capture current working directory so we can use for relative paths
181+
wd <- getwd()
182+
183+
withr::local_dir(path, .local_envir = .env)
184184
withr::local_envvar(
185185
R_TESTS = "",
186186
TESTTHAT = "true",
187187
TESTTHAT_PKG = package,
188+
TESTTHAT_WD = wd,
188189
.local_envir = .env
189190
)
190191
}

R/snapshot-file.R

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ expect_snapshot_file <- function(
114114
lab <- quo_label(enquo(path))
115115

116116
check_string(path)
117+
if (!file.exists(path)) {
118+
cli::cli_abort("{.path {path}} doesn't exist.")
119+
}
117120
check_string(name)
118121
check_bool(cran)
119122
check_variant(variant)
@@ -162,15 +165,10 @@ expect_snapshot_file <- function(
162165
}
163166

164167
file <- snapshotter$file
165-
if (in_check_reporter()) {
166-
hint <- ""
167-
} else {
168-
hint <- snapshot_review_hint(file, name, is_text = is_text)
169-
}
170168

171169
if (!equal) {
172170
if (is_text) {
173-
base <- paste0(c(snapshotter$snap_dir, file, variant), collapse = "/")
171+
base <- paste0(c(snapshotter$snap_dir, variant, file), collapse = "/")
174172
old_path <- paste0(c(base, name), collapse = "/")
175173
new_path <- paste0(c(base, new_name(name)), collapse = "/")
176174

@@ -186,6 +184,8 @@ expect_snapshot_file <- function(
186184
comp <- NULL
187185
}
188186

187+
hint <- snapshot_hint(paste0(file, "/"), show_accept = is_text)
188+
189189
msg <- c(
190190
sprintf("Snapshot of %s has changed.", lab),
191191
comp,
@@ -212,28 +212,6 @@ announce_snapshot_file <- function(path, name = basename(path)) {
212212
}
213213
}
214214

215-
snapshot_review_hint <- function(
216-
test,
217-
name,
218-
is_text = FALSE,
219-
reset_output = TRUE
220-
) {
221-
if (reset_output) {
222-
local_reporter_output()
223-
}
224-
225-
c(
226-
if (is_text) {
227-
cli::format_inline(
228-
"* Run {.run testthat::snapshot_accept('{test}/{name}')} to accept the change."
229-
)
230-
},
231-
cli::format_inline(
232-
"* Run {.run testthat::snapshot_review('{test}/{name}')} to review the change."
233-
)
234-
)
235-
}
236-
237215
snapshot_file_equal <- function(
238216
snap_dir, # _snaps/
239217
snap_test, # test file name

R/snapshot.R

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -372,18 +372,12 @@ expect_snapshot_helper <- function(
372372
} else {
373373
variant_lab <- ""
374374
}
375-
if (in_check_reporter()) {
376-
hint <- ""
377-
} else {
378-
hint <- snapshot_accept_hint(variant, snapshotter$file)
379-
}
380375

381376
if (length(comp) != 0) {
382-
msg <- sprintf(
383-
"Snapshot of %s has changed%s:\n%s\n\n%s",
384-
lab,
385-
variant_lab,
386-
paste0(comp, collapse = "\n\n"),
377+
hint <- snapshot_hint(snapshotter$file)
378+
msg <- c(
379+
sprintf("Snapshot of %s has changed%s:", lab, variant_lab),
380+
comp,
387381
hint
388382
)
389383
return(snapshot_fail(msg, trace_env = trace_env))
@@ -392,28 +386,59 @@ expect_snapshot_helper <- function(
392386
pass(NULL)
393387
}
394388

395-
snapshot_accept_hint <- function(variant, file, reset_output = TRUE) {
389+
snapshot_hint <- function(id, show_accept = TRUE, reset_output = TRUE) {
390+
if (in_check_reporter()) {
391+
return("")
392+
}
393+
396394
if (reset_output) {
397395
local_reporter_output()
398396
}
399397

400-
if (is.null(variant) || variant == "_default") {
401-
name <- file
398+
full_name <- paste0(id, collapse = "/")
399+
args <- c(full_name, snapshot_hint_path())
400+
args <- encodeString(args, quote = '"')
401+
args <- paste0(args, collapse = ", ")
402+
403+
accept_link <- cli::format_inline("{.run testthat::snapshot_accept({args})}")
404+
review_link <- cli::format_inline("{.run testthat::snapshot_review({args})}")
405+
406+
out <- c(
407+
if (show_accept) sprintf("* Run %s to accept the change.", accept_link),
408+
sprintf("* Run %s to review the change.", review_link)
409+
)
410+
structure(out, class = "testthat_hint")
411+
}
412+
413+
# Include path argument if we're in a different working directory
414+
snapshot_hint_path <- function() {
415+
wd <- Sys.getenv("TESTTHAT_WD", unset = "")
416+
if (wd == "") {
417+
return()
418+
}
419+
420+
test_path <- file.path(wd, "tests/testthat")
421+
if (test_path == getwd()) {
422+
return()
423+
}
424+
425+
old <- normalizePath(wd)
426+
new <- normalizePath(getwd())
427+
428+
if (startsWith(new, old)) {
429+
substr(new, nchar(old) + 2, nchar(new))
402430
} else {
403-
name <- file.path(variant, file)
431+
new
404432
}
433+
}
405434

406-
paste0(
407-
cli::format_inline(
408-
"* Run {.run testthat::snapshot_accept('{name}')} to accept the change."
409-
),
410-
"\n",
411-
cli::format_inline(
412-
"* Run {.run testthat::snapshot_review('{name}')} to review the change."
413-
)
414-
)
435+
#' @export
436+
print.testthat_hint <- function(x, ...) {
437+
cat(paste0(x, "\n", collapse = ""))
438+
invisible(x)
415439
}
416440

441+
417442
snapshot_not_available <- function(message) {
418443
local_reporter_output()
419444

tests/testthat/_snaps/snapshot-file.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,30 @@
2525
# generates informative hint
2626

2727
Code
28-
base::writeLines(snapshot_review_hint("lala", "foo.R", reset_output = FALSE))
28+
snapshot_hint("lala", reset_output = FALSE)
2929
Output
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.
30+
* Run `testthat::snapshot_accept("lala")` to accept the change.
31+
* Run `testthat::snapshot_review("lala")` to review the change.
4032

4133
# expect_snapshot_file validates its inputs
4234

4335
Code
44-
expect_snapshot_file(123, "test.txt")
36+
expect_snapshot_file(123)
4537
Condition
4638
Error in `expect_snapshot_file()`:
4739
! `path` must be a single string, not the number 123.
4840
Code
49-
expect_snapshot_file("test.txt", 123)
41+
expect_snapshot_file("doesnt-exist.txt")
42+
Condition
43+
Error in `expect_snapshot_file()`:
44+
! 'doesnt-exist.txt' doesn't exist.
45+
Code
46+
expect_snapshot_file(path, 123)
5047
Condition
5148
Error in `expect_snapshot_file()`:
5249
! `name` must be a single string, not the number 123.
5350
Code
54-
expect_snapshot_file("test.txt", "test.txt", cran = "yes")
51+
expect_snapshot_file(path, "test.txt", cran = "yes")
5552
Condition
5653
Error in `expect_snapshot_file()`:
5754
! `cran` must be `TRUE` or `FALSE`, not the string "yes".

tests/testthat/_snaps/snapshot.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,15 +264,10 @@
264264
# hint is informative
265265

266266
Code
267-
cat(snapshot_accept_hint("_default", "bar.R", reset_output = FALSE))
267+
snapshot_hint("bar.R", reset_output = FALSE)
268268
Output
269-
* Run `testthat::snapshot_accept('bar.R')` to accept the change.
270-
* Run `testthat::snapshot_review('bar.R')` to review the change.
271-
Code
272-
cat(snapshot_accept_hint("foo", "bar.R", reset_output = FALSE))
273-
Output
274-
* Run `testthat::snapshot_accept('foo/bar.R')` to accept the change.
275-
* Run `testthat::snapshot_review('foo/bar.R')` to review the change.
269+
* Run `testthat::snapshot_accept("bar.R")` to accept the change.
270+
* Run `testthat::snapshot_review("bar.R")` to review the change.
276271

277272
# expect_snapshot validates its inputs
278273

tests/testthat/test-snapshot-file.R

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

165165
test_that("generates informative hint", {
166-
expect_snapshot(base::writeLines(snapshot_review_hint(
167-
"lala",
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,
176-
reset_output = FALSE
177-
)))
166+
local_mocked_bindings(in_check_reporter = function() FALSE)
167+
withr::local_envvar(GITHUB_ACTIONS = "false", TESTTHAT_WD = NA)
168+
169+
expect_snapshot(snapshot_hint("lala", reset_output = FALSE))
178170
})
179171

180172
test_that("expect_snapshot_file validates its inputs", {
173+
path <- withr::local_tempfile(lines = "x")
174+
181175
expect_snapshot(error = TRUE, {
182-
expect_snapshot_file(123, "test.txt")
183-
expect_snapshot_file("test.txt", 123)
184-
expect_snapshot_file("test.txt", "test.txt", cran = "yes")
176+
expect_snapshot_file(123)
177+
expect_snapshot_file("doesnt-exist.txt")
178+
expect_snapshot_file(path, 123)
179+
expect_snapshot_file(path, "test.txt", cran = "yes")
185180
})
186181
})

tests/testthat/test-snapshot.R

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,24 @@ test_that("errors and warnings are folded", {
166166
# })
167167

168168
test_that("hint is informative", {
169-
withr::local_envvar("GITHUB_ACTIONS" = "false")
169+
local_mocked_bindings(in_check_reporter = function() FALSE)
170+
withr::local_envvar(GITHUB_ACTIONS = "false", TESTTHAT_WD = NA)
170171

171-
expect_snapshot({
172-
cat(snapshot_accept_hint("_default", "bar.R", reset_output = FALSE))
173-
cat(snapshot_accept_hint("foo", "bar.R", reset_output = FALSE))
174-
})
172+
expect_snapshot(snapshot_hint("bar.R", reset_output = FALSE))
173+
})
174+
175+
test_that("hint includes path when WD is different", {
176+
local_mocked_bindings(in_check_reporter = function() FALSE)
177+
withr::local_envvar(TESTTHAT_WD = "..")
178+
179+
hint <- snapshot_hint("bar.R", reset_output = FALSE)
180+
# Can't use snapshot here because its hint will get the wrong path
181+
expect_match(
182+
hint,
183+
'snapshot_accept("bar.R", "testthat")',
184+
fixed = TRUE,
185+
all = FALSE
186+
)
175187
})
176188

177189
test_that("expect_snapshot requires a non-empty test label", {

0 commit comments

Comments
 (0)