CI: nx affected doesn't build schematics-core when other packages' tests depend on it at runtime
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'stargetDefaultshastest: { dependsOn: ["build"] }andbuild: { dependsOn: ["^build"] }, so in principle a project's own build dependencies should be picked up transitively.- But since the
@ngrx/schematics-coreimport is resolved via a runtimenode_modulespath (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 onschematics-core's build output. - Locally, running e.g.
pnpm nx run store:testdirectly (not vianx affected) passed cleanly for me — but only becausenode_modules/@ngrx/schematics-corewas already populated on my machine from an earlier, unrelated manual build. That artifact wouldn't exist on a fresh CI checkout unlessschematics-corehappens 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
- Open a PR whose diff does not touch anything under
modules/schematics-core/(e.g. a small change to the roottsconfig.json, unrelated to schematics). - Let the
test-affectedCI job run:pnpm exec nx affected -t test --skip-nx-cache --parallel=3. - Observe that
schematics-coreis not included in the list of affected projects Nx reports at the start of the run. - 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?- 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 #5203 (a one-linebaseUrlremoval from the roottsconfig.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
- The failing CI run referenced above: [paste the direct link to the failed
test-affectedjob on PR #5203] - The passing comparison run referenced above: [paste the direct link to the
test-affectedjob on PR #5202] - PR #5203 itself, where this was first observed: https://github.com/ngrx/platform/pull/5203
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
Source: ngrx/platform