--- title: "Getting Started with snapr" vignette: > %\VignetteIndexEntry{Getting Started with snapr} %\VignetteEngine{quarto::html} %\VignetteEncoding{UTF-8} --- ## Introduction 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](https://testthat.r-lib.org/)'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) ## Installation Install the development version from GitHub: ```r # install.packages("pak") pak::pak("d-morrison/snapr") ``` ## Basic Workflow Snapshot tests live inside `test_that()` blocks, just like any other [testthat](https://testthat.r-lib.org/) expectation. ### Snapshot a data.frame Use `expect_snapshot_data()` when you want a human-readable CSV snapshot: ```r 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. ### Snapshot any R object 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](https://github.com/brodieG/diffobj) to produce human-readable diffs during review: ```r test_that("model structure is stable", { model <- lm(mpg ~ wt, data = mtcars) expect_snapshot_object(model, name = "mpg_model") }) ``` ## Choosing a Writer 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 | ### JSON example ```r 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) }) ``` ### Deparse example ```r test_that("simple list is stable", { expect_snapshot_object(list(x = 1:3), name = "simple", writer = save_deparse) }) ``` ## Handling Platform Differences 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 | ```r 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. ## Reviewing Snapshots When a snapshot test fails, you can interactively review the differences with: ```r 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](https://github.com/d-morrison/diffviewer) fork of [diffviewer](https://github.com/r-lib/diffviewer). This fork wraps [diffobj](https://github.com/brodieG/diffobj) to compare deserialized R objects with arbitrary structures rather than raw bytes: ```r pak::pak("d-morrison/diffviewer") ``` To accept all new snapshots at once (e.g., after an intentional change): ```r testthat::snapshot_accept() ``` ## Summary | 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()` |