fix(@angular/build): trigger test re-run on non-spec file changes in watch mode#32870
fix(@angular/build): trigger test re-run on non-spec file changes in watch mode#32870maruthang wants to merge 1 commit intoangular:mainfrom
Conversation
…watch mode When non-test files (services, components, etc.) change during watch mode, use Vitest's module graph to find dependent test specifications and include them in the re-run set. Previously only direct .spec.ts file changes triggered test re-runs. Fixes angular#32159
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request updates the Vitest executor to ensure that changes to non-test files, such as components or services, trigger re-runs of their dependent test specifications by querying Vitest's module graph. A new test case verifies this behavior in watch mode. The reviewer suggested refactoring the logic in executor.ts to consolidate multiple loops into a single, more efficient loop that uses a Set for deduplication.
| // For non-test files (e.g., services, components), find dependent test specs | ||
| // via Vitest's module graph so that changes to these files trigger test re-runs. | ||
| for (const file of modifiedNonTestFiles) { | ||
| const specs = vitest.getModuleSpecifications(file); | ||
| if (specs) { | ||
| this.debugLog( | ||
| DebugLogLevel.Verbose, | ||
| `Found ${specs.length} dependent test specification(s) for non-test file '${file}'.`, | ||
| ); | ||
| specsToRerun.push(...specs); | ||
| } | ||
| } |
There was a problem hiding this comment.
The logic for collecting specs to re-run is spread across multiple loops and intermediate collections (modifiedSourceFiles, modifiedNonTestFiles). This could be simplified and made more efficient by processing each modified file in a single loop. This would also naturally handle deduplication of specs if a Set is used.
Consider refactoring the logic from lines 145-190 to something like this:
const specsToRerun = new Set<string>();
for (const modifiedFile of [...buildResult.modified, ...buildResult.added]) {
const absoluteOutputFile = this.normalizePath(path.join(this.options.workspaceRoot, modifiedFile));
vitest.invalidateFile(absoluteOutputFile);
const source = this.entryPointToTestFile.get(modifiedFile);
if (source) {
// This is a test file
vitest.invalidateFile(source);
const specs = vitest.getModuleSpecifications(source);
if (specs) {
specs.forEach(spec => specsToRerun.add(spec));
}
} else {
// This is a non-test file
const specs = vitest.getModuleSpecifications(absoluteOutputFile);
if (specs) {
this.debugLog(
DebugLogLevel.Verbose,
`Found ${specs.length} dependent test specification(s) for non-test file '${absoluteOutputFile}'.`,
);
specs.forEach(spec => specsToRerun.add(spec));
}
}
}
if (specsToRerun.size > 0) {
const specsToRerunArr = [...specsToRerun];
this.debugLog(DebugLogLevel.Info, `Re-running ${specsToRerunArr.length} test specifications.`);
this.debugLog(DebugLogLevel.Verbose, 'Specs to rerun:', specsToRerunArr);
testResults = await vitest.rerunTestSpecifications(specsToRerunArr);
}
PR Checklist
PR Type
What is the current behavior?
In watch mode, the unit-test builder only re-runs tests when
.spec.tsfiles change. Changes to non-test files (services, components, etc.) are ignored, even though tests depend on them.Issue Number: #32159
What is the new behavior?
When non-test files change during watch mode, Vitest's module graph is queried to find dependent test specifications, which are then included in the re-run set. This ensures that changes to any source file trigger the relevant tests.
Does this PR introduce a breaking change?