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