Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ S3method(print,comparison)
S3method(print,expectation)
S3method(print,mismatch_character)
S3method(print,mismatch_numeric)
S3method(print,testthat_hint)
S3method(print,testthat_results)
S3method(snapshot_replay,character)
S3method(snapshot_replay,condition)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# testthat (development version)

* `expect_snapshot_file()` now clearly errors if the `path` doesnt exist (#2191).
* `expect_snapshot_file()` now considers `.json` to be a text file (#1593).
* `expect_snapshot_file()` now shows differences for text files (#1593).
* The failure messages for all `expect_` functions have been rewritten to first state what was expected and then what was actually received (#2142).
Expand Down
9 changes: 5 additions & 4 deletions R/local.R
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,15 @@ local_test_directory <- function(path, package = NULL, .env = parent.frame()) {
# Set edition before changing working directory in case path is relative
local_edition(find_edition(path, package), .env = .env)

withr::local_dir(
path,
.local_envir = .env
)
# Capture current working directory so we can use for relative paths
wd <- getwd()

withr::local_dir(path, .local_envir = .env)
withr::local_envvar(
R_TESTS = "",
TESTTHAT = "true",
TESTTHAT_PKG = package,
TESTTHAT_WD = wd,
.local_envir = .env
)
}
Expand Down
34 changes: 6 additions & 28 deletions R/snapshot-file.R
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ expect_snapshot_file <- function(
lab <- quo_label(enquo(path))

check_string(path)
if (!file.exists(path)) {
cli::cli_abort("{.path {path}} doesn't exist.")
}
check_string(name)
check_bool(cran)
check_variant(variant)
Expand Down Expand Up @@ -157,15 +160,10 @@ expect_snapshot_file <- function(
}

file <- snapshotter$file
if (in_check_reporter()) {
hint <- ""
} else {
hint <- snapshot_review_hint(file, name, is_text = is_text)
}

if (!equal) {
if (is_text) {
base <- paste0(c(snapshotter$snap_dir, file, variant), collapse = "/")
base <- paste0(c(snapshotter$snap_dir, variant, file), collapse = "/")
old_path <- paste0(c(base, name), collapse = "/")
new_path <- paste0(c(base, new_name(name)), collapse = "/")

Expand All @@ -181,6 +179,8 @@ expect_snapshot_file <- function(
comp <- NULL
}

hint <- snapshot_hint(file, name, show_accept = is_text)

msg <- c(
sprintf("Snapshot of %s has changed.", lab),
comp,
Expand All @@ -207,28 +207,6 @@ announce_snapshot_file <- function(path, name = basename(path)) {
}
}

snapshot_review_hint <- function(
test,
name,
is_text = FALSE,
reset_output = TRUE
) {
if (reset_output) {
local_reporter_output()
}

c(
if (is_text) {
cli::format_inline(
"* Run {.run testthat::snapshot_accept('{test}/{name}')} to accept the change."
)
},
cli::format_inline(
"* Run {.run testthat::snapshot_review('{test}/{name}')} to review the change."
)
)
}

snapshot_file_equal <- function(
snap_dir, # _snaps/
snap_test, # test file name
Expand Down
78 changes: 55 additions & 23 deletions R/snapshot.R
Original file line number Diff line number Diff line change
Expand Up @@ -367,18 +367,12 @@ expect_snapshot_helper <- function(
} else {
variant_lab <- ""
}
if (in_check_reporter()) {
hint <- ""
} else {
hint <- snapshot_accept_hint(variant, snapshotter$file)
}

if (length(comp) != 0) {
msg <- sprintf(
"Snapshot of %s has changed%s:\n%s\n\n%s",
lab,
variant_lab,
paste0(comp, collapse = "\n\n"),
hint <- snapshot_hint(NULL, snapshotter$file)
msg <- c(
sprintf("Snapshot of %s has changed%s:", lab, variant_lab),
comp,
hint
)
return(snapshot_fail(msg, trace_env = trace_env))
Expand All @@ -387,28 +381,66 @@ expect_snapshot_helper <- function(
pass(NULL)
}

snapshot_accept_hint <- function(variant, file, reset_output = TRUE) {
snapshot_hint <- function(
file,
name,
show_accept = TRUE,
reset_output = TRUE
) {
if (in_check_reporter()) {
return("")
}

if (reset_output) {
local_reporter_output()
}

if (is.null(variant) || variant == "_default") {
name <- file
id <- c(file, name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: The hint has changed from "Review the test file snapshots" to "Review this specific snapshot only", which causes work (delete the file name or many copy/paste's) to review more than one snapshot in a single test file. While the new code is accurate, it makes reviewing more time consuming.

I'd advocate for still returning the variant name for review.

Expected:

  • testthat::snapshot_review("mytest/", "inst/apps/001-hello/tests/testthat")
    Not:
  • testthat::snapshot_review("mytest/002.png", "inst/apps/001-hello/tests/testthat")
Suggested change
id <- c(file, name)
id <- file

Or would it be possible to have the final comments suggest to review the test file's snaps.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooooooh, I did wonder about that, but I thought that was the existing behaviour too. I removed the variant because it didn't work, but I think that's because it doesn't work when both file and variant are supplied.

(There's something about the code paths here that I find extremely confusing.)

full_name <- paste0(id, collapse = "/")

args <- c(full_name, snapshot_hint_path())
args <- encodeString(args, quote = '"')
args <- paste0(args, collapse = ", ")

accept_link <- cli::format_inline("{.run testthat::snapshot_accept({args})}")
review_link <- cli::format_inline("{.run testthat::snapshot_review({args})}")

out <- c(
if (show_accept) sprintf("* Run %s to accept the change.", accept_link),
sprintf("* Run %s to review the change.", review_link)
)
structure(out, class = "testthat_hint")
}

# Include path argument if we're in a different working directory
snapshot_hint_path <- function() {
wd <- Sys.getenv("TESTTHAT_WD", unset = "")
if (wd == "") {
return()
}

test_path <- file.path(wd, "tests/testthat")
if (test_path == getwd()) {
return()
}

old <- normalizePath(wd)
new <- normalizePath(getwd())

if (startsWith(new, old)) {
substr(new, nchar(old) + 2, nchar(new))
} else {
name <- file.path(variant, file)
new
}
}

paste0(
cli::format_inline(
"* Run {.run testthat::snapshot_accept('{name}')} to accept the change."
),
"\n",
cli::format_inline(
"* Run {.run testthat::snapshot_review('{name}')} to review the change."
)
)
#' @export
print.testthat_hint <- function(x, ...) {
cat(paste0(x, "\n", collapse = ""))
invisible(x)
}


snapshot_not_available <- function(message) {
local_reporter_output()

Expand Down
25 changes: 11 additions & 14 deletions tests/testthat/_snaps/snapshot-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,30 @@
# generates informative hint

Code
base::writeLines(snapshot_review_hint("lala", "foo.R", reset_output = FALSE))
snapshot_hint("lala", "foo.R", reset_output = FALSE)
Output
* Run `testthat::snapshot_review('lala/foo.R')` to review the change.

---

Code
base::writeLines(snapshot_review_hint("lala", "foo.R", is_text = TRUE,
reset_output = FALSE))
Output
* Run `testthat::snapshot_accept('lala/foo.R')` to accept the change.
* Run `testthat::snapshot_review('lala/foo.R')` to review the change.
* Run `testthat::snapshot_accept("lala/foo.R")` to accept the change.
* Run `testthat::snapshot_review("lala/foo.R")` to review the change.

# expect_snapshot_file validates its inputs

Code
expect_snapshot_file(123, "test.txt")
expect_snapshot_file(123)
Condition
Error in `expect_snapshot_file()`:
! `path` must be a single string, not the number 123.
Code
expect_snapshot_file("test.txt", 123)
expect_snapshot_file("doesnt-exist.txt")
Condition
Error in `expect_snapshot_file()`:
! 'doesnt-exist.txt' doesn't exist.
Code
expect_snapshot_file(path, 123)
Condition
Error in `expect_snapshot_file()`:
! `name` must be a single string, not the number 123.
Code
expect_snapshot_file("test.txt", "test.txt", cran = "yes")
expect_snapshot_file(path, "test.txt", cran = "yes")
Condition
Error in `expect_snapshot_file()`:
! `cran` must be `TRUE` or `FALSE`, not the string "yes".
Expand Down
11 changes: 3 additions & 8 deletions tests/testthat/_snaps/snapshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,10 @@
# hint is informative

Code
cat(snapshot_accept_hint("_default", "bar.R", reset_output = FALSE))
snapshot_hint(NULL, "bar.R", reset_output = FALSE)
Output
* Run `testthat::snapshot_accept('bar.R')` to accept the change.
* Run `testthat::snapshot_review('bar.R')` to review the change.
Code
cat(snapshot_accept_hint("foo", "bar.R", reset_output = FALSE))
Output
* Run `testthat::snapshot_accept('foo/bar.R')` to accept the change.
* Run `testthat::snapshot_review('foo/bar.R')` to review the change.
* Run `testthat::snapshot_accept("bar.R")` to accept the change.
* Run `testthat::snapshot_review("bar.R")` to review the change.

# expect_snapshot validates its inputs

Expand Down
25 changes: 10 additions & 15 deletions tests/testthat/test-snapshot-file.R
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,19 @@ test_that("split_path handles edge cases", {
})

test_that("generates informative hint", {
expect_snapshot(base::writeLines(snapshot_review_hint(
"lala",
"foo.R",
reset_output = FALSE
)))

expect_snapshot(base::writeLines(snapshot_review_hint(
"lala",
"foo.R",
is_text = TRUE,
reset_output = FALSE
)))
local_mocked_bindings(in_check_reporter = function() FALSE)
withr::local_envvar(GITHUB_ACTIONS = "false", TESTTHAT_WD = NA)

expect_snapshot(snapshot_hint("lala", "foo.R", reset_output = FALSE))
})

test_that("expect_snapshot_file validates its inputs", {
path <- withr::local_tempfile(lines = "x")

expect_snapshot(error = TRUE, {
expect_snapshot_file(123, "test.txt")
expect_snapshot_file("test.txt", 123)
expect_snapshot_file("test.txt", "test.txt", cran = "yes")
expect_snapshot_file(123)
expect_snapshot_file("doesnt-exist.txt")
expect_snapshot_file(path, 123)
expect_snapshot_file(path, "test.txt", cran = "yes")
})
})
22 changes: 17 additions & 5 deletions tests/testthat/test-snapshot.R
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,24 @@ test_that("errors and warnings are folded", {
# })

test_that("hint is informative", {
withr::local_envvar("GITHUB_ACTIONS" = "false")
local_mocked_bindings(in_check_reporter = function() FALSE)
withr::local_envvar(GITHUB_ACTIONS = "false", TESTTHAT_WD = NA)

expect_snapshot({
cat(snapshot_accept_hint("_default", "bar.R", reset_output = FALSE))
cat(snapshot_accept_hint("foo", "bar.R", reset_output = FALSE))
})
expect_snapshot(snapshot_hint(NULL, "bar.R", reset_output = FALSE))
})

test_that("hint includes path when WD is different", {
local_mocked_bindings(in_check_reporter = function() FALSE)
withr::local_envvar(TESTTHAT_WD = "..")

hint <- snapshot_hint(NULL, "bar.R", reset_output = FALSE)
# Can't use snapshot here because its hint will get the wrong path
expect_match(
hint,
'snapshot_accept("bar.R", "testthat")',
fixed = TRUE,
all = FALSE
)
})

test_that("expect_snapshot requires a non-empty test label", {
Expand Down
Loading