feat(testing): remove deprecated getJestProjects (#30844)

Remove the deprecated function `getJestProjects`.

BREAKING CHANGE: The previously deprecated `getJestProjects` function
was removed in favor of `getJestProjectsAsync`.
This commit is contained in:
Leosvel Pérez Espinosa 2025-04-25 15:12:13 +02:00 committed by GitHub
parent 69ea6327d3
commit c0aa245d9c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 432 additions and 397 deletions

View File

@ -2429,8 +2429,18 @@
} }
}, },
"migrations": { "migrations": {
"/nx-api/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync-v21": {
"description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync-v21.json",
"hidden": false,
"name": "replace-getJestProjects-with-getJestProjectsAsync-v21",
"version": "21.0.0-beta.9",
"originalFilePath": "/packages/jest",
"path": "/nx-api/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync-v21",
"type": "migration"
},
"/nx-api/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync": { "/nx-api/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync": {
"description": "replace getJestProjects with getJestProjectsAsync", "description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync.json", "file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync.json",
"hidden": false, "hidden": false,
"name": "replace-getJestProjects-with-getJestProjectsAsync", "name": "replace-getJestProjects-with-getJestProjectsAsync",

View File

@ -2413,7 +2413,17 @@
], ],
"migrations": [ "migrations": [
{ {
"description": "replace getJestProjects with getJestProjectsAsync", "description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync-v21.json",
"hidden": false,
"name": "replace-getJestProjects-with-getJestProjectsAsync-v21",
"version": "21.0.0-beta.9",
"originalFilePath": "/packages/jest",
"path": "jest/migrations/replace-getJestProjects-with-getJestProjectsAsync-v21",
"type": "migration"
},
{
"description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync.json", "file": "generated/packages/jest/migrations/replace-getJestProjects-with-getJestProjectsAsync.json",
"hidden": false, "hidden": false,
"name": "replace-getJestProjects-with-getJestProjectsAsync", "name": "replace-getJestProjects-with-getJestProjectsAsync",

View File

@ -0,0 +1,13 @@
{
"name": "replace-getJestProjects-with-getJestProjectsAsync-v21",
"cli": "nx",
"version": "21.0.0-beta.9",
"description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"implementation": "/packages/jest/src/migrations/update-21-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts",
"aliases": [],
"hidden": false,
"path": "/packages/jest",
"schema": null,
"type": "migration",
"examplesFile": "#### Replace Usage of `getJestProjects` with `getJestProjectsAsync`\n\nReplaces the usage of the removed `getJestProjects` function with the `getJestProjectsAsync` function.\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjects } from '@nx/jest';\n\nexport default {\n projects: getJestProjects(),\n};\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjectsAsync } from '@nx/jest';\n\nexport default async () => ({\n projects: await getJestProjectsAsync(),\n});\n```\n\n{% /tab %}\n{% /tabs %}\n"
}

View File

@ -2,12 +2,12 @@
"name": "replace-getJestProjects-with-getJestProjectsAsync", "name": "replace-getJestProjects-with-getJestProjectsAsync",
"cli": "nx", "cli": "nx",
"version": "20.0.0-beta.5", "version": "20.0.0-beta.5",
"description": "replace getJestProjects with getJestProjectsAsync", "description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"implementation": "/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts", "implementation": "/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts",
"aliases": [], "aliases": [],
"hidden": false, "hidden": false,
"path": "/packages/jest", "path": "/packages/jest",
"schema": null, "schema": null,
"type": "migration", "type": "migration",
"examplesFile": "#### Replace getJestProjects with getJestProjectsAsync\n\nReplace getJestProjects with getJestProjectsAsync\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjects } from '@nx/jest';\n\nexport default {\n projects: getJestProjects(),\n};\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjectsAsync } from '@nx/jest';\n\nexport default async () => ({\n projects: await getJestProjectsAsync(),\n});\n```\n\n{% /tab %}\n{% /tabs %}\n" "examplesFile": "#### Replace Usage of `getJestProjects` with `getJestProjectsAsync`\n\nReplaces the usage of the deprecated `getJestProjects` function with the `getJestProjectsAsync` function.\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjects } from '@nx/jest';\n\nexport default {\n projects: getJestProjects(),\n};\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```ts {% fileName=\"jest.config.ts\" %}\nimport { getJestProjectsAsync } from '@nx/jest';\n\nexport default async () => ({\n projects: await getJestProjectsAsync(),\n});\n```\n\n{% /tab %}\n{% /tabs %}\n"
} }

View File

@ -11,8 +11,4 @@ export {
} from './src/utils/config/update-config'; } from './src/utils/config/update-config';
export { jestConfigObjectAst } from './src/utils/config/functions'; export { jestConfigObjectAst } from './src/utils/config/functions';
export { jestInitGenerator } from './src/generators/init/init'; export { jestInitGenerator } from './src/generators/init/init';
export { export { getJestProjectsAsync } from './src/utils/config/get-jest-projects';
getJestProjects,
getJestProjectsAsync,
getNestedJestProjects,
} from './src/utils/config/get-jest-projects';

View File

@ -8,8 +8,14 @@
"replace-getJestProjects-with-getJestProjectsAsync": { "replace-getJestProjects-with-getJestProjectsAsync": {
"cli": "nx", "cli": "nx",
"version": "20.0.0-beta.5", "version": "20.0.0-beta.5",
"description": "replace getJestProjects with getJestProjectsAsync", "description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"implementation": "./src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync" "implementation": "./src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync"
},
"replace-getJestProjects-with-getJestProjectsAsync-v21": {
"cli": "nx",
"version": "21.0.0-beta.9",
"description": "Replace usage of `getJestProjects` with `getJestProjectsAsync`.",
"implementation": "./src/migrations/update-21-0-0/replace-getJestProjects-with-getJestProjectsAsync"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {

View File

@ -75,11 +75,11 @@ describe('createJestConfig', () => {
}, },
}); });
const expected = ` const expected = `
import { getJestProjects } from '@nx/jest'; import { getJestProjectsAsync } from '@nx/jest';
export default { export default async () => ({
projects: getJestProjects(), projects: await getJestProjectsAsync(),
extraThing: "Goes Here" extraThing: "Goes Here"
} });
`; `;
tree.write('jest.config.ts', expected); tree.write('jest.config.ts', expected);

View File

@ -1,37 +0,0 @@
import { readProjectConfiguration, type Tree } from '@nx/devkit';
import { findRootJestConfig } from '../../../utils/config/config-file';
import { addPropertyToJestConfig } from '../../../utils/config/update-config';
import type { NormalizedJestProjectSchema } from '../schema';
function isUsingUtilityFunction(host: Tree) {
const rootConfig = findRootJestConfig(host);
if (!rootConfig) {
return false;
}
const rootConfigContent = host.read(rootConfig, 'utf-8');
return (
rootConfigContent.includes('getJestProjects()') ||
rootConfigContent.includes('getJestProjectsAsync()')
);
}
export function updateJestConfig(
host: Tree,
options: NormalizedJestProjectSchema
) {
if (isUsingUtilityFunction(host)) {
return;
}
const project = readProjectConfiguration(host, options.project);
const rootConfig = findRootJestConfig(host);
if (rootConfig) {
addPropertyToJestConfig(
host,
findRootJestConfig(host),
'projects',
`<rootDir>/${project.root}`
);
}
}

View File

@ -1,6 +1,6 @@
#### Replace getJestProjects with getJestProjectsAsync #### Replace Usage of `getJestProjects` with `getJestProjectsAsync`
Replace getJestProjects with getJestProjectsAsync Replaces the usage of the deprecated `getJestProjects` function with the `getJestProjectsAsync` function.
#### Sample Code Changes #### Sample Code Changes

View File

@ -0,0 +1,30 @@
#### Replace Usage of `getJestProjects` with `getJestProjectsAsync`
Replaces the usage of the removed `getJestProjects` function with the `getJestProjectsAsync` function.
#### Sample Code Changes
{% tabs %}
{% tab label="Before" %}
```ts {% fileName="jest.config.ts" %}
import { getJestProjects } from '@nx/jest';
export default {
projects: getJestProjects(),
};
```
{% /tab %}
{% tab label="After" %}
```ts {% fileName="jest.config.ts" %}
import { getJestProjectsAsync } from '@nx/jest';
export default async () => ({
projects: await getJestProjectsAsync(),
});
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,191 @@
import { Tree } from '@nx/devkit';
import { createTree } from '@nx/devkit/testing';
import update from './replace-getJestProjects-with-getJestProjectsAsync';
describe('replace-getJestProjects-with-getJestProjectsAsync', () => {
let tree: Tree;
beforeEach(() => {
tree = createTree();
});
it('should replace getJestProjects with getJestProjectsAsync using `require`', async () => {
tree.write(
'jest.config.ts',
`
const { getJestProjects } = require('@nx/jest');
module.exports = {
projects: getJestProjects(),
};
`
);
await update(tree);
const updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
const { getJestProjectsAsync } = require('@nx/jest');
module.exports = async () => ({
projects: await getJestProjectsAsync(),
});
"
`);
});
it('should replace getJestProjects with getJestProjectsAsync using `import`', async () => {
tree.write(
'jest.config.ts',
`
import { getJestProjects } from '@nx/jest';
export default {
projects: getJestProjects(),
};
`
);
await update(tree);
const updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
import { getJestProjectsAsync } from '@nx/jest';
export default async () => ({
projects: await getJestProjectsAsync(),
});
"
`);
});
it('should replace getJestProjects with getJestProjectsAsync using `require` with `export default`', async () => {
tree.write(
'jest.config.ts',
`
const { getJestProjects } = require('@nx/jest');
export default {
projects: getJestProjects(),
};
`
);
await update(tree);
const updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
const { getJestProjectsAsync } = require('@nx/jest');
export default async () => ({
projects: await getJestProjectsAsync(),
});
"
`);
});
it('should replace getJestProjects with getJestProjectsAsync using `import` with `module.exports`', async () => {
tree.write(
'jest.config.ts',
`
import { getJestProjects } from '@nx/jest';
module.exports = {
projects: getJestProjects(),
};
`
);
await update(tree);
const updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
import { getJestProjectsAsync } from '@nx/jest';
module.exports = async () => ({
projects: await getJestProjectsAsync(),
});
"
`);
});
it('should replace getJestProjects with getJestProjectsAsync with additional properties', async () => {
tree.write(
'jest.config.ts',
`
const { getJestProjects } = require('@nx/jest');
module.exports = {
projects: getJestProjects(),
filename: __filename,
env: process.env,
dirname: __dirname
};
`
);
await update(tree);
const updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
const { getJestProjectsAsync } = require('@nx/jest');
module.exports = async () => ({
projects: await getJestProjectsAsync(),
filename: __filename,
env: process.env,
dirname: __dirname
});
"
`);
});
it('should not update config that are not in supported format', async () => {
// Users don't tend to update the root jest config file since it's only meant to be able to run
// `jest` command from the root of the repo. If the AST doesn't match what we generate
// then bail on the update. Users will still see that `getJestProjects` is deprecated when
// viewing the file.
tree.write(
'jest.config.ts',
`
import { getJestProjects } from '@nx/jest';
const obj = {
projects: getJestProjects(),
};
export default obj
`
);
await update(tree);
let updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
import { getJestProjects } from '@nx/jest';
const obj = {
projects: getJestProjects(),
};
export default obj
"
`);
tree.write(
'jest.config.ts',
`
const { getJestProjects } = require('@nx/jest');
const obj = {
projects: getJestProjects(),
};
module.exports = obj;
`
);
await update(tree);
updatedJestConfig = tree.read('jest.config.ts')?.toString();
expect(updatedJestConfig).toMatchInlineSnapshot(`
"
const { getJestProjects } = require('@nx/jest');
const obj = {
projects: getJestProjects(),
};
module.exports = obj;
"
`);
});
});

View File

@ -0,0 +1,140 @@
// go through the jest.config files
// see if it imports from @nx/jest and if it uses getJestProjects
// replace getJestProjects with getJestProjectsAsync
import { globAsync, Tree } from '@nx/devkit';
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
import {
BinaryExpression,
ExpressionStatement,
ExportAssignment,
} from 'typescript';
let tsModule: typeof import('typescript');
export default async function update(tree: Tree) {
if (!tsModule) {
tsModule = ensureTypescript();
}
const jestConfigPaths = await globAsync(tree, [
'**/jest.config.{cjs,mjs,js,cts,mts,ts}',
]);
jestConfigPaths.forEach((jestConfigPath) => {
const oldContent = tree.read(jestConfigPath).toString();
if (oldContent?.includes('projects: getJestProjects()')) {
let sourceFile = tsModule.createSourceFile(
jestConfigPath,
oldContent,
tsModule.ScriptTarget.Latest,
true
);
// find `require('@nx/jest')` or `import { getJestProjects } from '@nx/jest`
const requireStatement = sourceFile.statements.find(
(statement) =>
tsModule.isVariableStatement(statement) &&
statement.declarationList.declarations.some(
(declaration) =>
tsModule.isCallExpression(declaration.initializer) &&
tsModule.isIdentifier(declaration.initializer.expression) &&
declaration.initializer.expression.escapedText === 'require' &&
tsModule.isStringLiteral(declaration.initializer.arguments[0]) &&
declaration.initializer.arguments[0].text === '@nx/jest'
)
);
const importStatement = sourceFile.statements.find(
(statement) =>
tsModule.isImportDeclaration(statement) &&
statement.moduleSpecifier.getText() === `'@nx/jest'`
);
if (requireStatement || importStatement) {
// find `module.exports` statement with `projects: getJestProjects()`
const moduleExports = sourceFile.statements.find(
(statement) =>
tsModule.isExpressionStatement(statement) &&
tsModule.isBinaryExpression(statement.expression) &&
tsModule.isPropertyAccessExpression(statement.expression.left) &&
tsModule.isObjectLiteralExpression(statement.expression.right) &&
statement.expression.operatorToken.kind ===
tsModule.SyntaxKind.EqualsToken &&
tsModule.isIdentifier(statement.expression.left.expression) &&
statement.expression.left.expression.escapedText === 'module' &&
tsModule.isIdentifier(statement.expression.left.name) &&
statement.expression.left.name.escapedText === 'exports' &&
statement.expression.right.properties.some(
(property) =>
tsModule.isPropertyAssignment(property) &&
tsModule.isIdentifier(property.name) &&
property.name.escapedText === 'projects' &&
tsModule.isCallExpression(property.initializer) &&
tsModule.isIdentifier(property.initializer.expression) &&
property.initializer.expression.escapedText ===
'getJestProjects'
)
) as ExpressionStatement;
if (moduleExports) {
// replace getJestProjects with getJestProjectsAsync in export statement
const rightExpression = (
moduleExports.expression as BinaryExpression
).right.getText();
const newExpression = rightExpression.replace(
'getJestProjects()',
'await getJestProjectsAsync()'
);
const newStatement = `module.exports = async () => (${newExpression});`;
let newContent = oldContent.replace(
moduleExports.getText(),
newStatement
);
// replace getJestProjects with getJestProjectsAsync in import statement
newContent = newContent.replace(
'getJestProjects',
'getJestProjectsAsync'
);
tree.write(jestConfigPath, newContent);
} else {
// find `export default` statement with `projects: getJestProjects()`
const exportAssignment = sourceFile.statements.find((statement) =>
tsModule.isExportAssignment(statement)
) as ExportAssignment;
const defaultExport =
exportAssignment?.expression &&
tsModule.isObjectLiteralExpression(exportAssignment?.expression)
? exportAssignment?.expression
: null;
const projectProperty = defaultExport?.properties.find(
(property) =>
tsModule.isPropertyAssignment(property) &&
property.name.getText() === 'projects' &&
tsModule.isCallExpression(property.initializer) &&
tsModule.isIdentifier(property.initializer.expression) &&
property.initializer.expression.escapedText === 'getJestProjects'
);
if (projectProperty) {
// replace getJestProjects with getJestProjectsAsync in export statement
const newExpression = defaultExport
.getText()
.replace('getJestProjects()', 'await getJestProjectsAsync()');
const newStatement = `export default async () => (${newExpression});`;
let newContent = oldContent.replace(
exportAssignment.getText(),
newStatement
);
// replace getJestProjects with getJestProjectsAsync in import statement
newContent = newContent.replace(
'getJestProjects',
'getJestProjectsAsync'
);
tree.write(jestConfigPath, newContent);
}
}
}
}
});
}

