Skip to content

Commit d562712

Browse files
hi-ogawacodex
andauthored
docs: document pretty-format and its usage across Vitest + add unit tests (#10052)
Co-authored-by: Codex <noreply@openai.com>
1 parent 0c7617e commit d562712

9 files changed

Lines changed: 1051 additions & 12 deletions

File tree

.github/workflows/issue-labeled.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ permissions:
1111
issues: write
1212
pull-requests: write
1313

14-
1514
jobs:
1615
reply-labeled:
1716
runs-on: ubuntu-latest

docs/api/browser/context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ utils.configurePrettyDOM({
292292
- **`maxLength`** - Maximum length of the output string (default: `7000`)
293293
- **`filterNode`** - A CSS selector string or function to filter out nodes from the output. When a string is provided, elements matching the selector will be excluded. When a function is provided, it should return `false` to exclude a node.
294294
- **`highlight`** - Enable syntax highlighting (default: `true`)
295-
- And other options from [`pretty-format`](https://npmx.dev/package/@vitest/pretty-format)
295+
- And other options from [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format)
296296
297297
#### Filtering with CSS Selectors <Version>4.1.0</Version> {#filtering-with-css-selectors}
298298

docs/config/diff.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ outline: deep
1010

1111
`DiffOptions` object or a path to a module which exports `DiffOptions`. Useful if you want to customize diff display.
1212

13+
Vitest diff rendering uses [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format) under the hood and a part of `DiffOptions` is forwarded to the pretty-format configuration, while the rest affects diff rendering itself.
14+
1315
For example, as a config object:
1416

1517
```ts

docs/config/snapshotformat.md

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,29 @@ outline: deep
55

66
# snapshotFormat <CRoot />
77

8-
- **Type:** `PrettyFormatOptions`
8+
- **Type:** `Omit<PrettyFormatOptions, 'plugins' | 'compareKeys'> & { compareKeys?: null | undefined }`
99

10-
Format options for snapshot testing. These options are passed down to our fork of [`pretty-format`](https://npmx.dev/package/pretty-format). In addition to the `pretty-format` options we support `printShadowRoot: boolean`.
10+
Format options for snapshot testing. These options configure the snapshot-specific formatting layer built on top of [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format).
11+
12+
For the full option surface of `PrettyFormatOptions`, see [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format). This page focuses on the Vitest snapshot-specific defaults and constraints.
13+
14+
Vitest snapshots already apply these defaults before your `snapshotFormat` overrides:
15+
16+
- `printBasicPrototype: false`
17+
- `escapeString: false`
18+
- `escapeRegex: true`
19+
- `printFunctionName: false`
20+
21+
Vitest also supports formatter options such as `printShadowRoot` and `maxOutputLength` in `snapshotFormat`.
22+
23+
`printShadowRoot` controls whether shadow-root contents are included in DOM snapshots.
24+
25+
`maxOutputLength` is an approximate per-depth output budget, not a hard cap on the final rendered string.
26+
27+
By default, snapshot keys are sorted using the formatter's default behavior. Set `compareKeys` to `null` to disable key sorting. Custom compare functions are not supported in `snapshotFormat`.
1128

1229
::: tip
13-
Beware that `plugins` field on this object will be ignored.
30+
Beware that `plugins` on this object will be ignored.
1431

15-
If you need to extend snapshot serializer via pretty-format plugins, please, use [`expect.addSnapshotSerializer`](/api/expect#expect-addsnapshotserializer) API or [snapshotSerializers](/config/snapshotserializers) option.
32+
If you need to extend snapshot serialization via pretty-format plugins, use [`expect.addSnapshotSerializer`](/api/expect#expect-addsnapshotserializer) or [`snapshotSerializers`](/config/snapshotserializers) instead.
1633
:::

docs/guide/snapshot.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ exports['toUpperCase 1'] = '"FOOBAR"'
3333

3434
The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. On subsequent test runs, Vitest will compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code that should be fixed, or the implementation has changed and the snapshot needs to be updated.
3535

36+
Vitest stores a serialized representation of the received value. Snapshot rendering is powered by [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format). [`snapshotFormat`](/config/snapshotformat) allows configuring general snapshot formatting behavior in Vitest. For further customization, you can implement your own [custom serializers](#custom-serializer) or [custom snapshot matchers](#custom-snapshot-matchers).
37+
3638
::: warning
3739
When using Snapshots with async concurrent tests, `expect` from the local [Test Context](/guide/test-context) must be used to ensure the right test is detected.
3840
:::
@@ -198,8 +200,6 @@ Pretty foo: Object {
198200
}
199201
```
200202

201-
We are using Jest's `pretty-format` for serializing snapshots. You can read more about it here: [pretty-format](https://github.com/facebook/jest/blob/main/packages/pretty-format/README.md#serialize).
202-
203203
## Custom Snapshot Matchers <Badge type="warning">experimental</Badge> <Version>4.1.3</Version> {#custom-snapshot-matchers}
204204

205205
You can build custom snapshot matchers using the composable functions exported from `vitest/runtime`. These let you transform values before snapshotting while preserving full snapshot lifecycle support (creation, update, inline rewriting).
@@ -285,7 +285,7 @@ This does not really affect the functionality but might affect your commit diff
285285

286286
#### 2. `printBasicPrototype` is default to `false`
287287

288-
Both Jest and Vitest's snapshots are powered by [`pretty-format`](https://github.com/facebook/jest/blob/main/packages/pretty-format). In Vitest we set `printBasicPrototype` default to `false` to provide a cleaner snapshot output, while in Jest <29.0.0 it's `true` by default.
288+
Both Jest and Vitest snapshots are powered by `pretty-format`, but Vitest applies its own snapshot defaults on top of [`@vitest/pretty-format`](https://npmx.dev/package/@vitest/pretty-format). In particular, Vitest sets `printBasicPrototype` to `false` to provide a cleaner snapshot output, while in Jest <29.0.0 it is `true` by default.
289289

290290
```ts
291291
import { expect, test } from 'vitest'

packages/pretty-format/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
[![NPM version](https://img.shields.io/npm/v/@vitest/pretty-format?color=a1b858&label=)](https://npmx.dev/package/@vitest/pretty-format)
44

5-
Jest's `pretty-format` implementation that only supports ESM.
5+
Vitest's fork of Jest's [`pretty-format`](https://npmx.dev/package/pretty-format).
66

7-
[GitHub](https://github.com/vitest-dev/vitest/tree/main/packages/pretty-format) | [Documentation](https://vitest.dev/)
7+
[GitHub](https://github.com/vitest-dev/vitest/tree/main/packages/pretty-format) | [Documentation](https://github.com/vitest-dev/vitest/blob/main/packages/pretty-format/USAGE.md)

packages/pretty-format/USAGE.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# @vitest/pretty-format
2+
3+
Vitest's fork of Jest's [`pretty-format`](https://npmx.dev/package/pretty-format), published as an ESM-only package.
4+
5+
This package powers several formatting paths in Vitest:
6+
7+
- snapshot serialization
8+
- assertion diff rendering
9+
- matcher and error messages
10+
- browser `prettyDOM` output
11+
12+
## Usage
13+
14+
```ts
15+
import { format } from '@vitest/pretty-format'
16+
17+
const value = {
18+
user: 'Ada',
19+
items: [1, 2, 3],
20+
}
21+
22+
console.log(format(value))
23+
/*
24+
-- output --
25+
Object {
26+
"items": Array [
27+
1,
28+
2,
29+
3,
30+
],
31+
"user": "Ada",
32+
}
33+
*/
34+
```
35+
36+
## Options
37+
38+
| key | type | default | notes |
39+
| :-------------------- | :--------------- | :---------- | :------------------------------------------------------------------- |
40+
| `callToJSON` | `boolean` | `true` | Call `toJSON` if present |
41+
| `compareKeys` | `function\|null` | `undefined` | Compare function for sorting object keys. Use `null` to skip sorting |
42+
| `escapeRegex` | `boolean` | `false` | Escape special characters in regular expressions |
43+
| `escapeString` | `boolean` | `true` | Escape special characters in strings |
44+
| `highlight` | `boolean` | `false` | Highlight syntax with terminal colors |
45+
| `indent` | `number` | `2` | Spaces per indentation level |
46+
| `maxDepth` | `number` | `Infinity` | Maximum depth to print |
47+
| `maxOutputLength` | `number` | `1_000_000` | Approximate per-depth output budget |
48+
| `maxWidth` | `number` | `Infinity` | Maximum number of items to print in collections |
49+
| `min` | `boolean` | `false` | Minimize added whitespace |
50+
| `plugins` | `array` | `[]` | Plugins to serialize application-specific data types |
51+
| `printBasicPrototype` | `boolean` | `true` | Print `Object` and `Array` prefixes for plain objects and arrays |
52+
| `printFunctionName` | `boolean` | `true` | Include or omit the function name |
53+
| `printShadowRoot` | `boolean` | `true` | Include shadow-root contents when formatting DOM nodes |
54+
55+
Important:
56+
57+
- `plugins: []` means the package does not auto-enable its built-in plugins by default
58+
- Vitest features opt into their own plugin stacks and option presets
59+
60+
## Built-in Plugins
61+
62+
The package exports these built-in plugins:
63+
64+
- `ReactTestComponent`
65+
- `ReactElement`
66+
- `DOMElement`
67+
- `DOMCollection`
68+
- `Immutable`
69+
- `AsymmetricMatcher`
70+
- `Error`
71+
72+
You can use them directly with `format(..., { plugins })`:
73+
74+
```ts
75+
import { format, plugins } from '@vitest/pretty-format'
76+
77+
console.log(
78+
format(document.body, {
79+
plugins: [plugins.DOMElement, plugins.DOMCollection],
80+
}),
81+
)
82+
```
83+
84+
## Vitest Extensions
85+
86+
Besides the inherited `pretty-format` API surface, Vitest currently adds and documents these notable behaviors:
87+
88+
### `printShadowRoot`
89+
90+
Controls whether DOM serialization includes shadow-root contents.
91+
92+
```ts
93+
format(element, {
94+
printShadowRoot: false,
95+
})
96+
```
97+
98+
### `maxOutputLength`
99+
100+
Approximate per-depth output budget used to prevent pathological expansion of large recursive structures.
101+
102+
This is a heuristic safety valve, not a hard cap on the final string length.
103+
104+
```ts
105+
format(value, {
106+
maxOutputLength: 100_000,
107+
})
108+
```
109+
110+
## How Vitest Uses It
111+
112+
### Snapshots
113+
114+
Snapshots use `@vitest/pretty-format` with snapshot-specific defaults such as:
115+
116+
- `printBasicPrototype: false`
117+
- `escapeString: false`
118+
- `escapeRegex: true`
119+
- `printFunctionName: false`
120+
121+
Default snapshot plugin stack:
122+
123+
- `ReactTestComponent`
124+
- `ReactElement`
125+
- `DOMElement`
126+
- `DOMCollection`
127+
- `Immutable`
128+
- `AsymmetricMatcher`
129+
- `MockSerializer`
130+
131+
Snapshot formatting is configured through [`test.snapshotFormat`](https://vitest.dev/config/snapshotformat), while serializer registration goes through [`expect.addSnapshotSerializer`](https://vitest.dev/api/expect#expect-addsnapshotserializer) or [`snapshotSerializers`](https://vitest.dev/config/snapshotserializers).
132+
133+
### Diffs
134+
135+
Assertion diffs use a different preset and plugin stack.
136+
137+
Default diff plugins:
138+
139+
- `ReactTestComponent`
140+
- `ReactElement`
141+
- `DOMElement`
142+
- `DOMCollection`
143+
- `Immutable`
144+
- `AsymmetricMatcher`
145+
- `Error`
146+
147+
### Vitest `stringify`
148+
149+
Matcher and error messages commonly go through Vitest's internal [`stringify`](https://github.com/vitest-dev/vitest/blob/59b0e6411be2b4aa5f2b339d02691aa83d5e403f/packages/utils/src/display.ts#L49) utility, which uses:
150+
151+
- `ReactTestComponent`
152+
- `ReactElement`
153+
- `DOMElement`
154+
- `DOMCollection`
155+
- `Immutable`
156+
- `AsymmetricMatcher`
157+
158+
`stringify` also adds wrapper-level behavior on top of `@vitest/pretty-format`:
159+
160+
- `maxLength`: if the formatted output grows too large, `stringify` retries with a smaller `maxDepth` to keep the result bounded
161+
- `filterNode`: swaps the default DOM plugin for a filtered variant so selected nodes are omitted from the output
162+
- fallback on formatter errors: if formatting throws, `stringify` retries with `callToJSON: false`
163+
164+
### Browser `prettyDOM`
165+
166+
Browser `prettyDOM` builds on Vitest's `stringify` path and enables browser-oriented defaults such as:
167+
168+
- `highlight: true`
169+
170+
It can also replace the default DOM plugin with a filtered variant when `filterNode` is configured.

packages/pretty-format/src/types.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,41 @@ export interface Options
3838
}
3939

4040
export interface PrettyFormatOptions {
41+
/**
42+
* Call `toJSON` on objects before formatting them.
43+
* Ignored after the formatter has already called `toJSON` once for a value.
44+
* @default true
45+
*/
4146
callToJSON?: boolean
47+
/**
48+
* Whether to escape special characters in regular expressions.
49+
* @default false
50+
*/
4251
escapeRegex?: boolean
52+
/**
53+
* Whether to escape special characters in strings.
54+
* @default true
55+
*/
4356
escapeString?: boolean
57+
/**
58+
* Whether to highlight syntax using terminal colors.
59+
* @default false
60+
*/
4461
highlight?: boolean
62+
/**
63+
* Number of spaces to use for each level of indentation.
64+
* @default 2
65+
*/
4566
indent?: number
67+
/**
68+
* Maximum depth to recurse into nested values.
69+
* @default Infinity
70+
*/
4671
maxDepth?: number
72+
/**
73+
* Maximum number of items to print in arrays, sets, maps, and similar collections.
74+
* @default Infinity
75+
*/
4776
maxWidth?: number
4877
/**
4978
* Approximate per-depth-level budget for output length.
@@ -53,11 +82,34 @@ export interface PrettyFormatOptions {
5382
* @default 1_000_000
5483
*/
5584
maxOutputLength?: number
85+
/**
86+
* Whether to minimize added whitespace, including indentation and line breaks.
87+
* @default false
88+
*/
5689
min?: boolean
90+
/**
91+
* Whether to print `Object` / `Array` prefixes for plain objects and arrays.
92+
* @default true
93+
*/
5794
printBasicPrototype?: boolean
95+
/**
96+
* Whether to include the function name when formatting functions.
97+
* @default true
98+
*/
5899
printFunctionName?: boolean
100+
/**
101+
* Whether to include shadow-root contents when formatting DOM nodes.
102+
* @default true
103+
*/
59104
printShadowRoot?: boolean
105+
/**
106+
* Compare function used when sorting object keys. Set to `null` to disable sorting.
107+
*/
60108
compareKeys?: CompareKeys
109+
/**
110+
* Plugins used to serialize application-specific data types.
111+
* @default []
112+
*/
61113
plugins?: Plugins
62114
}
63115

0 commit comments

Comments
 (0)