Skip to content

CI: nx affected doesn't build schematics-core when other packages' tests depend on it at runtime #5205

Description

@robert-md-or

Which @ngrx/* package(s) are the source of the bug?

schematics

Description

While working on PR #5203, the test-affected CI job failed across nearly every library package (store, effects, entity, router-store, store-devtools, component-store, operators, component, data, schematics, signals, example-app) with the same root cause:

Error: Failed to resolve import "@ngrx/schematics-core/testing" from "modules/store/migrations/18_0_0-beta/index.spec.ts". Does the file exist?

(and similar errors for @ngrx/schematics-core/testing/create-package in other packages)

What I found

The CI job (pnpm exec nx affected -t test --skip-nx-cache --parallel=3) computed 15 affected projects for this run. schematics-core was not among them — which makes sense, since the PR's change (removing a deprecated baseUrl from the root tsconfig.json) doesn't touch schematics-core's own source.

However, nearly every other package's test suite imports directly from @ngrx/schematics-core/testing at runtime (resolved via node_modules/@ngrx/schematics-core, which only gets populated when schematics-core's own build target runs its ncp dist/... node_modules/@ngrx/schematics-core step). Since schematics-core wasn't part of this affected run, it was never built, so the import couldn't resolve — even though store:build, effects:build, etc. all completed successfully beforehand.

The only test targets that passed in this run were www:test, standalone-app:test, and eslint-plugin:test — none of which import from @ngrx/schematics-core.

Why I think this is a graph/config gap, not specific to my PR

  • nx.json's targetDefaults has test: { dependsOn: ["build"] } and build: { dependsOn: ["^build"] }, so in principle a project's own build dependencies should be picked up transitively.
  • But since the @ngrx/schematics-core import is resolved via a runtime node_modules path (not a source-level TS project reference Nx's dependency graph analysis can see), Nx doesn't appear to know that these packages' test targets implicitly depend on schematics-core's build output.
  • Locally, running e.g. pnpm nx run store:test directly (not via nx affected) passed cleanly for me — but only because node_modules/@ngrx/schematics-core was already populated on my machine from an earlier, unrelated manual build. That artifact wouldn't exist on a fresh CI checkout unless schematics-core happens to be affected in that particular run.

If this reasoning is correct, any PR whose diff doesn't directly touch schematics-core would hit this same failure in the affected-based CI job, regardless of what the PR actually changes.

Supporting evidence: comparison with a sibling PR

A related PR I opened around the same time, #5202 (touching moduleResolution in a handful of non-root tsconfig files), passed CI cleanly. Looking at its test-affected output, only 3 projects were run: schematics, eslint-plugin, and www — exactly the projects whose own tsconfig files that PR touched. None of store, effects, entity, router-store, component-store, operators, component, data, or signals were part of that affected set, so their migration tests (which import @ngrx/schematics-core/testing) never ran, and the gap never surfaced.

#5203, by contrast, removed baseUrl from the root tsconfig.json — which is extended by nearly every project in the workspace. That caused Nx to mark 15 projects as affected at once, including all the ones whose tests depend on @ngrx/schematics-core being built. This is consistent with the hypothesis above: the gap only surfaces when a change happens to make Nx consider a wide-enough set of projects "affected" to include ones that need schematics-core's build output, without schematics-core itself being triggered.

Minimal reproduction of the bug/regression with instructions

  1. Open a PR whose diff does not touch anything under modules/schematics-core/ (e.g. a small change to the root tsconfig.json, unrelated to schematics).
  2. Let the test-affected CI job run: pnpm exec nx affected -t test --skip-nx-cache --parallel=3.
  3. Observe that schematics-core is not included in the list of affected projects Nx reports at the start of the run.
  4. Observe that most other library packages' test suites (store, effects, entity, router-store, store-devtools, component-store, operators, component, data, schematics, signals, example-app) fail with errors like:
   Error: Failed to resolve import "@ngrx/schematics-core/testing" from "modules/store/migrations/18_0_0-beta/index.spec.ts". Does the file exist?
  1. Compare against packages that don't import from @ngrx/schematics-core (e.g. www, standalone-app, eslint-plugin) — these pass without issue in the same run.
    For reference, this was observed on PR build: remove deprecated baseUrl from tsconfig.json #5203 (a one-line baseUrl removal from the root tsconfig.json) here: [link to the failed CI run].

Running the same test target directly and locally (e.g. pnpm nx run store:test, not via nx affected) does not reproduce the failure — but only because node_modules/@ngrx/schematics-core was already populated locally from an earlier, unrelated build. A fresh checkout without that pre-existing artifact should reproduce the failure the same way CI does.

Suggested next step

Might be worth adding an explicit implicitDependencies entry (or equivalent) on the packages that import from @ngrx/schematics-core/testing, so Nx's affected/dependency graph builds it whenever those packages' tests run — not just when schematics-core itself is part of the affected set.

Happy to help investigate further or open a PR once there's agreement on the right fix — wanted to flag this first since I wasn't fully sure of the intended dependency structure here.

Expected behavior

nx affected -t test should build schematics-core whenever it runs tests for any project whose test suite imports from @ngrx/schematics-core at runtime (e.g. @ngrx/schematics-core/testing), regardless of whether schematics-core itself is part of the computed affected set for that particular diff.

In other words, a CI run should pass or fail based on whether the actual code changes broke something — not based on which unrelated files happened to be touched and how that shaped Nx's affected-project calculation for that run.

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

NgRx: 22.0.0-beta.0
Angular: 22.0.0
Node: v24.15.0
Browser: N/A (build/test tooling issue)
OS: macOS (local repro attempt); CI runs on GitHub Actions (Linux)

Other information

Happy to help investigate further, run additional comparisons across other recent PRs, or open a PR against nx.json/project configs once there's agreement on the right fix.

I would be willing to submit a PR to fix this issue

  • Yes
  • No

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions