Skip to content

Commit 1507788

Browse files
authored
chore(repo): short-circuit isUsingTsSolutionSetup in unit tests (#35371)
## Current Behavior `isUsingTsSolutionSetup()` (in both `@nx/js` and `@nx/workspace`) falls back to `new FsTree(workspaceRoot, false)` when called without a tree, reading the real repo's `tsconfig.json` / `tsconfig.base.json`. Many unit tests indirectly invoke it (cypress-preset, playwright-preset, plugin `createNodesV2`, executor `normalize`, etc.), which surfaces as sandbox violations across ~13 test targets (angular, rspack, vite, rollup, webpack, react, next, js, cypress, remix, workspace, nest, node). ## Expected Behavior Unit tests should never touch the real workspace FS. A global mock in `scripts/unit-test-setup.js` short-circuits `isUsingTsSolutionSetup()` when called without a tree, returning `true` to match the de-facto behavior of hitting the real FS (the Nx repo is a TS solution workspace) and preserve every test's existing expectations. Calls that pass an explicit (virtual) tree still run the real implementation. Two specs that deliberately simulate a non-TS-solution workspace (via `node:fs` / `workspaceRoot` mocks) add a per-file override returning `false` to keep expressing that intent: - `packages/vite/src/plugins/plugin-vitest.spec.ts` - `packages/rollup/src/plugins/with-nx/normalize-options.spec.ts`
1 parent a0b4bf8 commit 1507788

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

packages/rollup/src/plugins/with-nx/normalize-options.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ jest.mock('@nx/js', () => ({
55
createEntryPoints: (x: string) => x,
66
}));
77

8+
// This spec simulates a non-TS-solution workspace via `workspaceRoot: '/tmp'`
9+
// (where tsconfig.base.json doesn't exist). The global mock in
10+
// `scripts/unit-test-setup.js` short-circuits `isUsingTsSolutionSetup()` before
11+
// any fs read, so we override it here to explicitly express the intent.
12+
jest.mock('@nx/js/src/utils/typescript/ts-solution-setup', () => ({
13+
...jest.requireActual('@nx/js/src/utils/typescript/ts-solution-setup'),
14+
isUsingTsSolutionSetup: jest.fn(() => false),
15+
}));
16+
817
jest.mock('@nx/devkit', () => ({
918
...jest.requireActual('@nx/devkit'),
1019
workspaceRoot: '/tmp',

packages/vite/src/plugins/plugin-vitest.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ jest.mock('vite', () => ({
5959
}),
6060
}));
6161

62+
// This spec simulates a non-TS-solution workspace via the `node:fs` mock above
63+
// (`existsSync` returns false for `tsconfig.base.json`). The global mock in
64+
// `scripts/unit-test-setup.js` short-circuits `isUsingTsSolutionSetup()` before
65+
// any fs read, so we override it here to explicitly express the intent.
66+
jest.mock('@nx/js/src/utils/typescript/ts-solution-setup', () => ({
67+
...jest.requireActual('@nx/js/src/utils/typescript/ts-solution-setup'),
68+
isUsingTsSolutionSetup: jest.fn(() => false),
69+
}));
70+
6271
jest.mock('../utils/executor-utils', () => ({
6372
loadViteDynamicImport: jest.fn().mockResolvedValue({
6473
resolveConfig: jest.fn().mockResolvedValue({

scripts/unit-test-setup.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,38 @@ module.exports = () => {
3939
*/
4040
ensurePackage: jest.fn((pkg) => jest.requireActual(pkg)),
4141
}));
42+
43+
/**
44+
* `isUsingTsSolutionSetup()` falls back to `new FsTree(workspaceRoot, false)`
45+
* when called without a tree, which reads the real repo's `tsconfig.json` /
46+
* `tsconfig.base.json`. That surfaces as a sandbox violation for tests that
47+
* indirectly invoke it (cypress-preset, playwright-preset, plugin
48+
* `createNodesV2`, executor `normalize`, etc.).
49+
*
50+
* Unit tests should never touch the real workspace FS, so when the function
51+
* is called without a tree, short-circuit to `true`. `true` matches the
52+
* de-facto behavior of hitting the real FS (the Nx repo is a TS solution
53+
* workspace), preserving every test's existing expectations without
54+
* reading from disk. Calls that pass an explicit (virtual) tree still run
55+
* the real implementation.
56+
*
57+
* There are two copies of the function — one in `@nx/js` and one in
58+
* `@nx/workspace` — both need to be mocked.
59+
*/
60+
const mockIsUsingTsSolutionSetup = (specifier) => {
61+
jest.doMock(specifier, () => {
62+
const actual = jest.requireActual(specifier);
63+
return {
64+
__esModule: true,
65+
...actual,
66+
isUsingTsSolutionSetup: jest.fn((tree) =>
67+
tree ? actual.isUsingTsSolutionSetup(tree) : true
68+
),
69+
};
70+
});
71+
};
72+
mockIsUsingTsSolutionSetup('@nx/js/src/utils/typescript/ts-solution-setup');
73+
mockIsUsingTsSolutionSetup(
74+
'@nx/workspace/src/utilities/typescript/ts-solution-setup'
75+
);
4276
};

0 commit comments

Comments
 (0)