fix(testing): install typescript in npm e2e workspaces to keep tsquery off TypeScript 7 - #36478
Merged
Conversation
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
|
View your CI Pipeline Execution ↗ for commit a225da4
☁️ Nx Cloud last updated this comment at |
…y off TypeScript 7
`@phenomnomnominal/tsquery@6.2.0` declares an unbounded
`typescript: ">3.0.0"` peer. npm auto-installs missing peers and resolves
that to `latest`, which has been TypeScript 7 since 7.0.2 was published on
2026-07-08. TypeScript 7 dropped the top-level CommonJS `SyntaxKind`
export that tsquery reads at module load, so it throws:
NX Cannot convert undefined or null to object
at Object.keys (<anonymous>)
at .../@phenomnomnominal/tsquery/dist/src/syntax-kind.js:8:27
npm hoists that copy into the single root `node_modules/typescript` slot,
demoting the compatible version, so tsquery resolves TypeScript 7 and any
generator touching it fails. This is what turns `e2e-vite` and `e2e-web`
red on the npm legs of the nightly matrix.
Installing `typescript` directly after the plugin install reclaims the
hoisted slot, which repairs the tree regardless of how it got there.
Only npm is affected. pnpm resolves peers per dependent and reuses the
version already in the graph; yarn does not auto-install peers at all.
Both were verified green in this scenario, so the fix is gated to npm.
The npm typescript install added in the previous commit forced `~6.0.3` on
every npm e2e workspace. `@nx/remix` pins TypeScript 5.x and hard-errors on
6.x, so `e2e-remix`'s `--integrated (npm)` suite failed at app generation:
NX Remix does not support TypeScript 6 (detected `typescript@~6.0.3`).
Add a `typescriptVersion` option to `newProject()`, defaulting to the
version `@nx/js` installs, and have the Remix npm suite pass `~5.9.2`.
Pinning 5.x still claims the hoisted root slot, so tsquery keeps resolving
a TypeScript that exposes `SyntaxKind`.
Only the npm suite needs this; the yarn suite never receives the install.
FrozenPandaz
force-pushed
the
fix/e2e-npm-typescript-peer
branch
from
July 27, 2026 20:51
95b997b to
bbbbfc4
Compare
jaysoo
approved these changes
Aug 11, 2026
FrozenPandaz
added a commit
that referenced
this pull request
Aug 11, 2026
## Current Behavior `e2e-expo` fails on its MacOS/npm combo. Jest's `NODE_ENV=test` leaves @expo/cli's fusebox debugger shell on, and `@react-native/dev-middleware` 0.85+ throws `DefaultToolLauncher must be mocked or overridden in tests` while eagerly preparing it. Behind that, `@nx/expo:serve` only resolves on a `Bundling complete`/`Bundled` stdout line. Expo builds the web bundle on first request, and `@nx/cypress` will not request anything until the dev server target reports ready, so the two deadlock until the 5 minute `runCLI` timeout. ## Expected Behavior Expo e2e sets `EXPO_UNSTABLE_HEADLESS=1` through a shared `setupExpoEnv` helper. `@nx/expo:serve` resolves once the packager accepts connections. ## Nightly suite fixed Failing run used for reproduction: https://github.com/nrwl/nx/actions/runs/31358783952 (commit `3298fd8`). | Suite | Combo | Failure | Local result | | --- | --- | --- | --- | | e2e-expo | MacOS/npm | `DefaultToolLauncher must be mocked or overridden in tests`, `expo-legacy.test.ts` "should run e2e for cypress" | 22 passed, 0 `DefaultToolLauncher`, 0 `ETIMEDOUT` | Latent since the Expo SDK 56 lane (#35904) landed on 2026-06-24: `@expo/cli` 56.1.x pins dev-middleware 0.85.3, and 0.84.0 has neither the assert nor the eager `prepareDebuggerShell()` call. The dev-server deadlock is only reachable once the `DefaultToolLauncher` error is gone, so it never appeared in a nightly report - it is the next blocker behind it. The npm/TypeScript 7 failures in the same nightly (e2e-vite, e2e-web, e2e-rspack) are handled by #36478, not here. ## Related Issue(s) NXC-4612 <!-- polygraph-session-start --> --- [View session information ↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/nightly-golden-test-fixes-19ad82e5) <!-- polygraph-session-end --> --------- Co-authored-by: Jason Jean <jason@nrwl.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Current Behavior
@phenomnomnominal/tsquery@6.2.0declares an unbounded peer:npm auto-installs missing peers and resolves that range to
latest, which has been TypeScript 7 since 7.0.2 was published on 2026-07-08. TypeScript 7 dropped the top-level CommonJSSyntaxKindexport — its CJS entry now exports only{ version, versionMajorMinor }— and tsquery readsts.SyntaxKindat module load time:npm hoists that copy into the single root
node_modules/typescriptslot and demotes the compatible version into a nestednode_modules, so tsquery resolves TypeScript 7 and any generator that loads it fails.This is what turns
e2e-viteande2e-webred on the npm legs of the nightly matrix — e.g.nx generate @nx/react:lib --unitTestRunner=vitest, which reaches tsquery through@nx/vitest's configuration generator and@nx/vite'svite-config-edit-utils.The timeline matches exactly: the 2026-07-08 nightly (06:00 UTC) was green on
Linux/npm; TypeScript 7.0.2 hitlatestat 15:55 UTC that day; every nightly since has been red on npm.Expected Behavior
After installing the requested
@nx/*packages, the e2e harness installstypescriptdirectly. A direct dependency wins the hoisted root slot, so tsquery resolves the pinned version and loads normally.Installing it after the plugin install means it repairs whatever tree npm produced rather than relying on a particular ordering. Verified against a deliberately broken tree:
Why npm only
Same scenario, per package manager:
latest(7.0.2) and hoists it to the single root slot, demoting the compatible 6.0.3@phenomnomnominal+tsquery@6.2.0_typescript@6.0.3) — TypeScript 7 is never downloadedThat matches the nightly matrix, where the npm legs are red while yarn stays green. The change is gated to npm accordingly.
Notes
typescriptVersionis imported from@nx/js/src/utils/versions, which is already an exports-map subpath, so no published package changes.7.1.0-dev.20260727.1still exports onlyversion/versionMajorMinor), so this is not something a newer TypeScript fixes. TheTODOpoints at the real resolutions: tsquery bounding its peer upstream, or Nx retiring its tsquery call sites (as fix(testing): template the e2e config for fresh projects instead of ast-parsing it #36304 began).--omit=peerto theensurePackagetemp-dir install path; this covers the workspace-root install that path does not touch.Related Issue(s)
N/A — surfaced from the nightly golden-test matrix rather than a filed issue.
View session information ↗