@nx/jest 22.7.0 → 22.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/migrations.json CHANGED
@@ -42,6 +42,14 @@
42
42
  },
43
43
  "description": "Replace removed matcher aliases in Jest v30 with their corresponding matcher",
44
44
  "implementation": "./src/migrations/update-21-3-0/replace-removed-matcher-aliases"
45
+ },
46
+ "update-snapshot-guide-link": {
47
+ "version": "23.0.0-beta.6",
48
+ "requires": {
49
+ "jest": ">=30.0.0"
50
+ },
51
+ "description": "Update the Jest snapshot guide link in `.snap` files from the legacy `https://goo.gl/fbAQLP` URL to `https://jestjs.io/docs/snapshot-testing`, which Jest v30 now requires.",
52
+ "implementation": "./src/migrations/update-23-0-0/update-snapshot-guide-link"
45
53
  }
46
54
  },
47
55
  "packageJsonUpdates": {
@@ -171,6 +179,26 @@
171
179
  "alwaysAddToPackageJson": false
172
180
  }
173
181
  }
182
+ },
183
+ "23.0.0-pin-jest-30-3-for-rn-compat": {
184
+ "version": "23.0.0-beta.9",
185
+ "requires": {
186
+ "jest": ">=30.0.0"
187
+ },
188
+ "packages": {
189
+ "jest": {
190
+ "version": "~30.3.0",
191
+ "alwaysAddToPackageJson": false
192
+ },
193
+ "babel-jest": {
194
+ "version": "~30.3.0",
195
+ "alwaysAddToPackageJson": false
196
+ },
197
+ "@types/jest": {
198
+ "version": "~30.0.0",
199
+ "alwaysAddToPackageJson": false
200
+ }
201
+ }
174
202
  }
175
203
  }
176
204
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/jest",
3
- "version": "22.7.0",
3
+ "version": "22.7.2",
4
4
  "private": false,
5
5
  "description": "The Nx Plugin for Jest contains executors and generators allowing your workspace to use the powerful Jest testing capabilities.",
