Skip to content

Commit 30f728b

Browse files
authored
feat: custom "snapshotEnvironment" option (#5449)
1 parent 2f91322 commit 30f728b

File tree

22 files changed

+195
-21
lines changed

22 files changed

+195
-21
lines changed

docs/config/index.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,3 +2200,31 @@ The `location` property has `column` and `line` values that correspond to the `t
22002200
::: tip
22012201
This option has no effect if you do not use custom code that relies on this.
22022202
:::
2203+
2204+
### snapshotEnvironment <Version>1.6.0</Version> {#snapshotEnvironment}
2205+
2206+
- **Type:** `string`
2207+
2208+
Path to a custom snapshot environment implementation. This is useful if you are running your tests in an environment that doesn't support Node.js APIs. This option doesn't have any effect on a browser runner.
2209+
2210+
This object should have the shape of `SnapshotEnvironment` and is used to resolve and read/write snapshot files:
2211+
2212+
```ts
2213+
export interface SnapshotEnvironment {
2214+
getVersion: () => string
2215+
getHeader: () => string
2216+
resolvePath: (filepath: string) => Promise<string>
2217+
resolveRawPath: (testPath: string, rawPath: string) => Promise<string>
2218+
saveSnapshotFile: (filepath: string, snapshot: string) => Promise<void>
2219+
readSnapshotFile: (filepath: string) => Promise<string | null>
2220+
removeSnapshotFile: (filepath: string) => Promise<void>
2221+
}
2222+
```
2223+
2224+
You can extend default `VitestSnapshotEnvironment` from `vitest/snapshot` entry point if you need to overwrite only a part of the API.
2225+
2226+
::: warning
2227+
This is a low-level option and should be used only for advanced cases where you don't have access to default Node.js APIs.
2228+
2229+
If you just need to configure snapshots feature, use [`snapshotFormat`](#snapshotformat) or [`resolveSnapshotPath`](#resolvesnapshotpath) options.
2230+
:::

packages/browser/src/client/runner.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { ResolvedConfig } from 'vitest'
33
import type { VitestExecutor } from 'vitest/execute'
44
import { rpc } from './rpc'
55
import { getConfig, importId } from './utils'
6-
import { BrowserSnapshotEnvironment } from './snapshot'
6+
import { VitestBrowserSnapshotEnvironment } from './snapshot'
77

88
interface BrowserRunnerOptions {
99
config: ResolvedConfig
@@ -92,7 +92,10 @@ export async function initiateRunner() {
9292
if (cachedRunner)
9393
return cachedRunner
9494
const config = getConfig()
95-
const [{ VitestTestRunner, NodeBenchmarkRunner }, { takeCoverageInsideWorker, loadDiffConfig, loadSnapshotSerializers }] = await Promise.all([
95+
const [
96+
{ VitestTestRunner, NodeBenchmarkRunner },
97+
{ takeCoverageInsideWorker, loadDiffConfig, loadSnapshotSerializers },
98+
] = await Promise.all([
9699
importId('vitest/runners') as Promise<typeof import('vitest/runners')>,
97100
importId('vitest/browser') as Promise<typeof import('vitest/browser')>,
98101
])
@@ -101,7 +104,7 @@ export async function initiateRunner() {
101104
takeCoverage: () => takeCoverageInsideWorker(config.coverage, { executeId: importId }),
102105
})
103106
if (!config.snapshotOptions.snapshotEnvironment)
104-
config.snapshotOptions.snapshotEnvironment = new BrowserSnapshotEnvironment()
107+
config.snapshotOptions.snapshotEnvironment = new VitestBrowserSnapshotEnvironment()
105108
const runner = new BrowserRunner({
106109
config,
107110
})

packages/browser/src/client/snapshot.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { SnapshotEnvironment } from 'vitest'
2-
import { rpc } from './rpc'
1+
import type { VitestClient } from '@vitest/ws-client'
2+
import type { SnapshotEnvironment } from 'vitest/snapshot'
33

4-
export class BrowserSnapshotEnvironment implements SnapshotEnvironment {
4+
export class VitestBrowserSnapshotEnvironment implements SnapshotEnvironment {
55
getVersion(): string {
66
return '1'
77
}
@@ -30,3 +30,8 @@ export class BrowserSnapshotEnvironment implements SnapshotEnvironment {
3030
return rpc().removeSnapshotFile(filepath)
3131
}
3232
}
33+
34+
function rpc(): VitestClient['rpc'] {
35+
// @ts-expect-error not typed global
36+
return globalThis.__vitest_worker__.rpc
37+
}

packages/vitest/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@
9191
"./reporters": {
9292
"types": "./dist/reporters.d.ts",
9393
"default": "./dist/reporters.js"
94+
},
95+
"./snapshot": {
96+
"types": "./dist/snapshot.d.ts",
97+
"default": "./dist/snapshot.js"
9498
}
9599
},
96100
"main": "./dist/index.js",

packages/vitest/rollup.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const entries = {
4141
'workers/vmForks': 'src/runtime/workers/vmForks.ts',
4242

4343
'workers/runVmTests': 'src/runtime/runVmTests.ts',
44+
45+
'snapshot': 'src/snapshot.ts',
4446
}
4547

4648
const dtsEntries = {
@@ -56,6 +58,7 @@ const dtsEntries = {
5658
execute: 'src/public/execute.ts',
5759
reporters: 'src/public/reporters.ts',
5860
workers: 'src/workers.ts',
61+
snapshot: 'src/snapshot.ts',
5962
}
6063

6164
const external = [

packages/vitest/snapshot.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './dist/snapshot.js'

packages/vitest/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from './integrations/chai'
1717
export * from './integrations/vi'
1818
export * from './integrations/utils'
1919
export { inject } from './integrations/inject'
20+
// TODO: remove in 2.0.0, import from vitest/snapshot directly
2021
export type { SnapshotEnvironment } from '@vitest/snapshot/environment'
2122

2223
export * from './types'
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment'
2-
import type { WorkerRPC } from '../../../types/worker'
3-
4-
export class VitestSnapshotEnvironment extends NodeSnapshotEnvironment {
5-
constructor(private rpc: WorkerRPC) {
6-
super()
7-
}
2+
import { getWorkerState } from '../../../utils'
83

4+
export class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment {
95
getHeader(): string {
106
return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`
117
}
128

139
resolvePath(filepath: string): Promise<string> {
14-
return this.rpc.resolveSnapshotPath(filepath)
10+
const rpc = getWorkerState().rpc
11+
return rpc.resolveSnapshotPath(filepath)
1512
}
1613
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { SnapshotEnvironment } from '@vitest/snapshot/environment'
2+
import type { VitestExecutor } from '../../../runtime/execute'
3+
import type { ResolvedConfig } from '../../../types'
4+
5+
export async function resolveSnapshotEnvironment(
6+
config: ResolvedConfig,
7+
executor: VitestExecutor,
8+
): Promise<SnapshotEnvironment> {
9+
if (!config.snapshotEnvironment) {
10+
const { VitestNodeSnapshotEnvironment } = await import('./node')
11+
return new VitestNodeSnapshotEnvironment()
12+
}
13+
14+
const mod = await executor.executeId(config.snapshotEnvironment)
15+
if (typeof mod.default !== 'object' || !mod.default)
16+
throw new Error('Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`')
17+
return mod.default
18+
}

packages/vitest/src/node/cli/cli-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,4 +637,5 @@ export const cliOptionsConfig: VitestCLIOptions = {
637637
deps: null,
638638
name: null,
639639
includeTaskLocation: null,
640+
snapshotEnvironment: null,
640641
}

0 commit comments

Comments
 (0)