@nx/jest 19.4.0-beta.0 → 19.4.0-beta.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/generators.json +6 -1
- package/package.json +4 -4
- package/src/generators/convert-to-inferred/convert-to-inferred.d.ts +7 -0
- package/src/generators/convert-to-inferred/convert-to-inferred.js +207 -0
- package/src/generators/convert-to-inferred/schema.json +19 -0
- package/src/plugins/plugin.js +2 -0
package/generators.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"init": {
|
|
6
6
|
"factory": "./src/generators/init/init#jestInitGeneratorInternal",
|
|
7
7
|
"schema": "./src/generators/init/schema.json",
|
|
8
|
-
"description": "Initialize the `@
|
|
8
|
+
"description": "Initialize the `@nx/jest` plugin.",
|
|
9
9
|
"aliases": ["ng-add"],
|
|
10
10
|
"hidden": true
|
|
11
11
|
},
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"schema": "./src/generators/configuration/schema.json",
|
|
15
15
|
"description": "Add Jest configuration to a project.",
|
|
16
16
|
"hidden": true
|
|
17
|
+
},
|
|
18
|
+
"convert-to-inferred": {
|
|
19
|
+
"factory": "./src/generators/convert-to-inferred/convert-to-inferred",
|
|
20
|
+
"schema": "./src/generators/convert-to-inferred/schema.json",
|
|
21
|
+
"description": "Convert existing Jest project(s) using `@nx/jest:jest` executor to use `@nx/jest/plugin`."
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/jest",
|
|
3
|
-
"version": "19.4.0-beta.
|
|
3
|
+
"version": "19.4.0-beta.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": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@jest/reporters": "^29.4.1",
|
|
39
39
|
"@jest/test-result": "^29.4.1",
|
|
40
|
-
"@nx/devkit": "19.4.0-beta.
|
|
41
|
-
"@nx/js": "19.4.0-beta.
|
|
40
|
+
"@nx/devkit": "19.4.0-beta.2",
|
|
41
|
+
"@nx/js": "19.4.0-beta.2",
|
|
42
42
|
"@phenomnomnominal/tsquery": "~5.0.1",
|
|
43
43
|
"chalk": "^4.1.0",
|
|
44
44
|
"identity-obj-proxy": "3.0.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"resolve.exports": "1.1.0",
|
|
50
50
|
"tslib": "^2.3.0",
|
|
51
51
|
"yargs-parser": "21.1.1",
|
|
52
|
-
"@nrwl/jest": "19.4.0-beta.
|
|
52
|
+
"@nrwl/jest": "19.4.0-beta.2"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertToInferred = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const executor_to_plugin_migrator_1 = require("@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator");
|
|
6
|
+
const plugin_migration_utils_1 = require("@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils");
|
|
7
|
+
const jest_config_1 = require("jest-config");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const plugin_1 = require("../../plugins/plugin");
|
|
10
|
+
const config_file_1 = require("../../utils/config/config-file");
|
|
11
|
+
async function convertToInferred(tree, options) {
|
|
12
|
+
const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
|
|
13
|
+
const migratedProjects = await (0, executor_to_plugin_migrator_1.migrateProjectExecutorsToPlugin)(tree, projectGraph, '@nx/jest/plugin', plugin_1.createNodesV2, { targetName: 'test' }, [
|
|
14
|
+
{
|
|
15
|
+
executors: ['@nx/jest:jest', '@nrwl/jest:jest'],
|
|
16
|
+
postTargetTransformer,
|
|
17
|
+
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
|
18
|
+
},
|
|
19
|
+
], options.project);
|
|
20
|
+
if (migratedProjects.size === 0) {
|
|
21
|
+
throw new Error('Could not find any targets to migrate.');
|
|
22
|
+
}
|
|
23
|
+
if (!options.skipFormat) {
|
|
24
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.convertToInferred = convertToInferred;
|
|
28
|
+
async function postTargetTransformer(target, tree, projectDetails, inferredTarget) {
|
|
29
|
+
const jestConfigPath = config_file_1.jestConfigExtensions
|
|
30
|
+
.map((ext) => `jest.config.${ext}`)
|
|
31
|
+
.find((configFileName) => tree.exists(node_path_1.posix.join(projectDetails.root, configFileName)));
|
|
32
|
+
if (target.options) {
|
|
33
|
+
await updateOptionsObject(target.options, projectDetails.root, tree.root, jestConfigPath);
|
|
34
|
+
}
|
|
35
|
+
if (target.configurations) {
|
|
36
|
+
for (const [configName, config] of Object.entries(target.configurations)) {
|
|
37
|
+
await updateConfigurationObject(config, projectDetails.root, tree.root, jestConfigPath);
|
|
38
|
+
if (!Object.keys(config).length) {
|
|
39
|
+
delete target.configurations[configName];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!Object.keys(target.configurations).length) {
|
|
43
|
+
delete target.defaultConfiguration;
|
|
44
|
+
delete target.configurations;
|
|
45
|
+
}
|
|
46
|
+
if ('defaultConfiguration' in target &&
|
|
47
|
+
!target.configurations?.[target.defaultConfiguration]) {
|
|
48
|
+
delete target.defaultConfiguration;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (target.outputs) {
|
|
52
|
+
(0, plugin_migration_utils_1.processTargetOutputs)(target, [], inferredTarget, {
|
|
53
|
+
projectName: projectDetails.projectName,
|
|
54
|
+
projectRoot: projectDetails.root,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return target;
|
|
58
|
+
}
|
|
59
|
+
exports.default = convertToInferred;
|
|
60
|
+
async function updateOptionsObject(targetOptions, projectRoot, workspaceRoot, defaultJestConfigPath) {
|
|
61
|
+
const jestConfigPath = targetOptions.jestConfig ?? defaultJestConfigPath;
|
|
62
|
+
// inferred targets are only identified after known files that Jest would
|
|
63
|
+
// pick up, so we can safely remove the config options
|
|
64
|
+
delete targetOptions.jestConfig;
|
|
65
|
+
delete targetOptions.config;
|
|
66
|
+
await updateOptions(targetOptions, projectRoot, workspaceRoot, jestConfigPath);
|
|
67
|
+
}
|
|
68
|
+
async function updateConfigurationObject(targetOptions, projectRoot, workspaceRoot, defaultJestConfigPath) {
|
|
69
|
+
const jestConfigPath = targetOptions.jestConfig ?? defaultJestConfigPath;
|
|
70
|
+
if (targetOptions.jestConfig) {
|
|
71
|
+
targetOptions.config = (0, plugin_migration_utils_1.toProjectRelativePath)(targetOptions.jestConfig, projectRoot);
|
|
72
|
+
delete targetOptions.jestConfig;
|
|
73
|
+
}
|
|
74
|
+
else if (targetOptions.config) {
|
|
75
|
+
targetOptions.config = (0, plugin_migration_utils_1.toProjectRelativePath)(targetOptions.config, projectRoot);
|
|
76
|
+
}
|
|
77
|
+
await updateOptions(targetOptions, projectRoot, workspaceRoot, jestConfigPath);
|
|
78
|
+
}
|
|
79
|
+
async function updateOptions(targetOptions, projectRoot, workspaceRoot, jestConfigPath) {
|
|
80
|
+
// deprecated and unused
|
|
81
|
+
delete targetOptions.tsConfig;
|
|
82
|
+
if ('codeCoverage' in targetOptions) {
|
|
83
|
+
targetOptions.coverage = targetOptions.codeCoverage;
|
|
84
|
+
delete targetOptions.codeCoverage;
|
|
85
|
+
}
|
|
86
|
+
const testPathPatterns = [];
|
|
87
|
+
if ('testFile' in targetOptions) {
|
|
88
|
+
testPathPatterns.push(toProjectRelativeRegexPath(targetOptions.testFile, projectRoot));
|
|
89
|
+
delete targetOptions.testFile;
|
|
90
|
+
}
|
|
91
|
+
if ('testPathPattern' in targetOptions) {
|
|
92
|
+
testPathPatterns.push(...targetOptions.testPathPattern.map((pattern) => toProjectRelativeRegexPath(pattern, projectRoot)));
|
|
93
|
+
}
|
|
94
|
+
if (testPathPatterns.length > 1) {
|
|
95
|
+
targetOptions.testPathPattern = `\"${testPathPatterns.join('|')}\"`;
|
|
96
|
+
}
|
|
97
|
+
else if (testPathPatterns.length === 1) {
|
|
98
|
+
targetOptions.testPathPattern = testPathPatterns[0];
|
|
99
|
+
}
|
|
100
|
+
if ('testPathIgnorePatterns' in targetOptions) {
|
|
101
|
+
if (targetOptions.testPathIgnorePatterns.length > 1) {
|
|
102
|
+
targetOptions.testPathIgnorePatterns = `\"${targetOptions.testPathIgnorePatterns
|
|
103
|
+
.map((pattern) => toProjectRelativeRegexPath(pattern, projectRoot))
|
|
104
|
+
.join('|')}\"`;
|
|
105
|
+
}
|
|
106
|
+
else if (targetOptions.testPathIgnorePatterns.length === 1) {
|
|
107
|
+
targetOptions.testPathIgnorePatterns = toProjectRelativeRegexPath(targetOptions.testPathIgnorePatterns[0], projectRoot);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if ('testMatch' in targetOptions) {
|
|
111
|
+
targetOptions.testMatch = targetOptions.testMatch
|
|
112
|
+
.map((pattern) => `"${toProjectRelativeGlobPath(pattern, projectRoot)}"`)
|
|
113
|
+
.join(' ');
|
|
114
|
+
}
|
|
115
|
+
if ('findRelatedTests' in targetOptions) {
|
|
116
|
+
// the executor accepts a comma-separated string, while jest accepts a space-separated string
|
|
117
|
+
const parsedSourceFiles = targetOptions.findRelatedTests
|
|
118
|
+
.split(',')
|
|
119
|
+
.map((s) => (0, plugin_migration_utils_1.toProjectRelativePath)(s.trim(), projectRoot))
|
|
120
|
+
.join(' ');
|
|
121
|
+
targetOptions.args = [`--findRelatedTests ${parsedSourceFiles}`];
|
|
122
|
+
delete targetOptions.findRelatedTests;
|
|
123
|
+
}
|
|
124
|
+
if ('setupFile' in targetOptions) {
|
|
125
|
+
const setupFiles = await processSetupFiles(targetOptions.setupFile, targetOptions.setupFilesAfterEnv, projectRoot, workspaceRoot, jestConfigPath);
|
|
126
|
+
if (setupFiles.length > 1) {
|
|
127
|
+
targetOptions.setupFilesAfterEnv = setupFiles
|
|
128
|
+
.map((sf) => `"${sf}"`)
|
|
129
|
+
.join(' ');
|
|
130
|
+
}
|
|
131
|
+
else if (setupFiles.length === 1) {
|
|
132
|
+
targetOptions.setupFilesAfterEnv = setupFiles[0];
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// if there are no setup files, it means they are already defined in the
|
|
136
|
+
// jest config, so we can remove the option
|
|
137
|
+
delete targetOptions.setupFilesAfterEnv;
|
|
138
|
+
}
|
|
139
|
+
delete targetOptions.setupFile;
|
|
140
|
+
}
|
|
141
|
+
if ('outputFile' in targetOptions) {
|
|
142
|
+
// update the output file to be relative to the project root
|
|
143
|
+
targetOptions.outputFile = (0, plugin_migration_utils_1.toProjectRelativePath)(targetOptions.outputFile, projectRoot);
|
|
144
|
+
}
|
|
145
|
+
if ('coverageDirectory' in targetOptions) {
|
|
146
|
+
// update the coverage directory to be relative to the project root
|
|
147
|
+
targetOptions.coverageDirectory = (0, plugin_migration_utils_1.toProjectRelativePath)(targetOptions.coverageDirectory, projectRoot);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function processSetupFiles(setupFile, setupFilesAfterEnv, projectRoot, workspaceRoot, jestConfigPath) {
|
|
151
|
+
// the jest executor merges the setupFile with the setupFilesAfterEnv, so
|
|
152
|
+
// to keep the task working as before we resolve the setupFilesAfterEnv
|
|
153
|
+
// from the options or the jest config and add the setupFile to it
|
|
154
|
+
// https://github.com/nrwl/nx/blob/bdd3375256613340899f649eb800d22abcc9f507/packages/jest/src/executors/jest/jest.impl.ts#L107-L113
|
|
155
|
+
const configSetupFilesAfterEnv = [];
|
|
156
|
+
if (jestConfigPath) {
|
|
157
|
+
const jestConfig = await (0, jest_config_1.readConfig)({ setupFilesAfterEnv }, (0, node_path_1.join)(workspaceRoot, jestConfigPath));
|
|
158
|
+
if (jestConfig.projectConfig.setupFilesAfterEnv) {
|
|
159
|
+
configSetupFilesAfterEnv.push(...jestConfig.projectConfig.setupFilesAfterEnv.map((file) => (0, plugin_migration_utils_1.toProjectRelativePath)(file, projectRoot)));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!configSetupFilesAfterEnv.length) {
|
|
163
|
+
return [(0, plugin_migration_utils_1.toProjectRelativePath)(setupFile, projectRoot)];
|
|
164
|
+
}
|
|
165
|
+
if (isSetupFileInConfig(configSetupFilesAfterEnv, setupFile, projectRoot, workspaceRoot)) {
|
|
166
|
+
// the setupFile is already included in the setupFilesAfterEnv
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
return [
|
|
170
|
+
...configSetupFilesAfterEnv,
|
|
171
|
+
(0, plugin_migration_utils_1.toProjectRelativePath)(setupFile, projectRoot),
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
function isSetupFileInConfig(setupFilesAfterEnv, setupFile, projectRoot, workspaceRoot) {
|
|
175
|
+
const normalizePath = (f) => f.startsWith('<rootDir>')
|
|
176
|
+
? node_path_1.posix.join(workspaceRoot, projectRoot, f.slice('<rootDir>'.length))
|
|
177
|
+
: node_path_1.posix.join(workspaceRoot, projectRoot, f);
|
|
178
|
+
const normalizedSetupFiles = new Set(setupFilesAfterEnv.map(normalizePath));
|
|
179
|
+
return normalizedSetupFiles.has(normalizePath((0, plugin_migration_utils_1.toProjectRelativePath)(setupFile, projectRoot)));
|
|
180
|
+
}
|
|
181
|
+
function toProjectRelativeRegexPath(path, projectRoot) {
|
|
182
|
+
if (projectRoot === '.') {
|
|
183
|
+
// workspace and project root are the same, keep the path as is
|
|
184
|
+
return path;
|
|
185
|
+
}
|
|
186
|
+
const normalizedRoot = (0, node_path_1.normalize)(projectRoot);
|
|
187
|
+
if (new RegExp(`^(?:\\.[\\/\\\\])?${normalizedRoot}(?:[\\/\\\\])?$`).test(path)) {
|
|
188
|
+
// path includes everything inside project root
|
|
189
|
+
return '.*';
|
|
190
|
+
}
|
|
191
|
+
const normalizedPath = (0, node_path_1.normalize)(path);
|
|
192
|
+
const startWithProjectRootRegex = new RegExp(`^(?:\\.[\\/\\\\])?${normalizedRoot}[\\/\\\\]`);
|
|
193
|
+
return startWithProjectRootRegex.test(normalizedPath)
|
|
194
|
+
? normalizedPath.replace(startWithProjectRootRegex, '')
|
|
195
|
+
: path;
|
|
196
|
+
}
|
|
197
|
+
function toProjectRelativeGlobPath(path, projectRoot) {
|
|
198
|
+
if (projectRoot === '.') {
|
|
199
|
+
// workspace and project root are the same, keep the path as is
|
|
200
|
+
return path;
|
|
201
|
+
}
|
|
202
|
+
// globs use forward slashes, so we make sure to normalize the path
|
|
203
|
+
const normalizedRoot = node_path_1.posix.normalize(projectRoot);
|
|
204
|
+
return path
|
|
205
|
+
.replace(new RegExp(`\/${normalizedRoot}\/`), '/')
|
|
206
|
+
.replace(/\*\*\/\*\*/g, '**');
|
|
207
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxJestConvertToInferred",
|
|
4
|
+
"description": "Convert existing Jest project(s) using `@nx/jest:jest` executor to use `@nx/jest/plugin`.",
|
|
5
|
+
"title": "Convert Jest project from executor to plugin",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"project": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "The project to convert from using the `@nx/jest:jest` executor to use `@nx/jest/plugin`. If not provided, all projects using the `@nx/jest:jest` executor will be converted.",
|
|
11
|
+
"x-priority": "important"
|
|
12
|
+
},
|
|
13
|
+
"skipFormat": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"description": "Whether to format files.",
|
|
16
|
+
"default": false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/plugins/plugin.js
CHANGED
|
@@ -144,6 +144,7 @@ async function buildJestTargets(configFilePath, projectRoot, options, context) {
|
|
|
144
144
|
metadata: {
|
|
145
145
|
technologies: ['jest'],
|
|
146
146
|
description: 'Run Jest Tests in CI',
|
|
147
|
+
nonAtomizedTarget: options.targetName,
|
|
147
148
|
},
|
|
148
149
|
};
|
|
149
150
|
targetGroup.push(options.ciTargetName);
|
|
@@ -162,6 +163,7 @@ async function buildJestTargets(configFilePath, projectRoot, options, context) {
|
|
|
162
163
|
metadata: {
|
|
163
164
|
technologies: ['jest'],
|
|
164
165
|
description: `Run Jest Tests in ${relativePath}`,
|
|
166
|
+
nonAtomizedTarget: options.targetName,
|
|
165
167
|
},
|
|
166
168
|
};
|
|
167
169
|
targetGroup.push(targetName);
|