6
6
  "repository": {
@@ -38,14 +38,14 @@
38
38
  "dependencies": {
39
39
  "@jest/reporters": "^30.0.2",
40
40
  "@jest/test-result": "^30.0.2",
41
- "@nx/devkit": "22.7.0",
42
- "@nx/js": "22.7.0",
43
- "@phenomnomnominal/tsquery": "~6.1.4",
41
+ "@nx/devkit": "22.7.2",
42
+ "@nx/js": "22.7.2",
43
+ "@phenomnomnominal/tsquery": "~6.2.0",
44
44
  "identity-obj-proxy": "3.0.0",
45
45
  "jest-config": "^30.0.2",
46
46
  "jest-resolve": "^30.0.2",
47
47
  "jest-util": "^30.0.2",
48
- "minimatch": "10.2.4",
48
+ "minimatch": "10.2.5",
49
49
  "picocolors": "^1.1.0",
50
50
  "resolve.exports": "2.0.3",
51
51
  "semver": "^7.6.3",
@@ -53,7 +53,7 @@
53
53
  "yargs-parser": "21.1.1"
54
54
  },
55
55
  "devDependencies": {
56
- "nx": "22.7.0"
56
+ "nx": "22.7.2"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public"
@@ -1 +1 @@
1
- {"version":3,"file":"jest-preset.d.ts","sourceRoot":"","sources":["../../../../packages/jest/preset/jest-preset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,MAAM,CAAC;AAK1C,eAAO,MAAM,QAAQ,EAAE,MAsCtB,CAAC"}
1
+ {"version":3,"file":"jest-preset.d.ts","sourceRoot":"","sources":["../../../../packages/jest/preset/jest-preset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,MAAM,CAAC;AAK1C,eAAO,MAAM,QAAQ,EAAE,MAuCtB,CAAC"}
@@ -25,6 +25,7 @@ exports.nxPreset = {
25
25
  ],
26
26
  },
27
27
  testEnvironment: 'jsdom',
28
+ modulePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/out-tsc/'],
28
29
  /**
29
30
  * manually set the exports names to load in common js, to mimic the behaviors of jest 27
30
31
  * before jest didn't fully support package exports and would load in common js code (typically via main field). now jest 28+ will load in the browser esm code, but jest esm support is not fully supported.
@@ -5,8 +5,6 @@ import { Tree } from '@nx/devkit';
5
5
  * in newer versions (22+, 24+) can cause issues with ESM syntax in .ts files
6
6
  * when the project is configured for CommonJS.
7
7
  *
8
- * This migration only runs if @nx/jest/plugin is registered in nx.json.
9
- *
10
8
  * Conversions:
11
9
  * - `export default { ... }` -> `module.exports = { ... }`
12
10
  * - `import { x } from 'y'` -> `const { x } = require('y')`
@@ -16,8 +14,8 @@ import { Tree } from '@nx/devkit';
16
14
  * - `import.meta`
17
15
  * - top-level `await`
18
16
  *
19
- * Projects with `type: module` in package.json will be warned as they are
20
- * incompatible with @nx/jest/plugin which forces CommonJS resolution.
17
+ * Projects with `type: module` in package.json are skipped and warned about,
18
+ * as they use ESM semantics and don't need the CJS conversion.
21
19
  */
22
20
  export default function convertJestConfigToCjs(tree: Tree): Promise<() => void>;
23
21
  //# sourceMappingURL=convert-jest-config-to-cjs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convert-jest-config-to-cjs.d.ts","sourceRoot":"","sources":["../../../../../../packages/jest/src/migrations/update-22-2-0/convert-jest-config-to-cjs.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,IAAI,EACL,MAAM,YAAY,CAAC;AAIpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAA8B,sBAAsB,CAAC,IAAI,EAAE,IAAI,uBA+F9D"}
1
+ {"version":3,"file":"convert-jest-config-to-cjs.d.ts","sourceRoot":"","sources":["../../../../../../packages/jest/src/migrations/update-22-2-0/convert-jest-config-to-cjs.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,IAAI,EACL,MAAM,YAAY,CAAC;AAGpB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAA8B,sBAAsB,CAAC,IAAI,EAAE,IAAI,uBAmF9D"}
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = convertJestConfigToCjs;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const find_plugin_for_config_file_1 = require("@nx/devkit/src/utils/find-plugin-for-config-file");
6
5
  const path_1 = require("path");
7
6
  /**
8
7
  * Migration to convert jest.config.ts files from ESM to CJS syntax for projects
@@ -10,8 +9,6 @@ const path_1 = require("path");
10
9
  * in newer versions (22+, 24+) can cause issues with ESM syntax in .ts files
11
10
  * when the project is configured for CommonJS.
12
11
  *
13
- * This migration only runs if @nx/jest/plugin is registered in nx.json.
14
- *
15
12
  * Conversions:
16
13
  * - `export default { ... }` -> `module.exports = { ... }`
17
14
  * - `import { x } from 'y'` -> `const { x } = require('y')`
@@ -21,24 +18,16 @@ const path_1 = require("path");
21
18
  * - `import.meta`
22
19
  * - top-level `await`
23
20
  *
24
- * Projects with `type: module` in package.json will be warned as they are
25
- * incompatible with @nx/jest/plugin which forces CommonJS resolution.
21
+ * Projects with `type: module` in package.json are skipped and warned about,
22
+ * as they use ESM semantics and don't need the CJS conversion.
26
23
  */
27
24
  async function convertJestConfigToCjs(tree) {
28
- // If @nx/jest/plugin not used, then there will not be any problems with graph construction, which
29
- // is what we're trying to address.
30
- if (!isJestPluginRegistered(tree))
31
- return;
32
25
  const { ast: parseAst, query } = require('@phenomnomnominal/tsquery');
33
26
  const jestConfigPaths = await (0, devkit_1.globAsync)(tree, ['**/jest.config.ts']);
34
27
  const projectsWithEsmOnlyFeatures = [];
35
28
  const projectsWithTypeModule = [];
36
29
  const modifiedFiles = [];
37
30
  for (const configPath of jestConfigPaths) {
38
- // Skip config files that are excluded from the plugin via include/exclude patterns
39
- const pluginRegistration = await (0, find_plugin_for_config_file_1.findPluginForConfigFile)(tree, '@nx/jest/plugin', configPath);
40
- if (!pluginRegistration)
41
- continue;
42
31
  const projectRoot = (0, path_1.dirname)(configPath);
43
32
  const packageJsonPath = (0, devkit_1.joinPathFragments)(projectRoot, 'package.json');
44
33
  const rootPackageJsonPath = 'package.json';
@@ -52,8 +41,8 @@ async function convertJestConfigToCjs(tree) {
52
41
  rootPackageJson = (0, devkit_1.readJson)(tree, rootPackageJsonPath);
53
42
  }
54
43
  const effectiveType = projectPackageJson?.type ?? rootPackageJson?.type ?? 'commonjs'; // CJS is default if missing
55
- // If type is "module", warn user - this is incompatible with @nx/jest/plugin
56
- // Should not be possible, but it's possible that there's a way to get this working that we're unaware of
44
+ // If type is "module", skip conversion: the file already runs under ESM
45
+ // semantics and does not need the CJS rewrite.
57
46
  if (effectiveType === 'module') {
58
47
  projectsWithTypeModule.push(configPath);
59
48
  continue;
@@ -79,9 +68,9 @@ async function convertJestConfigToCjs(tree) {
79
68
  if (hasWarnings) {
80
69
  return () => {
81
70
  if (projectsWithTypeModule.length > 0) {
82
- devkit_1.logger.warn(`The following projects have "type": "module" in their package.json which is incompatible ` +
83
- `with @nx/jest/plugin. Consider removing "type": "module" ` +
84
- `or using a different Jest configuration approach:\n` +
71
+ devkit_1.logger.warn(`The following jest.config.ts files belong to projects with "type": "module" in their package.json ` +
72
+ `and were left as-is. If you use @nx/jest/plugin, it forces CommonJS resolution, so consider ` +
73
+ `removing "type": "module" or using a different Jest configuration approach:\n` +
85
74
  projectsWithTypeModule.map((p) => ` - ${p}`).join('\n'));
86
75
  }
87
76
  if (projectsWithEsmOnlyFeatures.length > 0) {
@@ -134,26 +123,36 @@ function convertImportsToRequire(content, parseAst, query) {
134
123
  content = replaceNode(content, importDecl, requireStatement);
135
124
  continue;
136
125
  }
126
+ // `import type ...` is erased by Node's type-stripping at runtime, so it
127
+ // can remain in the file untouched — this preserves editor/tsc type safety.
128
+ if (importClause.isTypeOnly) {
129
+ continue;
130
+ }
137
131
  const parts = [];
132
+ const typeOnlySpecifiers = [];
138
133
  // Default import: import x from 'module'
139
134
  if (importClause.name) {
140
135
  const defaultName = importClause.name.getText();
141
136
  parts.push(`const ${defaultName} = require('${moduleSpecifier}').default ?? require('${moduleSpecifier}')`);
142
137
  }
143
- // Named imports: import { a, b } from 'module'
144
138
  if (importClause.namedBindings) {
145
139
  if (ts.isNamedImports(importClause.namedBindings)) {
146
- const namedImports = importClause.namedBindings.elements
147
- .map((element) => {
140
+ const valueSpecifiers = [];
141
+ for (const element of importClause.namedBindings.elements) {
148
142
  const name = element.name.getText();
149
143
  const propertyName = element.propertyName?.getText();
150
- if (propertyName) {
151
- return `${propertyName}: ${name}`;
144
+ if (element.isTypeOnly) {
145
+ // Inline `type` modifier: `import { type Foo, bar } from 'x'`.
146
+ // Preserve the type-only portion so type references still resolve.
147
+ typeOnlySpecifiers.push(propertyName ? `${propertyName} as ${name}` : name);
148
+ }
149
+ else {
150
+ valueSpecifiers.push(propertyName ? `${propertyName}: ${name}` : name);
152
151
  }
153
- return name;
154
- })
155
- .join(', ');
156
- parts.push(`const { ${namedImports} } = require('${moduleSpecifier}')`);
152
+ }
153
+ if (valueSpecifiers.length) {
154
+ parts.push(`const { ${valueSpecifiers.join(', ')} } = require('${moduleSpecifier}')`);
155
+ }
157
156
  }
158
157
  else if (ts.isNamespaceImport(importClause.namedBindings)) {
159
158
  // Namespace import: import * as x from 'module'
@@ -161,8 +160,16 @@ function convertImportsToRequire(content, parseAst, query) {
161
160
  parts.push(`const ${namespaceName} = require('${moduleSpecifier}')`);
162
161
  }
163
162
  }
164
- const requireStatement = parts.join(';\n');
165
- content = replaceNode(content, importDecl, requireStatement);
163
+ const replacementParts = [];
164
+ if (typeOnlySpecifiers.length) {
165
+ replacementParts.push(`import type { ${typeOnlySpecifiers.join(', ')} } from '${moduleSpecifier}'`);
166
+ }
167
+ replacementParts.push(...parts);
168
+ if (replacementParts.length === 0) {
169
+ continue;
170
+ }
171
+ const replacement = replacementParts.join(';\n');
172
+ content = replaceNode(content, importDecl, replacement);
166
173
  }
167
174
  return content;
168
175
  }
@@ -191,14 +198,3 @@ function replaceNode(content, node, replacement) {
191
198
  }
192
199
  return content.slice(0, start) + replacement + ';' + content.slice(endPos);
193
200
  }
194
- function isJestPluginRegistered(tree) {
195
- if (!tree.exists('nx.json')) {
196
- return false;
197
- }
198
- const nxJson = (0, devkit_1.readJson)(tree, 'nx.json');
199
- const plugins = nxJson.plugins ?? [];
200
- return plugins.some((plugin) => {
201
- const pluginName = typeof plugin === 'string' ? plugin : plugin.plugin;
202
- return pluginName === '@nx/jest/plugin' || pluginName === '@nx/jest';
203
- });
204
- }
@@ -0,0 +1,3 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function updateSnapshotGuideLink(tree: Tree): Promise<void>;
3
+ //# sourceMappingURL=update-snapshot-guide-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-snapshot-guide-link.d.ts","sourceRoot":"","sources":["../../../../../../packages/jest/src/migrations/update-23-0-0/update-snapshot-guide-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAM/D,wBAA8B,uBAAuB,CAAC,IAAI,EAAE,IAAI,iBA2B/D"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = updateSnapshotGuideLink;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const OLD_HEADER = '// Jest Snapshot v1, https://goo.gl/fbAQLP';
6
+ const NEW_HEADER = '// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing';
7
+ async function updateSnapshotGuideLink(tree) {
8
+ const snapshotFiles = await (0, devkit_1.globAsync)(tree, ['**/__snapshots__/*.snap']);
9
+ for (const snapshotFile of snapshotFiles) {
10
+ const content = tree.read(snapshotFile, 'utf-8');
11
+ if (!content) {
12
+ continue;
13
+ }
14
+ const newlineMatch = content.match(/\r?\n/);
15
+ if (!newlineMatch) {
16
+ continue;
17
+ }
18
+ const newline = newlineMatch[0];
19
+ const firstNewlineIndex = content.indexOf(newline);
20
+ const firstLine = content.slice(0, firstNewlineIndex);
21
+ if (firstLine !== OLD_HEADER) {
22
+ continue;
23
+ }
24
+ const updated = NEW_HEADER + content.slice(firstNewlineIndex);
25
+ tree.write(snapshotFile, updated);
26
+ }
27
+ await (0, devkit_1.formatFiles)(tree);
28
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/jest/src/utils/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAK5E,eAAO,MAAM,cAAc;;;;;;;;;;CAU1B,CAAC;AAEF,QAAA,MAAM,sBAAsB,mBAAoB,CAAC;AAIjD,KAAK,iBAAiB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AACjE,KAAK,mBAAmB,GAAG,MAAM,OAAO,cAAc,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG;KACtB,GAAG,IAAI,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAaxB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,OAiBlC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAclE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG;IACxD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAMA;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAc9D"}
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/jest/src/utils/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAU5E,eAAO,MAAM,cAAc;;;;;;;;;;CAU1B,CAAC;AAEF,QAAA,MAAM,sBAAsB,mBAAoB,CAAC;AAIjD,KAAK,iBAAiB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AACjE,KAAK,mBAAmB,GAAG,MAAM,OAAO,cAAc,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG;KACtB,GAAG,IAAI,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAaxB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,OAiBlC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAclE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG;IACxD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAMA;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAc9D"}
@@ -9,11 +9,16 @@ exports.validateInstalledJestVersion = validateInstalledJestVersion;
9
9
  const devkit_1 = require("@nx/devkit");
10
10
  const semver_1 = require("semver");
11
11
  const nxVersion = require('../../package.json').version;
12
+ // Jest is pinned to 30.3.x because jest-runtime@30.4.0 added a call to
13
+ // `_moduleMocker.clearMocksOnScope()`, which doesn't exist on the
14
+ // jest-mock@29 ModuleMocker that React Native's preset still feeds in
15
+ // (via `@react-native/jest-preset`'s pinned `jest-environment-node@^29.7.0`).
16
+ // Lift this once Meta ships a Jest-30-aware preset on react-native.
12
17
  exports.latestVersions = {
13
18
  nxVersion,
14
- jestVersion: '^30.0.2',
15
- babelJestVersion: '^30.0.2',
16
- jestTypesVersion: '^30.0.0',
19
+ jestVersion: '~30.3.0',
20
+ babelJestVersion: '~30.3.0',
21
+ jestTypesVersion: '~30.0.0',
17
22
  tsJestVersion: '^29.4.0',
18
23
  tslibVersion: '^2.3.0',
19
24
  swcJestVersion: '~0.2.38',