···107107expect.extend({ customMatcher })
108108```
109109110110+::: tip
111111+To build custom **snapshot matchers** (wrappers around `toMatchSnapshot` / `toMatchInlineSnapshot` / `toMatchFileSnapshot`), use the composable functions from `vitest/runtime`. See [Custom Snapshot Matchers](/guide/snapshot#custom-snapshot-matchers).
112112+:::
113113+110114Matcher function has access to `this` context with the following properties:
111115112116## `isNot`
+30
docs/guide/migration.md
···650650651651Otherwise your snapshots will have a lot of escaped `"` characters.
652652653653+### Custom Snapshot Matchers <Badge type="warning">experimental</Badge> <Version>4.1.3</Version>
654654+655655+Jest imports snapshot composables from `jest-snapshot`. In Vitest, import from `vitest/runtime` instead:
656656+657657+```ts
658658+const { toMatchSnapshot } = require('jest-snapshot') // [!code --]
659659+import { toMatchSnapshot } from 'vitest/runtime' // [!code ++]
660660+661661+expect.extend({
662662+ toMatchTrimmedSnapshot(received: string, length: number) {
663663+ return toMatchSnapshot.call(this, received.slice(0, length))
664664+ },
665665+})
666666+```
667667+668668+For inline snapshots, the same applies:
669669+670670+```ts
671671+const { toMatchInlineSnapshot } = require('jest-snapshot') // [!code --]
672672+import { toMatchInlineSnapshot } from 'vitest/runtime' // [!code ++]
673673+674674+expect.extend({
675675+ toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) {
676676+ return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot)
677677+ },
678678+})
679679+```
680680+681681+See [Custom Snapshot Matchers](/guide/snapshot#custom-snapshot-matchers) for the full guide.
682682+653683## Migrating from Mocha + Chai + Sinon {#mocha-chai-sinon}
654684655685Vitest provides excellent support for migrating from Mocha+Chai+Sinon test suites. While Vitest uses a Jest-compatible API by default, it also provides Chai-style assertions for spy/mock testing, making migration easier.
+70
docs/guide/snapshot.md
···200200201201We 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).
202202203203+## 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).
206206+207207+```ts
208208+import { expect, test } from 'vitest'
209209+import { toMatchFileSnapshot, toMatchInlineSnapshot, toMatchSnapshot } from 'vitest/runtime'
210210+211211+expect.extend({
212212+ toMatchTrimmedSnapshot(received: string, length: number) {
213213+ return toMatchSnapshot.call(this, received.slice(0, length))
214214+ },
215215+ toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) {
216216+ return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot)
217217+ },
218218+ async toMatchTrimmedFileSnapshot(received: string, file: string) {
219219+ return toMatchFileSnapshot.call(this, received.slice(0, 10), file)
220220+ },
221221+})
222222+223223+test('file snapshot', () => {
224224+ expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10)
225225+})
226226+227227+test('inline snapshot', () => {
228228+ expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot()
229229+})
230230+231231+test('raw file snapshot', async () => {
232232+ await expect('extra long string oh my gerd').toMatchTrimmedFileSnapshot('./raw-file.txt')
233233+})
234234+```
235235+236236+The composables return `{ pass, message }` so you can further customize the error:
237237+238238+```ts
239239+expect.extend({
240240+ toMatchTrimmedSnapshot(received: string, length: number) {
241241+ const result = toMatchSnapshot.call(this, received.slice(0, length))
242242+ return { ...result, message: () => `Trimmed snapshot failed: ${result.message()}` }
243243+ },
244244+})
245245+```
246246+247247+::: warning
248248+For inline snapshot matchers, the snapshot argument must be the last parameter (or second-to-last when using property matchers). Vitest rewrites the last string argument in the source code, so custom arguments before the snapshot work, but custom arguments after it are not supported.
249249+:::
250250+251251+::: tip
252252+File snapshot matchers must be `async` — `toMatchFileSnapshot` returns a `Promise`. Remember to `await` the result in the matcher and in your test.
253253+:::
254254+255255+For TypeScript, extend the `Assertion` interface:
256256+257257+```ts
258258+import 'vitest'
259259+260260+declare module 'vitest' {
261261+ interface Assertion<T = any> {
262262+ toMatchTrimmedSnapshot: (length: number) => T
263263+ toMatchTrimmedInlineSnapshot: (inlineSnapshot?: string) => T
264264+ toMatchTrimmedFileSnapshot: (file: string) => Promise<T>
265265+ }
266266+}
267267+```
268268+269269+::: tip
270270+See [Extending Matchers](/guide/extending-matchers) for more on `expect.extend` and custom matcher conventions.
271271+:::
272272+203273## Difference from Jest
204274205275Vitest provides an almost compatible Snapshot feature with [Jest's](https://jestjs.io/docs/snapshot-testing) with a few exceptions:
···11111212export { environments as builtinEnvironments } from '../integrations/env/index'
1313export { populateGlobal } from '../integrations/env/utils'
1414+export { toMatchFileSnapshot, toMatchInlineSnapshot, toMatchSnapshot } from '../integrations/snapshot/chai'
1415export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from '../integrations/snapshot/environments/node'
1516export type {
1617 Environment,