Skip to content

Commit a97bd37

Browse files
authored
chore(testing): stub plugin imports in devkit specs to avoid cross-project reads (#35374)
## Current Behavior Three devkit specs exercise helpers that do `await import('@nx/<plugin>/plugin')` at runtime (`findPluginForConfigFile` when a registration has `include`/`exclude`, and `addE2eCiTargetDefaults` unconditionally for every e2e plugin registration). Combined with the custom jest resolver in `scripts/patched-jest-resolver.js` — which maps `@nx/<pkg>` subpaths to workspace source — the dynamic imports pull the real plugin source plus everything transitively re-exported by `@nx/js` and `@nx/vite` into the jest process. Concretely, `devkit:test` ends up reading ~49 files across `packages/js/src/**` and `packages/vite/**` that are not declared (and cannot be declared without creating a project-graph cycle since `@nx/js` and `@nx/vite` both depend on `@nx/devkit`). The sandbox flags all 49 as undeclared-read violations. ## Expected Behavior None of these specs aim to validate the real plugin's behavior. They exercise devkit's own logic — how a registration is matched to a config file, how target defaults are written into `nx.json`, and how e2e web server info is resolved from a registered plugin — treating `@nx/<plugin>/plugin` as an opaque reference. The plugin's `createNodesV2[0]` glob is used by the devkit helpers only as a pattern pre-filter against conventional config filenames (`vite.config.ts`, `cypress.config.ts`); what the real plugin does beyond that is outside the scope of these tests. Stubbing the three plugin modules with `jest.mock(..., { virtual: true })` that exposes just the real plugin's glob pattern: - Preserves the minimal contract the devkit helpers rely on (the module resolves, and its glob matches the conventional config filenames used in the tests). - Drops the incidental loading of the real plugin and its entire transitive graph — removing all 49 reported sandbox violations. - Eliminates an accidental coupling to the pinned `@nx/cypress` version currently pulled from `node_modules`, which also transitively requires `@nx/js` workspace source via the custom resolver. Changes are test-only; no production code is touched.
1 parent 77f8e1e commit a97bd37

3 files changed

Lines changed: 38 additions & 0 deletions

File tree

packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
// Stub out the real @nx/vite/plugin so findPluginForConfigFile's dynamic
2+
// `await import('@nx/vite/plugin')` doesn't pull @nx/vite and @nx/js source
3+
// into this test. Only the createNodesV2 glob is consumed, and the include/
4+
// exclude assertions depend on the nxJson registration, not the real plugin.
5+
jest.mock(
6+
'@nx/vite/plugin',
7+
() => ({
8+
createNodesV2: [
9+
'**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}',
10+
jest.fn(),
11+
],
12+
}),
13+
{ virtual: true }
14+
);
15+
116
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
217
import { type Tree, readNxJson, updateNxJson } from 'nx/src/devkit-exports';
318
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';

packages/devkit/src/generators/target-defaults-utils.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
// Stub out @nx/cypress/plugin so the dynamic `await import('@nx/cypress/plugin')`
2+
// in addE2eCiTargetDefaults doesn't pull real plugin code (which transitively
3+
// imports @nx/js source and inflates sandbox inputs).
4+
jest.mock(
5+
'@nx/cypress/plugin',
6+
() => ({
7+
createNodesV2: ['**/cypress.config.{js,ts,mjs,cjs}', jest.fn()],
8+
}),
9+
{ virtual: true }
10+
);
11+
112
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
213
import { readNxJson, updateNxJson, type Tree } from 'nx/src/devkit-exports';
314
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';

packages/devkit/src/utils/find-plugin-for-config-file.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
// Stub out @nx/cypress/plugin so findPluginForConfigFile's dynamic
2+
// `await import('@nx/cypress/plugin')` (fired when include/exclude is present)
3+
// doesn't pull real plugin code, which transitively imports @nx/js source and
4+
// inflates sandbox inputs.
5+
jest.mock(
6+
'@nx/cypress/plugin',
7+
() => ({
8+
createNodesV2: ['**/cypress.config.{js,ts,mjs,cjs}', jest.fn()],
9+
}),
10+
{ virtual: true }
11+
);
12+
113
import { type Tree, readNxJson, updateNxJson } from 'nx/src/devkit-exports';
214
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
315
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';

0 commit comments

Comments
 (0)