Skip to content

fix(@angular/build): trigger test re-run on non-spec file changes in watch mode#32870

Closed
maruthang wants to merge 1 commit intoangular:mainfrom
maruthang:fix-32159-unit-test-watch-rerun
Closed

fix(@angular/build): trigger test re-run on non-spec file changes in watch mode#32870
maruthang wants to merge 1 commit intoangular:mainfrom
maruthang:fix-32159-unit-test-watch-rerun

Conversation

@maruthang
Copy link
Copy Markdown
Contributor

PR Checklist

PR Type

  • Bugfix

What is the current behavior?

In watch mode, the unit-test builder only re-runs tests when .spec.ts files 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?

  • Yes
  • No

…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
@google-cla
Copy link
Copy Markdown

google-cla bot commented Mar 27, 2026

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.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +179 to +190
// 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);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants