@@ -281,7 +281,6 @@ export async function createVitestConfigPlugin(
281281 test : {
282282 name : projectName ,
283283 include,
284- fsModuleCache : false ,
285284 // CLI provider browser options override, if present
286285 ...( browser ? { browser } : { } ) ,
287286 // Only override if the user explicitly set it via CLI
@@ -301,7 +300,6 @@ export async function createVitestConfigPlugin(
301300
302301 return {
303302 test : {
304- fsModuleCache : false ,
305303 coverage : await generateCoverageOption (
306304 options . coverage ,
307305 testConfig ?. coverage ,
@@ -335,12 +333,37 @@ export function createVitestPlugins(pluginOptions: PluginOptions): Vite.Plugin[]
335333 ) ;
336334 let vitestConfig : ResolvedConfig ;
337335
336+ /** The build output path served for a module, whether it is a test entry point or a built artifact. */
337+ const getOutputPath = ( id : string ) : string => {
338+ const entryPoint = testFileToEntryPoint . get ( id ) ;
339+
340+ return entryPoint ? entryPoint + '.js' : toPosixPath ( path . relative ( workspaceRoot , id ) ) ;
341+ } ;
342+
338343 return [
339344 {
340345 name : 'angular:test-in-memory-provider' ,
341346 enforce : 'pre' ,
342347 configureVitest ( context : VitestPluginContext ) {
343348 vitestConfig = context . vitest . config ;
349+
350+ // Vitest keys its file system module cache on the file found on disk. A test entry point is
351+ // served from its bundle instead, which also holds the application code it imports, so the
352+ // key must follow the served build output, or the cache would return a stale bundle.
353+ context . defineCacheKeyGenerator ( ( { id } ) => {
354+ const outputPath = getOutputPath ( id ) ;
355+ const outputFile = buildResultFiles . get ( outputPath ) ;
356+ if ( ! outputFile ) {
357+ return undefined ;
358+ }
359+ if ( outputFile . origin !== 'memory' ) {
360+ return false ;
361+ }
362+
363+ const sourceMapFile = buildResultFiles . get ( outputPath + '.map' ) ;
364+
365+ return `${ outputFile . hash } :${ sourceMapFile ?. origin === 'memory' ? sourceMapFile . hash : '' } ` ;
366+ } ) ;
344367 } ,
345368 resolveId : ( id : string , importer : string | undefined ) => {
346369 // Fast path for test entry points.
@@ -399,12 +422,9 @@ export function createVitestPlugins(pluginOptions: PluginOptions): Vite.Plugin[]
399422 async load ( id : string ) {
400423 assert ( buildResultFiles . size > 0 , 'buildResult must be available for in-memory loading.' ) ;
401424
402- // Attempt to load as a source test file.
403- const entryPoint = testFileToEntryPoint . get ( id ) ;
404- let outputPath ;
405- if ( entryPoint ) {
406- outputPath = entryPoint + '.js' ;
407-
425+ // Attempt to load as a source test file, or else as a built artifact.
426+ const outputPath = getOutputPath ( id ) ;
427+ if ( testFileToEntryPoint . has ( id ) ) {
408428 // Setup files must not be wrapped in a virtual import stub because Vitest only invalidates
409429 // the setup file itself between test files; wrapping it would cause the underlying bundle
410430 // to be cached, preventing per-test hooks from running on subsequent test files.
@@ -417,10 +437,6 @@ export function createVitestPlugins(pluginOptions: PluginOptions): Vite.Plugin[]
417437 code : `import "./${ outputPath } ";` ,
418438 } ;
419439 }
420- } else {
421- // Attempt to load as a built artifact.
422- const relativePath = path . relative ( workspaceRoot , id ) ;
423- outputPath = toPosixPath ( relativePath ) ;
424440 }
425441
426442 const outputFile = buildResultFiles . get ( outputPath ) ;
0 commit comments