Skip to content

Commit 92ba7fc

Browse files
authored
fix: scope cache key generators to projects (fix #11281) (#11301)
1 parent 38f9885 commit 92ba7fc

4 files changed

Lines changed: 70 additions & 8 deletions

File tree

‎packages/vitest/src/node/cache/fsModuleCache.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class FileSystemModuleCache {
4545
private version = '1.0.0-beta.8'
4646
private fsCacheRoots = new WeakMap<ResolvedConfig, string>()
4747
private fsEnvironmentHashMap = new WeakMap<DevEnvironment, string>()
48-
private fsCacheKeyGenerators = new Set<CacheKeyIdGenerator>()
48+
private fsCacheKeyGenerators = new WeakMap<ResolvedConfig, Set<CacheKeyIdGenerator>>()
4949
private warnedDeprecatedIgnore = new Set<string>()
5050
// this exists only to avoid the perf. cost of reading a file and generating a hash again
5151
// surprisingly, on some machines this has negligible effect
@@ -62,8 +62,13 @@ export class FileSystemModuleCache {
6262
this.metadataFilePath = join(this.rootCache, METADATA_FILE)
6363
}
6464

65-
public defineCacheKeyGenerator(callback: CacheKeyIdGenerator): void {
66-
this.fsCacheKeyGenerators.add(callback)
65+
public defineCacheKeyGenerator(config: ResolvedConfig, callback: CacheKeyIdGenerator): void {
66+
let generators = this.fsCacheKeyGenerators.get(config)
67+
if (!generators) {
68+
generators = new Set()
69+
this.fsCacheKeyGenerators.set(config, generators)
70+
}
71+
generators.add(callback)
6772
}
6873

6974
// A plugin can exclude itself from the cache key via `api.vitest.ignoreFsModuleCache`.
@@ -224,7 +229,7 @@ export class FileSystemModuleCache {
224229

225230
let hashString = ''
226231

227-
for (const generator of this.fsCacheKeyGenerators) {
232+
for (const generator of this.fsCacheKeyGenerators.get(vitestConfig) || []) {
228233
const result = generator({ environment, id, sourceCode: fileContent })
229234
if (typeof result === 'string') {
230235
hashString += result

‎packages/vitest/src/node/core.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,8 @@ export class Vitest {
396396
project,
397397
vitest: this,
398398
injectTestProjects: this.injectTestProject,
399-
defineCacheKeyGenerator: (callback) => this._fsCache.defineCacheKeyGenerator(callback),
399+
defineCacheKeyGenerator: (callback) =>
400+
this._fsCache.defineCacheKeyGenerator(project.config, callback),
400401
/**
401402
* @deprecated Use `defineCacheKeyGenerator` instead.
402403
*/
@@ -407,7 +408,7 @@ export class Vitest {
407408
'`experimental_defineCacheKeyGenerator` is deprecated. Use `defineCacheKeyGenerator` instead.',
408409
)
409410
}
410-
this._fsCache.defineCacheKeyGenerator(callback)
411+
this._fsCache.defineCacheKeyGenerator(project.config, callback)
411412
},
412413
}),
413414
)

‎packages/vitest/src/node/types/plugin.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface VitestPluginContext {
1010
config: TestProjectConfiguration | TestProjectConfiguration[],
1111
) => Promise<TestProject[]>
1212
/**
13-
* Define a generator that will be applied before hashing the cache key.
13+
* Define a generator that will be applied before hashing this project's cache key.
1414
*
1515
* Use this to make sure Vitest generates correct hash. It is a good idea
1616
* to define this function if your plugin can be registered with different options.

‎test/e2e/test/caching.test.ts‎

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from 'vitest'
2-
import { runVitest, useFS } from '../../test-utils'
2+
import { runInlineTests, runVitest, useFS } from '../../test-utils'
33

44
test("if file has import.meta.glob, it's not cached", async () => {
55
const { createFile } = useFS(
@@ -138,6 +138,62 @@ test('if cache key generator is defined, the hash is valid', async () => {
138138
`)
139139
})
140140

141+
test.each([
142+
['foo', 'bar'],
143+
['bar', 'foo'],
144+
])('cache key generators are scoped to projects (%s, %s)', async (first, second) => {
145+
const cold = await runInlineTests({
146+
'vitest.config.js': `
147+
import { defineConfig } from 'vitest/config'
148+
export default defineConfig({
149+
test: {
150+
fsModuleCache: true,
151+
fsModuleCachePath: './node_modules/.vitest-fs-cache',
152+
projects: ${JSON.stringify([first, second])}.map(name => ({
153+
plugins: [{
154+
name: 'replacer',
155+
configureVitest({ defineCacheKeyGenerator }) {
156+
defineCacheKeyGenerator(() => name)
157+
},
158+
transform(code, id) {
159+
if (id.endsWith('/common.js')) {
160+
return code.replace('PLACEHOLDER', name)
161+
}
162+
},
163+
}],
164+
test: { name, include: [name + '.test.js'] },
165+
})),
166+
},
167+
})
168+
`,
169+
'common.js': `export const value = 'PLACEHOLDER'`,
170+
'foo.test.js': `
171+
import { expect, test } from 'vitest'
172+
import { value } from './common.js'
173+
test('project value', () => expect(value).toBe('foo'))
174+
`,
175+
'bar.test.js': `
176+
import { expect, test } from 'vitest'
177+
import { value } from './common.js'
178+
test('project value', () => expect(value).toBe('bar'))
179+
`,
180+
})
181+
const warm = await runVitest({ root: cold.root })
182+
for (const run of [cold, warm]) {
183+
expect(run.stderr).toBe('')
184+
expect(run.errorTree()).toMatchInlineSnapshot(`
185+
{
186+
"bar.test.js": {
187+
"project value": "passed",
188+
},
189+
"foo.test.js": {
190+
"project value": "passed",
191+
},
192+
}
193+
`)
194+
}
195+
})
196+
141197
test('if cache key generator bails out, the file is not cached', async () => {
142198
process.env.REPLACED = 'value1'
143199

0 commit comments

Comments
 (0)