insta/lib.rs
1#![warn(clippy::doc_markdown)]
2#![warn(rustdoc::all)]
3
4//! <div align="center">
5//! <img src="https://github.com/mitsuhiko/insta/blob/master/assets/logo.png?raw=true" width="250" height="250">
6//! <p><strong>insta: a snapshot testing library for Rust</strong></p>
7//! </div>
8//!
9//! # What are snapshot tests
10//!
11//! Snapshots tests (also sometimes called approval tests) are tests that
12//! assert values against a reference value (the snapshot). This is similar
13//! to how [`assert_eq!`] lets you compare a value against a reference value but
14//! unlike simple string assertions, snapshot tests let you test against complex
15//! values and come with comprehensive tools to review changes.
16//!
17//! Snapshot tests are particularly useful if your reference values are very
18//! large or change often.
19//!
20//! # What it looks like:
21//!
22//! ```no_run
23//! #[test]
24//! fn test_hello_world() {
25//! insta::assert_debug_snapshot!(vec![1, 2, 3]);
26//! }
27//! ```
28//!
29//! Where are the snapshots stored? Right next to your test in a folder
30//! called `snapshots` as individual [`.snap` files](https://insta.rs/docs/snapshot-files/).
31//!
32//! Got curious?
33//!
34//! * [Read the introduction](https://insta.rs/docs/quickstart/)
35//! * [Read the main documentation](https://insta.rs/docs/) which does not just
36//! cover the API of the crate but also many of the details of how it works.
37//! * There is a screencast that shows the entire workflow: [watch the insta
38//! introduction screencast](https://www.youtube.com/watch?v=rCHrMqE4JOY&feature=youtu.be).
39//!
40//! # Writing Tests
41//!
42//! ```
43//! use insta::assert_debug_snapshot;
44//!
45//! #[test]
46//! fn test_snapshots() {
47//! assert_debug_snapshot!(vec![1, 2, 3]);
48//! }
49//! ```
50//!
51//! The recommended flow is to run the tests once, have them fail and check
52//! if the result is okay.
53//! By default, the new snapshots are stored next
54//! to the old ones with the extra `.new` extension. Once you are satisfied
55//! move the new files over. To simplify this workflow you can use
56//! `cargo insta review` (requires
57//! [`cargo-insta`](https://crates.io/crates/cargo-insta)) which will let you
58//! interactively review them:
59//!
60//! ```text
61//! $ cargo test
62//! $ cargo insta review
63//! ```
64//!
65//! # Use Without `cargo-insta`
66//!
67//! Note that `cargo-insta` is entirely optional. You can also just use insta
68//! directly from `cargo test` and control it via the `INSTA_UPDATE` environment
69//! variable — see [Updating snapshots](#updating-snapshots) for details.
70//!
71//! You can for instance first run the tests and not write any new snapshots, and
72//! if you like them run the tests again and update them:
73//!
74//! ```text
75//! INSTA_UPDATE=no cargo test
76//! INSTA_UPDATE=always cargo test
77//! ```
78//!
79//! # Assertion Macros
80//!
81//! This crate exports multiple macros for snapshot testing:
82//!
83//! - [`assert_snapshot!`] for comparing basic snapshots of
84//! [`Display`](std::fmt::Display) outputs, often strings.
85//! - [`assert_debug_snapshot!`] for comparing [`Debug`] outputs of values.
86//!
87//! The following macros require the use of [`serde::Serialize`]:
88//!
89#![cfg_attr(
90 feature = "csv",
91 doc = "- [`assert_csv_snapshot!`] for comparing CSV serialized output. (requires the `csv` feature)"
92)]
93#![cfg_attr(
94 feature = "toml",
95 doc = "- [`assert_toml_snapshot!`] for comparing TOML serialized output. (requires the `toml` feature)"
96)]
97#![cfg_attr(
98 feature = "yaml",
99 doc = "- [`assert_yaml_snapshot!`] for comparing YAML serialized output. (requires the `yaml` feature)"
100)]
101#![cfg_attr(
102 feature = "ron",
103 doc = "- [`assert_ron_snapshot!`] for comparing RON serialized output. (requires the `ron` feature)"
104)]
105#![cfg_attr(
106 feature = "json",
107 doc = "- [`assert_json_snapshot!`] for comparing JSON serialized output. (requires the `json` feature)"
108)]
109#![cfg_attr(
110 feature = "json",
111 doc = "- [`assert_compact_json_snapshot!`] for comparing JSON serialized output while preferring single-line formatting. (requires the `json` feature)"
112)]
113//!
114//! For macros that work with [`serde`] this crate also permits redacting of
115//! partial values. See [redactions in the
116//! documentation](https://insta.rs/docs/redactions/) for more information.
117//!
118//! # Updating snapshots
119//!
120//! During test runs snapshots will be updated according to the `INSTA_UPDATE`
121//! environment variable. The default is `auto` which will write snapshots for
122//! any failing tests into `.snap.new` files (if no CI is detected) so that
123//! [`cargo-insta`](https://crates.io/crates/cargo-insta) can pick them up for
124//! review. Normally you don't have to change this variable.
125//!
126//! `INSTA_UPDATE` modes:
127//!
128//! - `auto`: the default. `no` for CI environments or `new` otherwise
129//! - `new`: writes snapshots for any failing tests into `.snap.new` files,
130//! pending review
131//! - `always`: writes snapshots for any failing tests into `.snap` files,
132//! bypassing review
133//! - `unseen`: `always` for previously unseen snapshots or `new` for existing
134//! snapshots
135//! - `no`: does not write to snapshot files at all; just runs tests
136//! - `force`: forcibly updates snapshot files, even if assertions pass
137//!
138//! When `new`, `auto` or `unseen` is used, the
139//! [`cargo-insta`](https://crates.io/crates/cargo-insta) command can be used to
140//! review the snapshots conveniently:
141//!
142//! ```text
143//! $ cargo insta review
144//! ```
145//!
146//! "enter" or "a" accepts a new snapshot, "escape" or "r" rejects, "space" or
147//! "s" skips the snapshot for now.
148//!
149//! For more information [read the cargo insta
150//! docs](https://insta.rs/docs/cli/).
151//!
152//! # Inline Snapshots
153//!
154//! Additionally snapshots can also be stored inline. In that case the format
155//! for the snapshot macros is `assert_snapshot!(reference_value, @"snapshot")`.
156//! The leading at sign (`@`) indicates that the following string is the
157//! reference value. On review, `cargo-insta` will update the string with the
158//! new value.
159//!
160//! Example:
161//!
162//! ```no_run
163//! # use insta::assert_snapshot;
164//! assert_snapshot!(2 + 2, @"");
165//! ```
166//!
167//! Like with normal snapshots, an initial test failure will write the proposed
168//! value into a draft file (note that inline snapshots use `.pending-snap`
169//! files rather than `.snap.new` files). Running `cargo insta review` will
170//! review the proposed changes and update the source files on acceptance
171//! automatically.
172//!
173//! # Features
174//!
175//! The following features exist:
176//!
177//! * `csv`: enables CSV support (via [`serde`])
178//! * `json`: enables JSON support (via [`serde`])
179//! * `ron`: enables RON support (via [`serde`])
180//! * `toml`: enables TOML support (via [`serde`])
181//! * `yaml`: enables YAML support (via [`serde`])
182//! * `redactions`: enables support for redactions
183//! * `filters`: enables support for filters
184//! * `glob`: enables support for globbing ([`glob!`])
185//! * `colors`: enables color output (enabled by default)
186//!
187//! For legacy reasons the `json` and `yaml` features are enabled by default in
188//! limited capacity. You will receive a deprecation warning if you are not
189//! opting into them but for now the macros will continue to function.
190//!
191//! Enabling any of the [`serde`] based formats enables the hidden `serde` feature
192//! which gates some [`serde`] specific APIs such as [`Settings::set_info`].
193//!
194//! # Dependencies
195//!
196//! [`insta`] tries to be light in dependencies but this is tricky to accomplish
197//! given what it tries to do.
198//! By default, it currently depends on [`serde`] for
199//! the [`assert_toml_snapshot!`] and [`assert_yaml_snapshot!`] macros. In the
200//! future this default dependencies will be removed. To already benefit from
201//! this optimization you can disable the default features and manually opt into
202//! what you want.
203//!
204//! # Settings
205//!
206//! There are some settings that can be changed on a per-thread (and thus
207//! per-test) basis. For more information see [Settings].
208//!
209//! Additionally, Insta will load a YAML config file with settings that change
210//! the behavior of insta between runs. It's loaded from any of the following
211//! locations: `.config/insta.yaml`, `insta.yaml` and `.insta.yaml` from the
212//! workspace root. The following config options exist:
213//!
214//! ```yaml
215//! behavior:
216//! # also set by INSTA_REQUIRE_FULL_MATCH
217//! require_full_match: true/false
218//! # also set by INSTA_FORCE_PASS
219//! force_pass: true/false
220//! # also set by INSTA_OUTPUT
221//! output: "diff" | "summary" | "minimal" | "none"
222//! # also set by INSTA_UPDATE
223//! update: "auto" | "new" | "always" | "no" | "unseen" | "force"
224//! # also set by INSTA_GLOB_FAIL_FAST
225//! glob_fail_fast: true/false
226//!
227//! # these are used by cargo insta test
228//! test:
229//! # also set by INSTA_TEST_RUNNER
230//! # cargo-nextest binary path can be explicitly set by INSTA_CARGO_NEXTEST_BIN
231//! runner: "auto" | "cargo-test" | "nextest"
232//! # whether to fallback to `cargo-test` if `nextest` is not available,
233//! # also set by INSTA_TEST_RUNNER_FALLBACK, default false
234//! test_runner_fallback: true/false
235//! # automatically assume --review was passed to cargo insta test
236//! auto_review: true/false
237//! # automatically assume --accept-unseen was passed to cargo insta test
238//! auto_accept_unseen: true/false
239//!
240//! # these are used by cargo insta review
241//! review:
242//! # also look for snapshots in ignored folders
243//! include_ignored: true / false
244//! # also look for snapshots in hidden folders
245//! include_hidden: true / false
246//! # show a warning if undiscovered (ignored or hidden) snapshots are found.
247//! # defaults to true but creates a performance hit.
248//! warn_undiscovered: true / false
249//! ```
250//!
251//! # Optional: Faster Runs
252//!
253//! Insta benefits from being compiled in release mode, even as dev dependency.
254//! It will compile slightly slower once, but use less memory, have faster diffs
255//! and just generally be more fun to use. To achieve that, opt [`insta`] and
256//! [`similar`] (the diffing library) into higher optimization in your
257//! `Cargo.toml`:
258//!
259//! ```yaml
260//! [profile.dev.package.insta]
261//! opt-level = 3
262//!
263//! [profile.dev.package.similar]
264//! opt-level = 3
265//! ```
266//!
267//! You can also disable the default features of [`insta`] which will cut down on
268//! the compile time a bit by removing some quality of life features.
269//!
270//! [`insta`]: https://docs.rs/insta
271#![cfg_attr(docsrs, feature(doc_cfg))]
272
273#[macro_use]
274mod macros;
275mod content;
276mod env;
277mod output;
278mod runtime;
279#[cfg(feature = "serde")]
280mod serialization;
281mod settings;
282mod snapshot;
283mod utils;
284
285#[cfg(feature = "redactions")]
286mod redaction;
287
288#[cfg(feature = "filters")]
289mod filters;
290
291#[cfg(feature = "glob")]
292mod glob;
293
294#[cfg(test)]
295mod test;
296
297pub use crate::settings::Settings;
298pub use crate::snapshot::{MetaData, Snapshot, TextSnapshotKind};
299
300/// Exposes some library internals.
301///
302/// You're unlikely to want to work with these objects but they
303/// are exposed for documentation primarily.
304///
305/// This module does not follow the same stability guarantees as the rest of the crate and is not
306/// guaranteed to be compatible between minor versions.
307pub mod internals {
308 pub use crate::content::Content;
309 #[cfg(feature = "filters")]
310 pub use crate::filters::Filters;
311 pub use crate::runtime::AutoName;
312 pub use crate::settings::SettingsBindDropGuard;
313 pub use crate::snapshot::{MetaData, SnapshotContents};
314 #[cfg(feature = "redactions")]
315 pub use crate::{
316 redaction::{ContentPath, Redaction},
317 settings::Redactions,
318 };
319}
320
321// exported for cargo-insta only
322#[doc(hidden)]
323#[cfg(feature = "_cargo_insta_internal")]
324pub mod _cargo_insta_support {
325 pub use crate::{
326 content::Error as ContentError,
327 env::{
328 Error as ToolConfigError, OutputBehavior, SnapshotUpdate, TestRunner, ToolConfig,
329 UnreferencedSnapshots,
330 },
331 output::SnapshotPrinter,
332 snapshot::PendingInlineSnapshot,
333 snapshot::SnapshotContents,
334 snapshot::TextSnapshotContents,
335 utils::get_cargo,
336 utils::is_ci,
337 };
338}
339
340// useful for redactions
341#[cfg(feature = "redactions")]
342pub use crate::redaction::{dynamic_redaction, rounded_redaction, sorted_redaction};
343
344// these are here to make the macros work
345#[doc(hidden)]
346pub mod _macro_support {
347 pub use crate::content::Content;
348 pub use crate::env::{get_cargo_workspace, Workspace};
349 pub use crate::runtime::{
350 assert_snapshot, with_allow_duplicates, AutoName, BinarySnapshotValue, InlineValue,
351 SnapshotValue,
352 };
353 pub use core::{file, line, module_path};
354 pub use std::{any, env, format, option_env, path, vec};
355
356 #[cfg(feature = "serde")]
357 pub use crate::serialization::{serialize_value, SerializationFormat, SnapshotLocation};
358
359 #[cfg(feature = "glob")]
360 pub use crate::glob::glob_exec;
361
362 #[cfg(feature = "redactions")]
363 pub use crate::{
364 redaction::Redaction, redaction::Selector, serialization::serialize_value_redacted,
365 };
366}