Skip to content

Commit 80aa13d

Browse files
authored
fix: run tests that import a deleted file (#11669)
1 parent 79501f3 commit 80aa13d

2 files changed

Lines changed: 88 additions & 2 deletions

File tree

‎packages/vitest/src/node/affected-modules.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DevEnvironment } from 'vite'
1+
import type { DevEnvironment, EnvironmentModuleNode } from 'vite'
22
import type { Vitest } from './core'
33
import type { TestProject } from './project'
44
import type { TestSpecification } from './test-specification'
@@ -357,9 +357,13 @@ class ProjectGraph {
357357
const imports = new Set([...(transformed.deps || []), ...(transformed.dynamicDeps || [])])
358358
const dependencies: string[] = []
359359
const watchedFiles: string[] = []
360+
let failed = false
360361
// ids keep the query, so `./file.txt?raw` is walked as its own module
361362
this.environment.moduleGraph.getModuleById(id)?.importedModules.forEach((imported) => {
362-
if (imported.id && imported.file && this.resolver.isLocalSourceFile(imported.file)) {
363+
// a dynamic import of a missing file can be caught, a static one always fails
364+
if (isMissingFile(imported) && transformed.deps?.includes(imported.url)) {
365+
failed = true
366+
} else if (imported.id && imported.file && this.resolver.isLocalSourceFile(imported.file)) {
363367
;(imports.has(imported.url) ? dependencies : watchedFiles).push(imported.id)
364368
}
365369
})
@@ -375,10 +379,16 @@ class ProjectGraph {
375379
watchedFiles,
376380
mocked: new Set(Array.from(replaced, (mockedId) => cleanUrl(mockedId))),
377381
restored: new Set(Array.from(restored, (restoredId) => cleanUrl(restoredId))),
382+
failed,
378383
}
379384
}
380385
}
381386

387+
// in SSR, Vite keeps an import it can't resolve as is, a bare one can still be loaded by Node
388+
function isMissingFile(mod: EnvironmentModuleNode): boolean {
389+
return mod.id?.[0] === '.' || mod.meta?.['vite:alias']?.noResolved === true
390+
}
391+
382392
/**
383393
* Walks the module graph once for every root, skipping a module only when every walk that reaches it mocks it.
384394
*/

‎test/e2e/test/related-deps.test.ts‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,82 @@ describe('modules that fail to load', () => {
14591459
`)
14601460
})
14611461

1462+
test('a test that imports a deleted file runs and reports the error', async () => {
1463+
const { results } = await runInlineTests(
1464+
{
1465+
'vitest.config.js': { resolve: { alias: { '@': '/src' } } },
1466+
'src/other.js': 'export {}',
1467+
'a.test.js': testFile('a', `import './src/helper.js'`),
1468+
'b.test.js': testFile('b', `import '@/helper'`),
1469+
'c.test.js': testFile('c', `import './src/other.js'`),
1470+
},
1471+
{ related: ['src/helper.js'] },
1472+
)
1473+
1474+
expect(moduleStates(results)).toMatchInlineSnapshot(`
1475+
[
1476+
[
1477+
"a.test.js",
1478+
"failed",
1479+
],
1480+
[
1481+
"b.test.js",
1482+
"failed",
1483+
],
1484+
]
1485+
`)
1486+
})
1487+
1488+
test('a test that catches a dynamic import of a deleted file does not run', async () => {
1489+
const { results } = await runInlineTests(
1490+
{
1491+
'src/changed.js': 'export {}',
1492+
'a.test.js': `
1493+
import { test } from 'vitest'
1494+
test('a', async () => {
1495+
await import('./src/helper.js').catch(() => {})
1496+
})
1497+
`,
1498+
'b.test.js': testFile('b', `import './src/changed.js'`),
1499+
},
1500+
{ related: ['src/helper.js', 'src/changed.js'] },
1501+
)
1502+
1503+
expect(moduleStates(results)).toMatchInlineSnapshot(`
1504+
[
1505+
[
1506+
"b.test.js",
1507+
"passed",
1508+
],
1509+
]
1510+
`)
1511+
})
1512+
1513+
test('a setup file that imports a deleted file runs every test', async () => {
1514+
const { results } = await runInlineTests(
1515+
{
1516+
'vitest.config.js': { test: { setupFiles: ['./setup.js'] } },
1517+
'setup.js': `import './src/helper.js'`,
1518+
'a.test.js': testFile('a'),
1519+
'b.test.js': testFile('b'),
1520+
},
1521+
{ related: ['src/helper.js'] },
1522+
)
1523+
1524+
expect(moduleStates(results)).toMatchInlineSnapshot(`
1525+
[
1526+
[
1527+
"a.test.js",
1528+
"failed",
1529+
],
1530+
[
1531+
"b.test.js",
1532+
"failed",
1533+
],
1534+
]
1535+
`)
1536+
})
1537+
14621538
function moduleStates(modules: TestModule[]) {
14631539
return modules
14641540
.map((testModule) => [testModule.relativeModuleId, testModule.state()])

0 commit comments

Comments
 (0)