diff --git a/docs/config/index.md b/docs/config/index.md
index 7a441d0687f0..0bab567ee59f 100644
--- a/docs/config/index.md
+++ b/docs/config/index.md
@@ -1899,7 +1899,7 @@ A list of paths to snapshot serializer modules for snapshot testing, useful if y
### resolveSnapshotPath
-- **Type**: `(testPath: string, snapExtension: string) => string`
+- **Type**: `(testPath: string, snapExtension: string, context: { config: SerializedConfig }) => string`
- **Default**: stores snapshot files in `__snapshots__` directory
Overrides default snapshot path. For example, to store snapshots next to test files:
diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts
index 6d37821be88e..0147438cddb9 100644
--- a/packages/browser/src/node/rpc.ts
+++ b/packages/browser/src/node/rpc.ts
@@ -1,5 +1,5 @@
import type { ErrorWithDiff } from 'vitest'
-import type { BrowserCommandContext } from 'vitest/node'
+import type { BrowserCommandContext, ResolveSnapshotPathHandlerContext } from 'vitest/node'
import type { WebSocket } from 'ws'
import type { BrowserServer } from './server'
import type { WebSocketBrowserEvents, WebSocketBrowserHandlers } from './types'
@@ -90,7 +90,9 @@ export function setupBrowserRpc(server: BrowserServer) {
return ctx.report('onUserConsoleLog', log)
},
resolveSnapshotPath(testPath) {
- return ctx.snapshot.resolvePath(testPath)
+ return ctx.snapshot.resolvePath(testPath, {
+ config: project.getSerializableConfig(),
+ })
},
resolveSnapshotRawPath(testPath, rawPath) {
return ctx.snapshot.resolveRawPath(testPath, rawPath)
diff --git a/packages/snapshot/src/manager.ts b/packages/snapshot/src/manager.ts
index 5a4caa0029af..11ed69847aab 100644
--- a/packages/snapshot/src/manager.ts
+++ b/packages/snapshot/src/manager.ts
@@ -23,7 +23,7 @@ export class SnapshotManager {
addSnapshotResult(this.summary, result)
}
- resolvePath(testPath: string): string {
+ resolvePath(testPath: string, context?: T): string {
const resolver
= this.options.resolveSnapshotPath || (() => {
return join(
@@ -32,7 +32,7 @@ export class SnapshotManager {
)
})
- const path = resolver(testPath, this.extension)
+ const path = resolver(testPath, this.extension, context)
return path
}
diff --git a/packages/snapshot/src/types/index.ts b/packages/snapshot/src/types/index.ts
index d1bf8af4fac8..b5378e5a8cb6 100644
--- a/packages/snapshot/src/types/index.ts
+++ b/packages/snapshot/src/types/index.ts
@@ -20,7 +20,7 @@ export interface SnapshotStateOptions {
snapshotEnvironment: SnapshotEnvironment
expand?: boolean
snapshotFormat?: PrettyFormatOptions
- resolveSnapshotPath?: (path: string, extension: string) => string
+ resolveSnapshotPath?: (path: string, extension: string, context?: any) => string
}
export interface SnapshotMatchOptions {
diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts
index 9018c2b9a6bd..28b65a4bcd97 100644
--- a/packages/vitest/src/node/pools/rpc.ts
+++ b/packages/vitest/src/node/pools/rpc.ts
@@ -1,5 +1,6 @@
import type { RawSourceMap } from 'vite-node'
import type { RuntimeRPC } from '../../types/rpc'
+import type { ResolveSnapshotPathHandlerContext } from '../types/config'
import type { WorkspaceProject } from '../workspace'
import { mkdir, writeFile } from 'node:fs/promises'
import { join } from 'pathe'
@@ -20,7 +21,9 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti
ctx.snapshot.add(snapshot)
},
resolveSnapshotPath(testPath: string) {
- return ctx.snapshot.resolvePath(testPath)
+ return ctx.snapshot.resolvePath(testPath, {
+ config: project.getSerializableConfig(),
+ })
},
async getSourceMap(id, force) {
if (force) {
diff --git a/packages/vitest/src/node/types/config.ts b/packages/vitest/src/node/types/config.ts
index 1eae8e3c1bb8..fe600405ddc1 100644
--- a/packages/vitest/src/node/types/config.ts
+++ b/packages/vitest/src/node/types/config.ts
@@ -6,6 +6,7 @@ import type { SerializedDiffOptions } from '@vitest/utils/diff'
import type { AliasOptions, ConfigEnv, DepOptimizationConfig, ServerOptions, UserConfig as ViteUserConfig } from 'vite'
import type { ViteNodeServerOptions } from 'vite-node'
import type { ChaiConfig } from '../../integrations/chai/config'
+import type { SerializedConfig } from '../../runtime/config'
import type { EnvironmentOptions } from '../../types/environment'
import type { Arrayable, ErrorWithDiff, ParsedStack, ProvidedContext } from '../../types/general'
import type { HappyDOMOptions } from '../../types/happy-dom-options'
@@ -225,6 +226,14 @@ type ReporterWithOptions =
: [Name, Partial]
: [Name, Record]
+export interface ResolveSnapshotPathHandlerContext { config: SerializedConfig }
+
+export type ResolveSnapshotPathHandler = (
+ testPath: string,
+ snapExtension: string,
+ context: ResolveSnapshotPathHandlerContext
+) => string
+
export interface InlineConfig {
/**
* Name of the project. Will be used to display in the reporter.
@@ -574,7 +583,7 @@ export interface InlineConfig {
/**
* Resolve custom snapshot path
*/
- resolveSnapshotPath?: (path: string, extension: string) => string
+ resolveSnapshotPath?: ResolveSnapshotPathHandler
/**
* Path to a custom snapshot environment module that has a default export of `SnapshotEnvironment` object.
diff --git a/packages/vitest/src/public/node.ts b/packages/vitest/src/public/node.ts
index e46a3911134e..c8ba9ef7679f 100644
--- a/packages/vitest/src/public/node.ts
+++ b/packages/vitest/src/public/node.ts
@@ -79,6 +79,8 @@ export type {
ProjectConfig,
ResolvedConfig,
ResolvedProjectConfig,
+ ResolveSnapshotPathHandler,
+ ResolveSnapshotPathHandlerContext,
RuntimeConfig,
SequenceHooks,
SequenceSetupFiles,
diff --git a/test/config/fixtures/snapshot-path-context/__snapshots__/project1/basic.test.ts.snap b/test/config/fixtures/snapshot-path-context/__snapshots__/project1/basic.test.ts.snap
new file mode 100644
index 000000000000..ec0254df2305
--- /dev/null
+++ b/test/config/fixtures/snapshot-path-context/__snapshots__/project1/basic.test.ts.snap
@@ -0,0 +1,3 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`basic 1`] = `"hello"`;
diff --git a/test/config/fixtures/snapshot-path-context/__snapshots__/project2/basic.test.ts.snap b/test/config/fixtures/snapshot-path-context/__snapshots__/project2/basic.test.ts.snap
new file mode 100644
index 000000000000..ec0254df2305
--- /dev/null
+++ b/test/config/fixtures/snapshot-path-context/__snapshots__/project2/basic.test.ts.snap
@@ -0,0 +1,3 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`basic 1`] = `"hello"`;
diff --git a/test/config/fixtures/snapshot-path-context/basic.test.ts b/test/config/fixtures/snapshot-path-context/basic.test.ts
new file mode 100644
index 000000000000..4cb90a2abcc7
--- /dev/null
+++ b/test/config/fixtures/snapshot-path-context/basic.test.ts
@@ -0,0 +1,5 @@
+import { test, expect } from 'vitest'
+
+test('basic', () => {
+ expect('hello').toMatchSnapshot()
+})
diff --git a/test/config/fixtures/snapshot-path-context/vitest.config.ts b/test/config/fixtures/snapshot-path-context/vitest.config.ts
new file mode 100644
index 000000000000..a03d2b41cc56
--- /dev/null
+++ b/test/config/fixtures/snapshot-path-context/vitest.config.ts
@@ -0,0 +1,15 @@
+import { join, dirname, basename } from 'node:path';
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ resolveSnapshotPath(path, extension, context) {
+ return join(
+ dirname(path),
+ '__snapshots__',
+ context.config.name ?? 'na',
+ basename(path) + extension
+ );
+ },
+ },
+});
diff --git a/test/config/fixtures/snapshot-path-context/vitest.workspace.ts b/test/config/fixtures/snapshot-path-context/vitest.workspace.ts
new file mode 100644
index 000000000000..30764821b1e0
--- /dev/null
+++ b/test/config/fixtures/snapshot-path-context/vitest.workspace.ts
@@ -0,0 +1,18 @@
+import { defineWorkspace } from 'vitest/config'
+
+export default defineWorkspace([
+ {
+ extends: './vitest.config.ts',
+ test: {
+ name: 'project1',
+ root: import.meta.dirname,
+ }
+ },
+ {
+ extends: './vitest.config.ts',
+ test: {
+ name: 'project2',
+ root: import.meta.dirname,
+ }
+ }
+])
diff --git a/test/config/test/snapshot.test.ts b/test/config/test/snapshot.test.ts
new file mode 100644
index 000000000000..9e890cc40062
--- /dev/null
+++ b/test/config/test/snapshot.test.ts
@@ -0,0 +1,19 @@
+import { expect, test } from 'vitest'
+import { runVitest } from '../../test-utils'
+
+test('resolveSnapshotPath context', async () => {
+ const { stderr, ctx } = await runVitest({
+ root: './fixtures/snapshot-path-context',
+ })
+ expect(stderr).toBe('')
+ expect(
+ Object.fromEntries(
+ ctx!.state.getFiles().map(f => [`${f.projectName}|${f.name}`, f.result?.state]),
+ ),
+ ).toMatchInlineSnapshot(`
+ {
+ "project1|basic.test.ts": "pass",
+ "project2|basic.test.ts": "pass",
+ }
+ `)
+})