Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions packages/vitest/src/node/cache/fsModuleCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class FileSystemModuleCache {
private version = '1.0.0-beta.8'
private fsCacheRoots = new WeakMap<ResolvedConfig, string>()
private fsEnvironmentHashMap = new WeakMap<DevEnvironment, string>()
private fsCacheKeyGenerators = new Set<CacheKeyIdGenerator>()
private fsCacheKeyGenerators = new WeakMap<ResolvedConfig, Set<CacheKeyIdGenerator>>()
private warnedDeprecatedIgnore = new Set<string>()
// this exists only to avoid the perf. cost of reading a file and generating a hash again
// surprisingly, on some machines this has negligible effect
Expand All @@ -62,8 +62,13 @@ export class FileSystemModuleCache {
this.metadataFilePath = join(this.rootCache, METADATA_FILE)
}

public defineCacheKeyGenerator(callback: CacheKeyIdGenerator): void {
this.fsCacheKeyGenerators.add(callback)
public defineCacheKeyGenerator(config: ResolvedConfig, callback: CacheKeyIdGenerator): void {
let generators = this.fsCacheKeyGenerators.get(config)
if (!generators) {
generators = new Set()
this.fsCacheKeyGenerators.set(config, generators)
}
generators.add(callback)
}

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

let hashString = ''

for (const generator of this.fsCacheKeyGenerators) {
for (const generator of this.fsCacheKeyGenerators.get(vitestConfig) || []) {
const result = generator({ environment, id, sourceCode: fileContent })
if (typeof result === 'string') {
hashString += result
Expand Down
5 changes: 3 additions & 2 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ export class Vitest {
project,
vitest: this,
injectTestProjects: this.injectTestProject,
defineCacheKeyGenerator: (callback) => this._fsCache.defineCacheKeyGenerator(callback),
defineCacheKeyGenerator: (callback) =>
this._fsCache.defineCacheKeyGenerator(project.config, callback),
/**
* @deprecated Use `defineCacheKeyGenerator` instead.
*/
Expand All @@ -407,7 +408,7 @@ export class Vitest {
'`experimental_defineCacheKeyGenerator` is deprecated. Use `defineCacheKeyGenerator` instead.',
)
}
this._fsCache.defineCacheKeyGenerator(callback)
this._fsCache.defineCacheKeyGenerator(project.config, callback)
},
}),
)
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/types/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface VitestPluginContext {
config: TestProjectConfiguration | TestProjectConfiguration[],
) => Promise<TestProject[]>
/**
* Define a generator that will be applied before hashing the cache key.
* Define a generator that will be applied before hashing this project's cache key.
*
* Use this to make sure Vitest generates correct hash. It is a good idea
* to define this function if your plugin can be registered with different options.
Expand Down
58 changes: 57 additions & 1 deletion test/e2e/test/caching.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from 'vitest'
import { runVitest, useFS } from '../../test-utils'
import { runInlineTests, runVitest, useFS } from '../../test-utils'

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

test.each([
['foo', 'bar'],
['bar', 'foo'],
])('cache key generators are scoped to projects (%s, %s)', async (first, second) => {
const cold = await runInlineTests({
'vitest.config.js': `
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
fsModuleCache: true,
fsModuleCachePath: './node_modules/.vitest-fs-cache',
projects: ${JSON.stringify([first, second])}.map(name => ({
plugins: [{
name: 'replacer',
configureVitest({ defineCacheKeyGenerator }) {
defineCacheKeyGenerator(() => name)
},
transform(code, id) {
if (id.endsWith('/common.js')) {
return code.replace('PLACEHOLDER', name)
}
},
}],
test: { name, include: [name + '.test.js'] },
})),
},
})
`,
'common.js': `export const value = 'PLACEHOLDER'`,
'foo.test.js': `
import { expect, test } from 'vitest'
import { value } from './common.js'
test('project value', () => expect(value).toBe('foo'))
`,
'bar.test.js': `
import { expect, test } from 'vitest'
import { value } from './common.js'
test('project value', () => expect(value).toBe('bar'))
`,
})
const warm = await runVitest({ root: cold.root })
for (const run of [cold, warm]) {
expect(run.stderr).toBe('')
expect(run.errorTree()).toMatchInlineSnapshot(`
{
"bar.test.js": {
"project value": "passed",
},
"foo.test.js": {
"project value": "passed",
},
}
`)
}
})

test('if cache key generator bails out, the file is not cached', async () => {
process.env.REPLACED = 'value1'

Expand Down
Loading