diff --git a/guide/extending-matchers.md b/guide/extending-matchers.md index 06300420..f262d369 100644 --- a/guide/extending-matchers.md +++ b/guide/extending-matchers.md @@ -107,6 +107,10 @@ function customMatcher(this: MatcherState, received: unknown, arg1: unknown, arg expect.extend({ customMatcher }) ``` + +::: tip +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). +::: 断言方法可以访问上下文 `this` 对象中的这些属性: diff --git a/guide/migration.md b/guide/migration.md index 1776f724..189f6577 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -640,6 +640,36 @@ export default defineConfig({ ``` 否则快照中会出现大量转义的 `"` 字符。 + +### Custom Snapshot Matchers experimental 4.1.3 + +Jest imports snapshot composables from `jest-snapshot`. In Vitest, import from `vitest/runtime` instead: + +```ts +const { toMatchSnapshot } = require('jest-snapshot') // [!code --] +import { toMatchSnapshot } from 'vitest/runtime' // [!code ++] + +expect.extend({ + toMatchTrimmedSnapshot(received: string, length: number) { + return toMatchSnapshot.call(this, received.slice(0, length)) + }, +}) +``` + +For inline snapshots, the same applies: + +```ts +const { toMatchInlineSnapshot } = require('jest-snapshot') // [!code --] +import { toMatchInlineSnapshot } from 'vitest/runtime' // [!code ++] + +expect.extend({ + toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) { + return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot) + }, +}) +``` + +See [Custom Snapshot Matchers](/guide/snapshot#custom-snapshot-matchers) for the full guide. ## 从 Mocha + Chai + Sinon 迁移 {#mocha-chai-sinon} diff --git a/guide/snapshot.md b/guide/snapshot.md index 78e69b78..49233055 100644 --- a/guide/snapshot.md +++ b/guide/snapshot.md @@ -192,6 +192,76 @@ Pretty foo: Object { ``` 我们使用的是 Jest 的 `pretty-format` 来序列化快照。你可以在这里阅读更多相关内容:[pretty-format](https://github.com/facebook/jest/blob/main/packages/pretty-format/README.md#serialize). + +## Custom Snapshot Matchers experimental 4.1.3 {#custom-snapshot-matchers} + +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). + +```ts +import { expect, test } from 'vitest' +import { toMatchFileSnapshot, toMatchInlineSnapshot, toMatchSnapshot } from 'vitest/runtime' + +expect.extend({ + toMatchTrimmedSnapshot(received: string, length: number) { + return toMatchSnapshot.call(this, received.slice(0, length)) + }, + toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) { + return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot) + }, + async toMatchTrimmedFileSnapshot(received: string, file: string) { + return toMatchFileSnapshot.call(this, received.slice(0, 10), file) + }, +}) + +test('file snapshot', () => { + expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10) +}) + +test('inline snapshot', () => { + expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot() +}) + +test('raw file snapshot', async () => { + await expect('extra long string oh my gerd').toMatchTrimmedFileSnapshot('./raw-file.txt') +}) +``` + +The composables return `{ pass, message }` so you can further customize the error: + +```ts +expect.extend({ + toMatchTrimmedSnapshot(received: string, length: number) { + const result = toMatchSnapshot.call(this, received.slice(0, length)) + return { ...result, message: () => `Trimmed snapshot failed: ${result.message()}` } + }, +}) +``` + +::: warning +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. +::: + +::: tip +File snapshot matchers must be `async` — `toMatchFileSnapshot` returns a `Promise`. Remember to `await` the result in the matcher and in your test. +::: + +For TypeScript, extend the `Assertion` interface: + +```ts +import 'vitest' + +declare module 'vitest' { + interface Assertion { + toMatchTrimmedSnapshot: (length: number) => T + toMatchTrimmedInlineSnapshot: (inlineSnapshot?: string) => T + toMatchTrimmedFileSnapshot: (file: string) => Promise + } +} +``` + +::: tip +See [Extending Matchers](/guide/extending-matchers) for more on `expect.extend` and custom matcher conventions. +::: ## 与 Jest 的区别 {#difference-from-jest} diff --git a/guide/test-context.md b/guide/test-context.md index 9bf6759b..1a954a3d 100644 --- a/guide/test-context.md +++ b/guide/test-context.md @@ -894,7 +894,7 @@ This applies to all suite-level hooks: `beforeAll`, `afterAll`, and `aroundAll`. ::: ::: tip -Suite-level hooks can only access [**file-scoped** and **worker-scoped** fixtures](#fixture-scopes). Test-scoped fixtures are not available in these hooks because they run outside the context of individual tests. If you try to access a test-scoped fixture in a suite-level hook, Vitest will throw an error. +Suite-level hooks can only access [**file-scoped** and **worker-scoped** fixtures](#fixture-scopes), including `auto` fixtures. Test-scoped fixtures are not available in these hooks because they run outside the context of individual tests. If you try to access a test-scoped fixture in a suite-level hook, Vitest will throw an error. ```ts const test = baseTest