diff --git a/NAMESPACE b/NAMESPACE index 91a15d28e..dd0b8bdc5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -166,6 +166,7 @@ export(use_rmarkdown_template) export(use_roxygen_md) export(use_rstudio) export(use_rstudio_preferences) +export(use_snapshot) export(use_spell_check) export(use_standalone) export(use_template) diff --git a/NEWS.md b/NEWS.md index 0b87d4c5c..a6a597210 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ * Removes deprecated `use_tidy_style()` from to-do's from upkeep (@edgararuiz) * `pr_resume()` (without a specific `branch`) and `pr_fetch()` (without a specific `number`) no longer error when a branch name contains curly braces (#2107, @jonthegeek). +* `use_snapshot()` is a new function to open a testthat snapshot file corresponding to a given test/R file (#2156, @jonthegeek). # usethis 3.2.1 diff --git a/R/r.R b/R/r.R index 5b865ee83..c9c04e25c 100644 --- a/R/r.R +++ b/R/r.R @@ -1,13 +1,14 @@ -#' Create or edit R or test files +#' Create or edit R, test, and snapshot files #' -#' This pair of functions makes it easy to create paired R and test files, +#' @description +#' This family of functions makes it easy to create paired R and test files, #' using the convention that the tests for `R/foofy.R` should live -#' in `tests/testthat/test-foofy.R`. You can use them to create new files -#' from scratch by supplying `name`, or if you use RStudio, you can call -#' to create (or navigate to) the companion file based on the currently open -#' file. This also works when a test snapshot file is active, i.e. if you're -#' looking at `tests/testthat/_snaps/foofy.md`, `use_r()` or `use_test()` take -#' you to `R/foofy.R` or `tests/testthat/test-foofy.R`, respectively. +#' in `tests/testthat/test-foofy.R` and the results of any snapshot tests live +#' in `tests/testthat/snaps/foofy.md`. +#' +#' You can use them to create new files from scratch by supplying `name`, or +#' if you use RStudio or Positron, you can call to create (or navigate to) the +#' companion file based on the currently open file. #' #' @section Renaming files in an existing package: #' @@ -41,7 +42,7 @@ #' The [rename_files()] function can also be helpful. #' #' @param name Either a string giving a file name (without directory) or -#' `NULL` to take the name from the currently open file in RStudio. +#' `NULL` to take the name from the currently open file in RStudio/Positron. #' @inheritParams edit_file #' @seealso #' * The [testing](https://r-pkgs.org/testing-basics.html) and @@ -88,6 +89,27 @@ use_test <- function(name = NULL, open = rlang::is_interactive()) { invisible(TRUE) } +#' @rdname use_r +#' @export +use_snapshot <- function( + name = NULL, + open = rlang::is_interactive() +) { + if (!uses_testthat()) { + use_testthat_impl() + } + + snap_name <- compute_name(name, ext = "md") + path <- proj_path("tests", "testthat", "_snaps", snap_name) + + if (!file_exists(path)) { + cli::cli_abort("No snapshot file exists for {.var {snap_name}}.") + } + edit_file(path, open = open) + + invisible(TRUE) +} + #' Create or edit a test helper file #' #' This function creates (or opens) a test helper file, typically @@ -183,7 +205,11 @@ compute_active_name <- function(path, ext, error_call = caller_env()) { path <- proj_path_prep(path_expand_r(path)) dir <- path_dir(proj_rel_path(path)) - if (!dir %in% c("R", "src", "tests/testthat", "tests/testthat/_snaps")) { + if ( + !dir %in% c("R", "src", "tests/testthat", "tests/testthat/_snaps") && + # This makes sure variants are also supported. + !grepl("tests/testthat/_snaps", dir) + ) { cli::cli_abort( "Open file must be code, test, or snapshot.", call = error_call diff --git a/_pkgdown.yml b/_pkgdown.yml index 9e10f6596..72940d117 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -57,6 +57,7 @@ reference: - use_import_from - use_r - use_rmarkdown_template + - use_snapshot - use_spell_check - use_test - use_test_helper diff --git a/man/use_r.Rd b/man/use_r.Rd index 803375f32..ecef03983 100644 --- a/man/use_r.Rd +++ b/man/use_r.Rd @@ -3,27 +3,30 @@ \name{use_r} \alias{use_r} \alias{use_test} -\title{Create or edit R or test files} +\alias{use_snapshot} +\title{Create or edit R, test, and snapshot files} \usage{ use_r(name = NULL, open = rlang::is_interactive()) use_test(name = NULL, open = rlang::is_interactive()) + +use_snapshot(name = NULL, open = rlang::is_interactive()) } \arguments{ \item{name}{Either a string giving a file name (without directory) or -\code{NULL} to take the name from the currently open file in RStudio.} +\code{NULL} to take the name from the currently open file in RStudio/Positron.} \item{open}{Whether to open the file for interactive editing.} } \description{ -This pair of functions makes it easy to create paired R and test files, +This family of functions makes it easy to create paired R and test files, using the convention that the tests for \code{R/foofy.R} should live -in \code{tests/testthat/test-foofy.R}. You can use them to create new files -from scratch by supplying \code{name}, or if you use RStudio, you can call -to create (or navigate to) the companion file based on the currently open -file. This also works when a test snapshot file is active, i.e. if you're -looking at \verb{tests/testthat/_snaps/foofy.md}, \code{use_r()} or \code{use_test()} take -you to \code{R/foofy.R} or \code{tests/testthat/test-foofy.R}, respectively. +in \code{tests/testthat/test-foofy.R} and the results of any snapshot tests live +in \code{tests/testthat/snaps/foofy.md}. + +You can use them to create new files from scratch by supplying \code{name}, or +if you use RStudio or Positron, you can call to create (or navigate to) the +companion file based on the currently open file. } \section{Renaming files in an existing package}{ diff --git a/man/use_rcpp.Rd b/man/use_rcpp.Rd index 2cd79b614..2a482b123 100644 --- a/man/use_rcpp.Rd +++ b/man/use_rcpp.Rd @@ -17,7 +17,7 @@ use_c(name = NULL) } \arguments{ \item{name}{Either a string giving a file name (without directory) or -\code{NULL} to take the name from the currently open file in RStudio.} +\code{NULL} to take the name from the currently open file in RStudio/Positron.} } \description{ Adds infrastructure commonly needed when using compiled code: diff --git a/tests/testthat/_snaps/r.md b/tests/testthat/_snaps/r.md index f202815b0..925a0f9f1 100644 --- a/tests/testthat/_snaps/r.md +++ b/tests/testthat/_snaps/r.md @@ -1,3 +1,11 @@ +# use_snapshot() errors for non-existent snapshot file + + Code + use_snapshot("foo", open = FALSE) + Condition + Error in `use_snapshot()`: + ! No snapshot file exists for `foo.md`. + # use_test_helper() creates a helper file Code diff --git a/tests/testthat/test-r.R b/tests/testthat/test-r.R index 6839f088f..37059b36b 100644 --- a/tests/testthat/test-r.R +++ b/tests/testthat/test-r.R @@ -10,6 +10,24 @@ test_that("use_test() creates a test file", { expect_proj_file("tests", "testthat", "test-foo.R") }) +test_that("use_snapshot() errors for non-existent snapshot file", { + create_local_package() + expect_snapshot( + error = TRUE, + use_snapshot("foo", open = FALSE) + ) +}) + +test_that("use_snapshot() works for existing snapshot file", { + create_local_package() + path <- proj_path("tests", "testthat", "_snaps", "foo.md") + use_directory(path("tests", "testthat", "_snaps")) + write_utf8(path, "## Snapshot for foo") + expect_no_error( + use_snapshot("foo", open = FALSE) + ) +}) + test_that("use_test_helper() creates a helper file", { create_local_package()