View File

@ -18,72 +18,6 @@ describe('jestConfigObject', () => {
foo: 'bar', foo: 'bar',
}); });
}); });
xit('should work with async functions', async () => {
const tree = createTree();
jest.mock('@nx/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
}));
tree.write(
'jest.config.js',
`
const { getJestProjects } = require('@nx/jest');
module.exports = async () => ({
foo: 'bar'
});
`
);
expect(await jestConfigObject(tree, 'jest.config.js')).toEqual({
foo: 'bar',
});
});
it('should work with `getJestConfig`', () => {
const tree = createTree();
jest.mock('@nx/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
}));
tree.write(
'jest.config.js',
`
const { getJestProjects } = require('@nx/jest');
module.exports = {
projects: getJestProjects()
};
`
);
expect(jestConfigObject(tree, 'jest.config.js')).toEqual({
projects: ['<rootDir>/project-a', '<rootDir>/project-b'],
});
});
it('should work with node globals (require, __dirname, process, __filename, console, and other globals)', () => {
const tree = createTree();
jest.mock('@nx/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
}));
tree.write(
'jest.config.js',
`
const { getJestProjects } = require('@nx/jest');
module.exports = {
projects: getJestProjects(),
filename: __filename,
env: process.env,
dirname: __dirname
};
`
);
expect(jestConfigObject(tree, 'jest.config.js')).toEqual({
dirname: '/virtual',
filename: '/virtual/jest.config.js',
env: process.env,
projects: ['<rootDir>/project-a', '<rootDir>/project-b'],
});
});
}); });
describe('export default', () => { describe('export default', () => {

View File

@ -1,190 +1,6 @@
import type { import type { ProjectConfiguration, ProjectGraph } from '@nx/devkit';
ProjectConfiguration,
ProjectGraph,
WorkspaceJsonConfiguration,
} from '@nx/devkit';
import * as devkit from '@nx/devkit'; import * as devkit from '@nx/devkit';
import * as Workspace from 'nx/src/project-graph/file-utils'; import { getJestProjectsAsync } from './get-jest-projects';
import { getJestProjects, getJestProjectsAsync } from './get-jest-projects';
describe('getJestProjects', () => {
test('single project', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
'test-1': {
root: 'blah',
targets: {
test: {
executor: '@nx/jest:jest',
options: {
jestConfig: 'test/jest/config/location/jest.config.js',
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = [
'<rootDir>/test/jest/config/location/jest.config.js',
];
expect(getJestProjects()).toEqual(expectedResults);
});
test('custom target name', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
'test-1': {
root: 'blah',
targets: {
'test-with-jest': {
executor: '@nx/jest:jest',
options: {
jestConfig: 'test/jest/config/location/jest.config.js',
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = [
'<rootDir>/test/jest/config/location/jest.config.js',
];
expect(getJestProjects()).toEqual(expectedResults);
});
test('root project', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
'test-1': {
root: '.',
targets: {
test: {
executor: '@nx/jest:jest',
options: {
jestConfig: 'jest.config.app.js',
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = ['<rootDir>/jest.config.app.js'];
expect(getJestProjects()).toEqual(expectedResults);
});
test('configuration set with unique jestConfig', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
test: {
root: 'blah',
targets: {
'test-with-jest': {
executor: '@nx/jest:jest',
options: {
jestConfig: 'test/jest/config/location/jest.config.js',
},
configurations: {
prod: {
jestConfig: 'configuration-specific/jest.config.js',
},
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = [
'<rootDir>/test/jest/config/location/jest.config.js',
'<rootDir>/configuration-specific/jest.config.js',
];
expect(getJestProjects()).toEqual(expectedResults);
});
test('configuration, set with same jestConfig on configuration', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
test: {
root: 'blah',
targets: {
'test-with-jest': {
executor: '@nx/jest:jest',
options: {
jestConfig: 'test/jest/config/location/jest.config.js',
},
configurations: {
prod: {
jestConfig: 'test/jest/config/location/jest.config.js',
},
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = [
'<rootDir>/test/jest/config/location/jest.config.js',
];
expect(getJestProjects()).toEqual(expectedResults);
});
test('other projects and targets that do not use the nx jest test runner', () => {
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
projects: {
otherTarget: {
root: 'test',
targets: {
test: {
executor: 'something else',
options: {},
},
},
},
test: {
root: 'blah',
targets: {
'test-with-jest': {
executor: 'something else',
options: {
jestConfig: 'something random',
},
configurations: {
prod: {
jestConfig: 'configuration-specific/jest.config.js',
},
},
},
},
},
},
version: 1,
};
jest
.spyOn(Workspace, 'readWorkspaceConfig')
.mockImplementation(() => mockedWorkspaceConfig);
const expectedResults = [];
expect(getJestProjects()).toEqual(expectedResults);
});
});
describe('getJestProjectsAsync', () => { describe('getJestProjectsAsync', () => {
let projectGraph: ProjectGraph; let projectGraph: ProjectGraph;

View File

@ -1,9 +1,4 @@
import { import { createProjectGraphAsync, type TargetConfiguration } from '@nx/devkit';
createProjectGraphAsync,
type ProjectsConfigurations,
type TargetConfiguration,
} from '@nx/devkit';
import { readWorkspaceConfig } from 'nx/src/project-graph/file-utils';
import { join, parse } from 'path'; import { join, parse } from 'path';
import * as yargs from 'yargs-parser'; import * as yargs from 'yargs-parser';
@ -11,72 +6,6 @@ function getJestConfigProjectPath(projectJestConfigPath: string): string {
return join('<rootDir>', projectJestConfigPath); return join('<rootDir>', projectJestConfigPath);
} }
/**
* TODO(v21): Remove this function
* @deprecated To get projects use {@link getJestProjectsAsync} instead. This will be removed in v21.
* Get a list of paths to all the jest config files
* using the Nx Jest executor.
*
* This is used to configure Jest multi-project support. To support projects
* using inferred targets @see getJestProjectsAsync
*
* To add a project not using the Nx Jest executor:
* export default {
* projects: [...getJestProjects(), '<rootDir>/path/to/jest.config.ts'];
* }
*
**/
export function getJestProjects() {
const ws = readWorkspaceConfig({
format: 'nx',
}) as ProjectsConfigurations;
const jestConfigurationSet = new Set<string>();
for (const projectConfig of Object.values(ws.projects)) {
if (!projectConfig.targets) {
continue;
}
for (const targetConfiguration of Object.values(projectConfig.targets)) {
if (
targetConfiguration.executor !== '@nx/jest:jest' &&
targetConfiguration.executor !== '@nrwl/jest:jest'
) {
continue;
}
if (targetConfiguration.options?.jestConfig) {
jestConfigurationSet.add(
getJestConfigProjectPath(targetConfiguration.options.jestConfig)
);
}
if (targetConfiguration.configurations) {
for (const configurationObject of Object.values(
targetConfiguration.configurations
)) {
if (configurationObject.jestConfig) {
jestConfigurationSet.add(
getJestConfigProjectPath(configurationObject.jestConfig)
);
}
}
}
}
}
return Array.from(jestConfigurationSet);
}
/**
* a list of nested projects that have jest configured
* to be used in the testPathIgnorePatterns property of a given jest config
* https://jestjs.io/docs/configuration#testpathignorepatterns-arraystring
* */
export function getNestedJestProjects() {
// TODO(caleb): get current project path and list of all projects and their rootDir
// return a list of all projects that are nested in the current projects path
// always include node_modules as that's the default
const allProjects = getJestProjects();
return ['/node_modules/'];
}
/** /**
* Get a list of paths to all the jest config files * Get a list of paths to all the jest config files
* using the Nx Jest executor and `@nx/run:commands` * using the Nx Jest executor and `@nx/run:commands`

View File

@ -143,7 +143,7 @@ describe('updateJestConfig', () => {
expect(rootJestConfigAfter).toContain('getJestProjectsAsync()'); expect(rootJestConfigAfter).toContain('getJestProjectsAsync()');
}); });
it('updates the root config if not using `getJestProjects()`', async () => { it('updates the root config if not using `getJestProjectsAsync()`', async () => {
const rootJestConfigPath = '/jest.config.ts'; const rootJestConfigPath = '/jest.config.ts';
await libraryGenerator(tree, { await libraryGenerator(tree, {
name: 'some-test-dir-my-source', name: 'some-test-dir-my-source',
@ -180,7 +180,7 @@ describe('updateJestConfig', () => {
); );
}); });
it('updates the root config if `getJestProjects()` is used but old path exists', async () => { it('updates the root config if `getJestProjectsAsync()` is used but old path exists', async () => {
const rootJestConfigPath = '/jest.config.ts'; const rootJestConfigPath = '/jest.config.ts';
await libraryGenerator(tree, { await libraryGenerator(tree, {
name: 'some-test-dir-my-source', name: 'some-test-dir-my-source',
@ -188,11 +188,11 @@ describe('updateJestConfig', () => {
}); });
tree.write( tree.write(
rootJestConfigPath, rootJestConfigPath,
`const { getJestProjects } = require('@nx/jest'); `const { getJestProjectsAsync } = require('@nx/jest');
module.exports = { module.exports = async () => ({
projects: [...getJestProjects(), '<rootDir>/some/test/dir/my-source'] projects: [...(await getJestProjectsAsync()), '<rootDir>/some/test/dir/my-source']
}; });
` `
); );
const projectConfig = readProjectConfiguration( const projectConfig = readProjectConfiguration(
@ -217,10 +217,10 @@ module.exports = {
expect(rootJestConfigAfter).not.toContain( expect(rootJestConfigAfter).not.toContain(
'<rootDir>/other/test/dir/my-destination' '<rootDir>/other/test/dir/my-destination'
); );
expect(rootJestConfigAfter).toContain('getJestProjects()'); expect(rootJestConfigAfter).toContain('getJestProjectsAsync()');
}); });
it('updates the root config if `getJestProjects()` is used with other projects in the array', async () => { it('updates the root config if `getJestProjectsAsync()` is used with other projects in the array', async () => {
const rootJestConfigPath = '/jest.config.ts'; const rootJestConfigPath = '/jest.config.ts';
await libraryGenerator(tree, { await libraryGenerator(tree, {
name: 'some-test-dir-my-source', name: 'some-test-dir-my-source',
@ -228,11 +228,11 @@ module.exports = {
}); });
tree.write( tree.write(
rootJestConfigPath, rootJestConfigPath,
`const { getJestProjects } = require('@nx/jest'); `const { getJestProjectsAsync } = require('@nx/jest');
module.exports = { module.exports = async () => ({
projects: [...getJestProjects(), '<rootDir>/some/test/dir/my-source', '<rootDir>/foo'] projects: [...(await getJestProjectsAsync()), '<rootDir>/some/test/dir/my-source', '<rootDir>/foo']
}; });
` `
); );
const projectConfig = readProjectConfiguration( const projectConfig = readProjectConfiguration(
@ -258,6 +258,6 @@ module.exports = {
'<rootDir>/other/test/dir/my-destination' '<rootDir>/other/test/dir/my-destination'
); );
expect(rootJestConfigAfter).toContain('<rootDir>/foo'); expect(rootJestConfigAfter).toContain('<rootDir>/foo');
expect(rootJestConfigAfter).toContain('getJestProjects()'); expect(rootJestConfigAfter).toContain('getJestProjectsAsync()');
}); });
}); });

View File

@ -68,9 +68,9 @@ export function updateJestConfig(
const findProject = `'<rootDir>/${project.root}'`; const findProject = `'<rootDir>/${project.root}'`;
const oldRootJestConfigContent = tree.read(rootJestConfigPath, 'utf-8'); const oldRootJestConfigContent = tree.read(rootJestConfigPath, 'utf-8');
const usingJestProjects = const usingJestProjects = oldRootJestConfigContent.includes(
oldRootJestConfigContent.includes('getJestProjects()') || 'getJestProjectsAsync()'
oldRootJestConfigContent.includes('getJestProjectsAsync()'); );
const newRootJestConfigContent = oldRootJestConfigContent.replace( const newRootJestConfigContent = oldRootJestConfigContent.replace(
findProject, findProject,

View File

@ -26,10 +26,7 @@ function isUsingUtilityFunction(host: Tree) {
const rootConfig = host.read(rootConfigPath, 'utf-8'); const rootConfig = host.read(rootConfigPath, 'utf-8');
return ( return rootConfig.includes('getJestProjectsAsync()');
rootConfig.includes('getJestProjects()') ||
rootConfig.includes('getJestProjectsAsync()')
);
} }
/** /**