0
# Multi-Project Support
1
2
Utilities for working with Jest multi-project configurations in Nx workspaces. This functionality enables running Jest with multiple project configurations simultaneously, supporting complex monorepo testing scenarios.
3
4
## Capabilities
5
6
### Jest Projects Discovery
7
8
Automatically discover and collect Jest project configurations across the workspace.
9
10
```typescript { .api }
11
/**
12
* Get a list of paths to all Jest configuration files using Nx Jest executor
13
* and @nx/run-commands executor running Jest. Used to configure Jest multi-project support.
14
* @returns Promise resolving to array of Jest configuration file paths
15
*/
16
function getJestProjectsAsync(): Promise<string[]>;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { getJestProjectsAsync } from "@nx/jest";
23
24
// Get all Jest project configurations
25
const jestProjects = await getJestProjectsAsync();
26
console.log(jestProjects);
27
// Output: [
28
// '<rootDir>/apps/web-app/jest.config.ts',
29
// '<rootDir>/libs/shared-ui/jest.config.ts',
30
// '<rootDir>/libs/api-client/jest.config.ts'
31
// ]
32
33
// Use in root Jest configuration for multi-project setup
34
export default async () => ({
35
projects: await getJestProjectsAsync()
36
});
37
38
// Add additional custom projects
39
export default async () => ({
40
projects: [
41
...(await getJestProjectsAsync()),
42
'<rootDir>/tools/custom-testing/jest.config.ts'
43
]
44
});
45
```
46
47
### Multi-Project Configuration
48
49
The function integrates with Nx project graph to discover Jest configurations:
50
51
```typescript
52
// Root jest.config.ts example using getJestProjectsAsync
53
import { getJestProjectsAsync } from '@nx/jest';
54
55
export default async () => ({
56
projects: await getJestProjectsAsync(),
57
// Global configuration for all projects
58
coverageReporters: ['html', 'lcov', 'text-summary'],
59
collectCoverageFrom: [
60
'**/*.{js,jsx,ts,tsx}',
61
'!**/*.d.ts',
62
'!**/node_modules/**',
63
],
64
});
65
```
66
67
### Project Detection Logic
68
69
The function discovers Jest projects by analyzing:
70
71
1. **Nx Jest Executor**: Projects using `@nx/jest:jest` or `@nrwl/jest:jest` executor
72
2. **Run Commands Executor**: Projects using `nx:run-commands` executor that run Jest
73
3. **Configuration Files**: Direct analysis of Jest configuration file paths
74
75
**Detection Examples:**
76
77
```json
78
// Detected from project.json with Jest executor
79
{
80
"targets": {
81
"test": {
82
"executor": "@nx/jest:jest",
83
"options": {
84
"jestConfig": "apps/my-app/jest.config.ts"
85
}
86
}
87
}
88
}
89
90
// Detected from run-commands executor
91
{
92
"targets": {
93
"test": {
94
"executor": "nx:run-commands",
95
"options": {
96
"command": "jest --config=apps/my-app/jest.config.ts"
97
}
98
}
99
}
100
}
101
```
102
103
### Path Resolution
104
105
The function returns configuration paths in Jest-compatible format:
106
107
```typescript
108
// Internal path processing
109
function getJestConfigProjectPath(projectJestConfigPath: string): string {
110
return join('<rootDir>', projectJestConfigPath);
111
}
112
113
// Example transformation:
114
// Input: "apps/web-app/jest.config.ts"
115
// Output: "<rootDir>/apps/web-app/jest.config.ts"
116
```
117
118
### Integration with Nx Project Graph
119
120
The function leverages Nx's project graph for efficient project discovery:
121
122
```typescript { .api }
123
interface ProjectGraph {
124
nodes: Record<string, ProjectGraphNode>;
125
dependencies: Record<string, ProjectGraphDependency[]>;
126
}
127
128
interface ProjectGraphNode {
129
name: string;
130
type: string;
131
data: ProjectConfiguration;
132
}
133
```
134
135
**Project Graph Integration:**
136
137
```typescript
138
// Internal implementation pattern
139
export async function getJestProjectsAsync() {
140
const graph = await createProjectGraphAsync({
141
exitOnError: false,
142
resetDaemonClient: true,
143
});
144
145
const jestConfigurations = new Set<string>();
146
147
for (const node of Object.values(graph.nodes)) {
148
const projectConfig = node.data;
149
if (!projectConfig.targets) continue;
150
151
for (const targetConfiguration of Object.values(projectConfig.targets)) {
152
// Process Jest executors and run-commands
153
if (targetConfiguration.executor === '@nx/jest:jest') {
154
collectJestConfigFromJestExecutor(targetConfiguration, jestConfigurations);
155
} else if (targetConfiguration.executor === 'nx:run-commands') {
156
collectJestConfigFromRunCommandsExecutor(
157
targetConfiguration,
158
projectConfig.root,
159
jestConfigurations
160
);
161
}
162
}
163
}
164
165
return Array.from(jestConfigurations);
166
}
167
```
168
169
### Command Parsing for Run Commands
170
171
For `nx:run-commands` executors, the function parses Jest commands to extract configuration paths:
172
173
```typescript
174
// Example run-commands target
175
{
176
"executor": "nx:run-commands",
177
"options": {
178
"command": "jest --config libs/my-lib/jest.config.ts --passWithNoTests"
179
}
180
}
181
182
// Parsed to extract: "libs/my-lib/jest.config.ts"
183
```
184
185
### Common Multi-Project Patterns
186
187
#### Workspace-Wide Testing
188
189
```typescript
190
// jest.config.ts at workspace root
191
import { getJestProjectsAsync } from '@nx/jest';
192
193
export default async () => ({
194
projects: await getJestProjectsAsync(),
195
// Global settings apply to all projects
196
verbose: false,
197
collectCoverageFrom: [
198
'**/*.{js,jsx,ts,tsx}',
199
'!**/*.d.ts',
200
],
201
coverageReporters: ['text-summary', 'html'],
202
coverageDirectory: 'coverage'
203
});
204
```
205
206
#### Selective Project Testing
207
208
```typescript
209
// Filter projects based on specific criteria
210
export default async () => {
211
const allProjects = await getJestProjectsAsync();
212
213
// Only include library projects
214
const libProjects = allProjects.filter(path =>
215
path.includes('/libs/')
216
);
217
218
return {
219
projects: libProjects
220
};
221
};
222
```
223
224
#### Mixed Configuration
225
226
```typescript
227
// Combine auto-discovered projects with manual configurations
228
export default async () => ({
229
projects: [
230
...(await getJestProjectsAsync()),
231
// Add custom test configurations
232
'<rootDir>/tools/integration-tests/jest.config.ts',
233
'<rootDir>/e2e/jest.config.ts'
234
],
235
globalSetup: '<rootDir>/tools/jest-global-setup.ts',
236
globalTeardown: '<rootDir>/tools/jest-global-teardown.ts'
237
});
238
```
239
240
### Performance Considerations
241
242
- **Caching**: Project graph is cached for performance
243
- **Lazy Evaluation**: Projects are discovered only when needed
244
- **Error Handling**: Failed project graph creation doesn't block execution
245
- **Deduplication**: Duplicate configuration paths are automatically removed
246
247
### Migration Support
248
249
The function supports migration from legacy patterns:
250
251
```typescript
252
// Legacy manual project list
253
export default {
254
projects: [
255
'<rootDir>/apps/app1/jest.config.ts',
256
'<rootDir>/apps/app2/jest.config.ts',
257
'<rootDir>/libs/lib1/jest.config.ts'
258
]
259
};
260
261
// Migrated to automatic discovery
262
export default async () => ({
263
projects: await getJestProjectsAsync()
264
});
265
```
266
267
### Error Handling
268
269
The function includes robust error handling:
270
271
- **Graph Creation Errors**: Continues execution with empty project list
272
- **Invalid Configurations**: Skips malformed Jest configurations
273
- **Missing Files**: Handles references to non-existent configuration files
274
- **Permission Errors**: Gracefully handles file system access issues
275
276
### TypeScript Support
277
278
Full TypeScript support with proper type definitions:
279
280
```typescript
281
import type { Config } from 'jest';
282
import { getJestProjectsAsync } from '@nx/jest';
283
284
const config: Config = {
285
projects: await getJestProjectsAsync(),
286
// Additional configuration with full type safety
287
};
288
289
export default config;
290
```