snapshot_testing/
lib.rs

1/// Assert that `value` matches the snapshot at `snapshot_path`. If there is a
2/// mismatch the function will panic with a helpful diff that shows what
3/// changed.
4///
5/// If the env var `UPDATE_SNAPSHOTS` is set to `1`, `yes` or `true` then
6/// `value` will be written to `snapshot_file` instead of being asserted to
7/// match.
8///
9/// Set the env var `CLICOLOR_FORCE` to `1` to force colors in diffs in e.g. CI
10/// logs. See <https://github.com/console-rs/console/blob/a51fcead7cda/src/utils.rs#L18>
11/// which is what our dependency `similar-asserts` uses.
12#[track_caller]
13pub fn assert_eq_or_update(value: impl AsRef<str>, snapshot_path: impl AsRef<std::path::Path>) {
14    let value = value.as_ref();
15    let snapshot_path = snapshot_path.as_ref();
16
17    if update_snapshot() {
18        ensure_parent_dir_exists(snapshot_path);
19
20        std::fs::write(snapshot_path, value)
21            .unwrap_or_else(|e| panic!("Error writing {snapshot_path:?}: {e}"));
22    } else {
23        let snapshot = std::fs::read_to_string(snapshot_path)
24            .unwrap_or_else(|e| panic!("Error reading {snapshot_path:?}: {e}"));
25
26        similar_asserts::assert_eq!(
27            value,
28            snapshot,
29            "\n\n{}: Run with env var `UPDATE_SNAPSHOTS=yes` to update snapshots\n",
30            console::style("help").cyan()
31        );
32    }
33}
34
35fn ensure_parent_dir_exists(snapshot_path: &std::path::Path) {
36    if !snapshot_path.exists() {
37        std::fs::create_dir_all(snapshot_path.parent().unwrap())
38            .unwrap_or_else(|e| panic!("Error creating directory for {snapshot_path:?}: {e}"));
39    }
40}
41
42fn update_snapshot() -> bool {
43    std::env::var("UPDATE_SNAPSHOTS")
44        .map(|s| s.to_lowercase())
45        .is_ok_and(|s| s == "1" || s == "yes" || s == "true")
46}