Skip to content

snapshot

stable

Store, compare, and diff named text snapshots on disk, useful for snapshot testing and tracking output changes over time.

use plugin snapshot::{create_snapshot, update_snapshot, read_snapshot, …}
10 functions Utilities
/ filter jk navigate Esc clear
Functions (10)
  1. create_snapshot Write a snapshot if it does not yet exist
  2. update_snapshot Overwrite a snapshot with new content
  3. read_snapshot Read a snapshot's stored content
  4. delete_snapshot Delete a snapshot file
  5. list_snapshots List all snapshot names in a directory
  6. snapshot_exists Check whether a snapshot file exists
  7. snapshot_count Count snapshot files in a directory
  8. compare_snapshot Compare content against a stored snapshot
  9. diff_lines Compute a line-level diff between two strings
  10. format_diff Format two strings as a unified diff string

Overview

snapshot persists named blocks of text to disk so you can assert that some output stays stable across runs — the core idea behind snapshot testing. Every snapshot is a plain .snap file stored under a .snapshots/ directory inside a base_dir you provide, addressed only by its name; there are no handles or hidden state, just files you read, write, compare, and delete. Use it to lock in golden output (rendered HTML, serialized JSON, generated code) and to detect when that output changes unexpectedly.

The typical loop is: capture some output, create_snapshot it on the first run (which writes the file), then on later runs compare_snapshot the fresh output against the stored copy. When something legitimately changes, update_snapshot overwrites the golden file. The diff_lines and format_diff helpers work on any two strings, so you can render a readable diff whether or not a snapshot is involved.

Common patterns

Create-or-compare: on the first run the snapshot is written, and on every run afterwards you check the new output against it.

use plugin snapshot::{snapshot_exists, create_snapshot, compare_snapshot}

let output = "<h1>Hello</h1>"

if !snapshot_exists("homepage", "./tests") {
  create_snapshot("homepage", output, "./tests")
} else {
  let result = compare_snapshot("homepage", output, "./tests")
  if !result["matches"] {
    print("homepage changed:")
    print(result["diff"])
  }
}

Render a readable diff between expected and actual text, no snapshot needed:

use plugin snapshot::{format_diff}

let expected = "name: ada\nrole: admin"
let actual = "name: ada\nrole: user"
print(format_diff(expected, actual))

Update a golden file after an intentional change, then confirm it now matches:

use plugin snapshot::{update_snapshot, compare_snapshot}

let fixed = '{"status":"ok","version":2}'
update_snapshot("api_response", fixed, "./tests")

let result = compare_snapshot("api_response", fixed, "./tests")
print("matches after update: {result["matches"]}")

Write a snapshot if it does not yet exist

Writes content to a snapshot file named name inside base_dir/.snapshots/ — but only if the file does not already exist. Returns a table with path, exists (was a file already there?), and matches (does the existing file match content?).

use plugin snapshot::{create_snapshot}

let result = create_snapshot("homepage", "<h1>Hello</h1>", "./tests")
if result["exists"] && !result["matches"] {
  print("snapshot mismatch!")
}

Because the write only happens on first run, the same call doubles as a "record on first run, verify after" check — inspect exists to tell the two cases apart:

use plugin snapshot::{create_snapshot}

let r = create_snapshot("report", "totals: 42", "./tests")
if !r["exists"] {
  print("recorded new snapshot at {r["path"]}")
} else if r["matches"] {
  print("output unchanged")
}

Overwrite a snapshot with new content

Unconditionally overwrites the snapshot named name with content. Use this to update golden files after an intentional change.

use plugin snapshot::{update_snapshot}

update_snapshot("api_response", '{"status":"ok"}', "./tests")

Read a snapshot's stored content

Returns the stored content of the snapshot named name as a string, or nil if no snapshot exists yet.

use plugin snapshot::{read_snapshot}

let stored = read_snapshot("homepage", "./tests")
if stored != nil {
  print("stored length: {stored.len()}")
}

Delete a snapshot file

Deletes the snapshot file for name. Does nothing if it does not exist.

use plugin snapshot::{delete_snapshot}

delete_snapshot("old_output", "./tests")

List all snapshot names in a directory

Returns a sorted table of snapshot names (without the .snap extension) found in base_dir/.snapshots/.

use plugin snapshot::{list_snapshots}

let names = list_snapshots("./tests")
for _, name in names {
  print(name)
}

Combine it with read_snapshot to dump every stored snapshot's content:

use plugin snapshot::{list_snapshots, read_snapshot}

for _, name in list_snapshots("./tests") {
  print("--- {name} ---")
  print(read_snapshot(name, "./tests"))
}

Check whether a snapshot file exists

Returns true if a snapshot file for name exists in base_dir/.snapshots/.

use plugin snapshot::{snapshot_exists}

if snapshot_exists("homepage", "./tests") {
  print("snapshot found")
}

Count snapshot files in a directory

Returns the number of .snap files in base_dir/.snapshots/.

use plugin snapshot::{snapshot_count}

let count = snapshot_count("./tests")
print("{count} snapshots on disk")

Compare content against a stored snapshot

Compares content against the stored snapshot named name. Returns a table with exists (bool), matches (bool), and diff (a string showing differences, or nil if they match).

use plugin snapshot::{create_snapshot, compare_snapshot}

let output = "<h1>Hello</h1>"
create_snapshot("page", output, "./tests")

let result = compare_snapshot("page", "<h1>World</h1>", "./tests")
if !result["matches"] {
  print(result["diff"])
}

When the snapshot was never recorded, exists is false and diff is nil — a useful signal to fall back to create_snapshot:

use plugin snapshot::{compare_snapshot, create_snapshot}

let out = "build #1"
let cmp = compare_snapshot("build", out, "./tests")
if !cmp["exists"] {
  create_snapshot("build", out, "./tests")
  print("first run: recorded baseline")
}

Compute a line-level diff between two strings

Computes a line-level diff between expected and actual. Returns a table of change entries, each with line_num, type ("changed", "removed", or "added"), and text.

use plugin snapshot::{diff_lines}

let changes = diff_lines("line1\nline2\nline3", "line1\nchanged\nline3")
for _, change in changes {
  print("L{change["line_num"]} ({change["type"]}): {change["text"]}")
}

Because it returns structured entries, you can count just the kinds of change you care about — for example, how many lines were added:

use plugin snapshot::{diff_lines}

let changes = diff_lines("a\nb", "a\nb\nc\nd")
let added = 0
for _, change in changes {
  if change["type"] == "added" {
    added = added + 1
  }
}
print("{added} lines added")

Format two strings as a unified diff string

Formats the diff between expected and actual as a unified diff string with --- expected / +++ actual headers. Lines prefixed with - are removals and + are additions.

use plugin snapshot::{format_diff}

let diff = format_diff("foo\nbar\nbaz", "foo\nQUX\nbaz")
print(diff)
enespt-br