Snapshot testing captures the output of a function or computation and saves it to a file. On subsequent test runs, the output is compared to the saved snapshot. If the output changes, the test fails — alerting you to unexpected behaviour.
snapr builds on top of testthat’s expect_snapshot_file() to provide convenient helpers for common R objects:
expect_snapshot_data() — for data.frames (stores as CSV for human-readable diffs)expect_snapshot_object() — for any R object (stores as RDS, JSON, or plain text depending on the writer you choose)Install the development version from GitHub:
# install.packages("pak")
pak::pak("d-morrison/snapr")Snapshot tests live inside test_that() blocks, just like any other testthat expectation.
Use expect_snapshot_data() when you want a human-readable CSV snapshot:
library(snapr)
test_that("iris subset is stable", {
expect_snapshot_data(iris[1:5, ], name = "iris_head")
})The first time you run this test, snapr creates tests/testthat/_snaps/iris_head.csv. On subsequent runs the data.frame is compared against that file and the test fails if anything has changed.
Use expect_snapshot_object() for objects that cannot be easily represented as a CSV. The default writer (save_rds()) stores the object as an .rds file and uses diffobj to produce human-readable diffs during review:
test_that("model structure is stable", {
model <- lm(mpg ~ wt, data = mtcars)
expect_snapshot_object(model, name = "mpg_model")
})The writer argument of expect_snapshot_object() controls the file format. snapr ships four built-in writers:
| Writer | Format | Best for |
|---|---|---|
save_rds() |
.rds (binary) |
Any R object; rich diffs via diffobj |
save_json() |
.json (text) |
Lists and data that map cleanly to JSON |
save_csv() |
.csv (text) |
data.frames (also used by expect_snapshot_data()) |
save_deparse() |
.txt (text) |
Simple objects; always human-readable |
test_that("config list is stable", {
config <- list(name = "my_app", version = "1.0.0", debug = TRUE)
expect_snapshot_object(config, name = "config", writer = save_json)
})test_that("simple list is stable", {
expect_snapshot_object(list(x = 1:3), name = "simple", writer = save_deparse)
})Some R objects (particularly RDS files and results from numerical algorithms) can differ across operating systems or R versions. snapr provides helper functions to create variant strings that are appended to snapshot names, keeping snapshots separate per platform:
| Function | Variant string | Use when… |
|---|---|---|
system_os() |
"linux", "darwin", "windows" |
Output differs by OS only |
darwin_variant() |
"darwin" / NULL |
Only macOS differs; Linux & Windows share one snapshot |
platform_variant() |
"linux-4.4" etc. |
Output differs by both OS and R version |
test_that("RDS snapshot is platform-safe", {
result <- list(x = rnorm(3))
expect_snapshot_object(
result,
name = "result",
variant = platform_variant()
)
})Text-based formats (JSON, CSV, deparse) typically produce identical output across platforms and do not require a variant.
When a snapshot test fails, you can interactively review the differences with:
testthat::snapshot_review()This opens a Shiny app that displays the old and new snapshots side-by-side, letting you accept or reject each change.
For richer, visual diffs when reviewing RDS snapshots, install the d-morrison/diffviewer fork of diffviewer. This fork wraps diffobj to compare deserialized R objects with arbitrary structures rather than raw bytes:
pak::pak("d-morrison/diffviewer")To accept all new snapshots at once (e.g., after an intentional change):
testthat::snapshot_accept()| Task | Function |
|---|---|
| Snapshot a data.frame | expect_snapshot_data(x, name) |
| Snapshot any object (RDS) | expect_snapshot_object(x, name) |
| Snapshot as JSON | expect_snapshot_object(x, name, writer = save_json) |
| Snapshot as CSV | expect_snapshot_object(x, name, writer = save_csv) |
| Snapshot as plain text | expect_snapshot_object(x, name, writer = save_deparse) |
| OS-specific variant | variant = system_os() |
| macOS-only variant | variant = darwin_variant() |
| OS + R-version variant | variant = platform_variant() |
| Review failing snapshots | testthat::snapshot_review() |
| Accept new snapshots | testthat::snapshot_accept() |