feat(testing): add getJestProjectsAsync to support inferred targets (#21897)
This commit is contained in:
parent
dd2c7d2601
commit
77a01ca94c
@ -13,5 +13,6 @@ export { jestConfigObjectAst } from './src/utils/config/functions';
|
||||
export { jestInitGenerator } from './src/generators/init/init';
|
||||
export {
|
||||
getJestProjects,
|
||||
getJestProjectsAsync,
|
||||
getNestedJestProjects,
|
||||
} from './src/utils/config/get-jest-projects';
|
||||
|
||||
@ -36,6 +36,8 @@
|
||||
"dependencies": {
|
||||
"@jest/reporters": "^29.4.1",
|
||||
"@jest/test-result": "^29.4.1",
|
||||
"@nx/devkit": "file:../devkit",
|
||||
"@nx/js": "file:../js",
|
||||
"@phenomnomnominal/tsquery": "~5.0.1",
|
||||
"chalk": "^4.1.0",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
@ -45,8 +47,7 @@
|
||||
"minimatch": "9.0.3",
|
||||
"resolve.exports": "1.1.0",
|
||||
"tslib": "^2.3.0",
|
||||
"@nx/devkit": "file:../devkit",
|
||||
"@nx/js": "file:../js"
|
||||
"yargs-parser": "21.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`createJestConfig should generate files 1`] = `
|
||||
"import { getJestProjects } from '@nx/jest';
|
||||
"import { getJestProjectsAsync } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};"
|
||||
export default async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});"
|
||||
`;
|
||||
|
||||
exports[`createJestConfig should generate files 2`] = `
|
||||
@ -15,11 +15,11 @@ module.exports = { ...nxPreset }"
|
||||
`;
|
||||
|
||||
exports[`createJestConfig should generate files with --js flag 1`] = `
|
||||
"const { getJestProjects } = require('@nx/jest');
|
||||
"const { getJestProjectsAsync } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};"
|
||||
module.exports = async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});"
|
||||
`;
|
||||
|
||||
exports[`createJestConfig should generate files with --js flag 2`] = `
|
||||
|
||||
@ -162,11 +162,11 @@ export default {
|
||||
"
|
||||
`);
|
||||
expect(tree.read('jest.config.ts', 'utf-8'))
|
||||
.toEqual(`import { getJestProjects } from '@nx/jest';
|
||||
.toEqual(`import { getJestProjectsAsync } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
export default async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});`);
|
||||
expect(readProjectConfiguration(tree, 'my-project').targets.test)
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
@ -214,11 +214,11 @@ module.exports = {
|
||||
|
||||
expect(tree.exists('jest.config.app.js')).toBeTruthy();
|
||||
expect(tree.read('jest.config.js', 'utf-8'))
|
||||
.toEqual(`const { getJestProjects } = require('@nx/jest');
|
||||
.toEqual(`const { getJestProjectsAsync } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
module.exports = async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -129,16 +129,16 @@ export async function createJestConfig(
|
||||
function generateGlobalConfig(tree: Tree, isJS: boolean) {
|
||||
const contents = isJS
|
||||
? stripIndents`
|
||||
const { getJestProjects } = require('@nx/jest');
|
||||
const { getJestProjectsAsync } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`
|
||||
module.exports = async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});`
|
||||
: stripIndents`
|
||||
import { getJestProjects } from '@nx/jest';
|
||||
import { getJestProjectsAsync } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`;
|
||||
export default async () => ({
|
||||
projects: await getJestProjectsAsync()
|
||||
});`;
|
||||
tree.write(`jest.config.${isJS ? 'js' : 'ts'}`, contents);
|
||||
}
|
||||
|
||||
@ -5,8 +5,15 @@ import { readProjectConfiguration, Tree } from '@nx/devkit';
|
||||
|
||||
function isUsingUtilityFunction(host: Tree) {
|
||||
const rootConfig = findRootJestConfig(host);
|
||||
if (!rootConfig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rootConfigContent = host.read(rootConfig, 'utf-8');
|
||||
|
||||
return (
|
||||
rootConfig && host.read(rootConfig).toString().includes('getJestProjects()')
|
||||
rootConfigContent.includes('getJestProjects()') ||
|
||||
rootConfigContent.includes('getJestProjectsAsync()')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ describe('@nx/jest/plugin', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
tempFs = new TempFs('test');
|
||||
process.chdir(tempFs.tempDir);
|
||||
context = {
|
||||
nxJsonConfiguration: {
|
||||
namedInputs: {
|
||||
|
||||
@ -12,7 +12,7 @@ import { dirname, join, relative, resolve } from 'path';
|
||||
|
||||
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
||||
import { existsSync, readdirSync } from 'fs';
|
||||
import { existsSync, readdirSync, readFileSync } from 'fs';
|
||||
import { readConfig } from 'jest-config';
|
||||
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
||||
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
||||
@ -82,6 +82,17 @@ export const createNodes: CreateNodes<JestPluginOptions> = [
|
||||
}
|
||||
}
|
||||
|
||||
const jestConfigContent = readFileSync(
|
||||
resolve(context.workspaceRoot, configFilePath),
|
||||
'utf-8'
|
||||
);
|
||||
if (jestConfigContent.includes('getJestProjectsAsync()')) {
|
||||
// The `getJestProjectsAsync` function uses the project graph, which leads to a
|
||||
// circular dependency. We can skip this since it's no intended to be used for
|
||||
// an Nx project.
|
||||
return {};
|
||||
}
|
||||
|
||||
options = normalizeOptions(options);
|
||||
|
||||
const hash = calculateHashForCreateNodes(projectRoot, options, context);
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import { getJestProjects } from './get-jest-projects';
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
ProjectGraph,
|
||||
WorkspaceJsonConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import * as devkit from '@nx/devkit';
|
||||
import * as Workspace from 'nx/src/project-graph/file-utils';
|
||||
import type { WorkspaceJsonConfiguration } from '@nx/devkit';
|
||||
import { getJestProjects, getJestProjectsAsync } from './get-jest-projects';
|
||||
|
||||
describe('getJestProjects', () => {
|
||||
test('single project', () => {
|
||||
@ -142,7 +147,7 @@ describe('getJestProjects', () => {
|
||||
expect(getJestProjects()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('other projects and targets that do not use the nrwl jest test runner', () => {
|
||||
test('other projects and targets that do not use the nx jest test runner', () => {
|
||||
const mockedWorkspaceConfig: WorkspaceJsonConfiguration = {
|
||||
projects: {
|
||||
otherTarget: {
|
||||
@ -180,3 +185,315 @@ describe('getJestProjects', () => {
|
||||
expect(getJestProjects()).toEqual(expectedResults);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getJestProjectsAsync', () => {
|
||||
let projectGraph: ProjectGraph;
|
||||
|
||||
function addProject(name: string, config: ProjectConfiguration): void {
|
||||
projectGraph.nodes[name] = { name, type: 'app', data: config };
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
projectGraph = { nodes: {}, dependencies: {} };
|
||||
jest
|
||||
.spyOn(devkit, 'createProjectGraphAsync')
|
||||
.mockReturnValue(Promise.resolve(projectGraph));
|
||||
});
|
||||
|
||||
test('single project', async () => {
|
||||
addProject('test-1', {
|
||||
root: 'blah',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'test/jest/config/location/jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/test/jest/config/location/jest.config.js',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('custom target name', async () => {
|
||||
addProject('test-1', {
|
||||
root: 'blah',
|
||||
targets: {
|
||||
'test-with-jest': {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'test/jest/config/location/jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/test/jest/config/location/jest.config.js',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('root project', async () => {
|
||||
addProject('test-1', {
|
||||
root: '.',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'jest.config.app.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = ['<rootDir>/jest.config.app.js'];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('configuration set with unique jestConfig', async () => {
|
||||
addProject('test-1', {
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/test/jest/config/location/jest.config.js',
|
||||
'<rootDir>/configuration-specific/jest.config.js',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('configuration, set with same jestConfig on configuration', async () => {
|
||||
addProject('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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/test/jest/config/location/jest.config.js',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('other projects and targets that do not use the nx jest test runner', async () => {
|
||||
addProject('otherTarget', {
|
||||
root: 'test',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'something else',
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
addProject('test', {
|
||||
root: 'blah',
|
||||
targets: {
|
||||
'test-with-jest': {
|
||||
executor: 'something else',
|
||||
options: {
|
||||
jestConfig: 'something random',
|
||||
},
|
||||
configurations: {
|
||||
prod: {
|
||||
jestConfig: 'configuration-specific/jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test.each`
|
||||
command
|
||||
${'jest'}
|
||||
${'npx jest'}
|
||||
${'yarn jest'}
|
||||
${'pnpm jest'}
|
||||
${'pnpm dlx jest'}
|
||||
${'echo "foo" && jest'}
|
||||
${'echo "foo" && npx jest'}
|
||||
${'jest && echo "foo"'}
|
||||
${'npx jest && echo "foo"'}
|
||||
${'echo "foo" && jest && echo "bar"'}
|
||||
${'echo "foo" && npx jest && echo "bar"'}
|
||||
`(
|
||||
'targets with nx:run-commands executor running "$command"',
|
||||
async ({ command }) => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command },
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = ['<rootDir>/projects/test-1'];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
}
|
||||
);
|
||||
|
||||
test.each`
|
||||
command
|
||||
${'jest'}
|
||||
${'npx jest'}
|
||||
${'yarn jest'}
|
||||
${'pnpm jest'}
|
||||
${'pnpm dlx jest'}
|
||||
${'echo "foo" && jest'}
|
||||
${'echo "foo" && npx jest'}
|
||||
${'jest && echo "foo"'}
|
||||
${'npx jest && echo "foo"'}
|
||||
${'echo "foo" && jest && echo "bar"'}
|
||||
${'echo "foo" && npx jest && echo "bar"'}
|
||||
`(
|
||||
'targets with nx:run-commands executor using "commands" option and running "$command"',
|
||||
async ({ command }) => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { commands: [command] },
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = ['<rootDir>/projects/test-1'];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
}
|
||||
);
|
||||
|
||||
test.each`
|
||||
command
|
||||
${'jest'}
|
||||
${'npx jest'}
|
||||
${'yarn jest'}
|
||||
${'pnpm jest'}
|
||||
${'pnpm dlx jest'}
|
||||
${'echo "foo" && jest'}
|
||||
${'echo "foo" && npx jest'}
|
||||
${'jest && echo "foo"'}
|
||||
${'npx jest && echo "foo"'}
|
||||
${'echo "foo" && jest && echo "bar"'}
|
||||
${'echo "foo" && npx jest && echo "bar"'}
|
||||
`(
|
||||
'targets with nx:run-commands executor using "commands" option using the object notation and running "$command"',
|
||||
async ({ command }) => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { commands: [{ command }] },
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = ['<rootDir>/projects/test-1'];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
}
|
||||
);
|
||||
|
||||
test.each`
|
||||
command | cwd
|
||||
${'jest --config projects/test-1/jest.config.ts'} | ${'.'}
|
||||
${'npx jest --config projects/test-1/jest.config.ts'} | ${'.'}
|
||||
${'jest --config jest.config.ts'} | ${undefined}
|
||||
${'npx jest --config jest.config.ts'} | ${undefined}
|
||||
${'jest --config jest.config.ts'} | ${'projects/test-1'}
|
||||
${'npx jest --config jest.config.ts'} | ${'projects/test-1'}
|
||||
${'echo "foo" && jest --config jest.config.ts'} | ${undefined}
|
||||
${'echo "foo" && npx jest --config jest.config.ts'} | ${undefined}
|
||||
${'jest --config jest.config.ts && echo "foo"'} | ${undefined}
|
||||
${'npx jest --config jest.config.ts && echo "foo"'} | ${undefined}
|
||||
${'echo "foo" && jest --config jest.config.ts && echo "bar"'} | ${undefined}
|
||||
${'echo "foo" && npx jest --config jest.config.ts && echo "bar"'} | ${undefined}
|
||||
`(
|
||||
'targets with nx:run-commands executor running "$command" at "$cwd"',
|
||||
async ({ command, cwd }) => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command, cwd },
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = ['<rootDir>/projects/test-1/jest.config.ts'];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
}
|
||||
);
|
||||
|
||||
test('targets with nx:run-commands executor with a command with multiple "jest" runs', async () => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
command: 'jest && jest --config jest1.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/projects/test-1',
|
||||
'<rootDir>/projects/test-1/jest1.config.ts',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
|
||||
test('projects with targets using both executors', async () => {
|
||||
addProject('test-1', {
|
||||
root: 'projects/test-1',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'projects/test-1/jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
addProject('test-2', {
|
||||
root: 'projects/test-2',
|
||||
targets: {
|
||||
test: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command: 'jest' },
|
||||
},
|
||||
},
|
||||
});
|
||||
const expectedResults = [
|
||||
'<rootDir>/projects/test-1/jest.config.js',
|
||||
'<rootDir>/projects/test-2',
|
||||
];
|
||||
expect(await getJestProjectsAsync()).toEqual(expectedResults);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import { join } from 'path';
|
||||
import type { ProjectsConfigurations } from '@nx/devkit';
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
type ProjectsConfigurations,
|
||||
type TargetConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { readWorkspaceConfig } from 'nx/src/project-graph/file-utils';
|
||||
import { join } from 'path';
|
||||
import * as yargs from 'yargs-parser';
|
||||
|
||||
function getJestConfigProjectPath(projectJestConfigPath: string): string {
|
||||
return join('<rootDir>', projectJestConfigPath);
|
||||
@ -10,7 +15,8 @@ function getJestConfigProjectPath(projectJestConfigPath: string): string {
|
||||
* 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.
|
||||
* 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 {
|
||||
@ -68,3 +74,146 @@ export function getNestedJestProjects() {
|
||||
const allProjects = getJestProjects();
|
||||
return ['/node_modules/'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of paths to all the jest config files
|
||||
* using the Nx Jest executor and `@nx/run:commands`
|
||||
* running `jest`.
|
||||
*
|
||||
* This is used to configure Jest multi-project support.
|
||||
*
|
||||
* To add a project not using the Nx Jest executor:
|
||||
* export default async () => ({
|
||||
* projects: [...(await getJestProjectsAsync()), '<rootDir>/path/to/jest.config.ts'];
|
||||
* });
|
||||
*
|
||||
**/
|
||||
export async function getJestProjectsAsync() {
|
||||
const graph = await createProjectGraphAsync({
|
||||
exitOnError: false,
|
||||
resetDaemonClient: true,
|
||||
});
|
||||
const jestConfigurations = new Set<string>();
|
||||
for (const node of Object.values(graph.nodes)) {
|
||||
const projectConfig = node.data;
|
||||
if (!projectConfig.targets) {
|
||||
continue;
|
||||
}
|
||||
for (const targetConfiguration of Object.values(projectConfig.targets)) {
|
||||
if (
|
||||
targetConfiguration.executor === '@nx/jest:jest' ||
|
||||
targetConfiguration.executor === '@nrwl/jest:jest'
|
||||
) {
|
||||
collectJestConfigFromJestExecutor(
|
||||
targetConfiguration,
|
||||
jestConfigurations
|
||||
);
|
||||
} else if (targetConfiguration.executor === 'nx:run-commands') {
|
||||
collectJestConfigFromRunCommandsExecutor(
|
||||
targetConfiguration,
|
||||
projectConfig.root,
|
||||
jestConfigurations
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(jestConfigurations);
|
||||
}
|
||||
|
||||
function collectJestConfigFromJestExecutor(
|
||||
targetConfiguration: TargetConfiguration,
|
||||
jestConfigurations: Set<string>
|
||||
): void {
|
||||
if (targetConfiguration.options?.jestConfig) {
|
||||
jestConfigurations.add(
|
||||
getJestConfigProjectPath(targetConfiguration.options.jestConfig)
|
||||
);
|
||||
}
|
||||
if (targetConfiguration.configurations) {
|
||||
for (const configurationObject of Object.values(
|
||||
targetConfiguration.configurations
|
||||
)) {
|
||||
if (configurationObject.jestConfig) {
|
||||
jestConfigurations.add(
|
||||
getJestConfigProjectPath(configurationObject.jestConfig)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectJestConfigFromRunCommandsExecutor(
|
||||
targetConfiguration: TargetConfiguration,
|
||||
projectRoot: string,
|
||||
jestConfigurations: Set<string>
|
||||
): void {
|
||||
if (targetConfiguration.options?.command) {
|
||||
collectJestConfigFromCommand(
|
||||
targetConfiguration.options.command,
|
||||
targetConfiguration.options.cwd ?? projectRoot,
|
||||
jestConfigurations
|
||||
);
|
||||
} else if (targetConfiguration.options?.commands) {
|
||||
for (const command of targetConfiguration.options.commands) {
|
||||
const commandScript =
|
||||
typeof command === 'string' ? command : command.command;
|
||||
collectJestConfigFromCommand(
|
||||
commandScript,
|
||||
targetConfiguration.options.cwd ?? projectRoot,
|
||||
jestConfigurations
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetConfiguration.configurations) {
|
||||
for (const configurationObject of Object.values(
|
||||
targetConfiguration.configurations
|
||||
)) {
|
||||
if (configurationObject.command) {
|
||||
collectJestConfigFromCommand(
|
||||
configurationObject.command,
|
||||
configurationObject.cwd ?? projectRoot,
|
||||
jestConfigurations
|
||||
);
|
||||
} else if (configurationObject.commands) {
|
||||
for (const command of configurationObject.commands) {
|
||||
const commandScript =
|
||||
typeof command === 'string' ? command : command.command;
|
||||
collectJestConfigFromCommand(
|
||||
commandScript,
|
||||
configurationObject.cwd ?? projectRoot,
|
||||
jestConfigurations
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectJestConfigFromCommand(
|
||||
command: string,
|
||||
cwd: string,
|
||||
jestConfigurations: Set<string>
|
||||
) {
|
||||
const jestCommandRegex =
|
||||
/(?<=^|&)(?:[^&\r\n\s]* )*jest(?: [^&\r\n\s]*)*(?=$|&)/g;
|
||||
const matches = command.match(jestCommandRegex);
|
||||
if (!matches) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const match of matches) {
|
||||
const parsed = yargs(match, {
|
||||
configuration: { 'strip-dashed': true },
|
||||
string: ['config'],
|
||||
});
|
||||
if (parsed.config) {
|
||||
jestConfigurations.add(
|
||||
getJestConfigProjectPath(join(cwd, parsed.config))
|
||||
);
|
||||
} else {
|
||||
jestConfigurations.add(getJestConfigProjectPath(cwd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ describe('updateJestConfig', () => {
|
||||
expect(jestConfigAfter).toContain(
|
||||
`coverageDirectory: '../coverage/my-destination'`
|
||||
);
|
||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||
expect(rootJestConfigAfter).toContain('getJestProjectsAsync()');
|
||||
});
|
||||
|
||||
it('should update the name and dir correctly when moving to a nested dir', async () => {
|
||||
@ -142,7 +142,7 @@ describe('updateJestConfig', () => {
|
||||
expect(jestConfigAfter).toContain(
|
||||
`coverageDirectory: '../coverage/other/test/dir/my-destination'`
|
||||
);
|
||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||
expect(rootJestConfigAfter).toContain('getJestProjectsAsync()');
|
||||
});
|
||||
|
||||
it('updates the root config if not using `getJestProjects()`', async () => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ProjectConfiguration, Tree } from '@nx/devkit';
|
||||
import * as path from 'path';
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import { findRootJestConfig } from '../../utils/jest-config';
|
||||
|
||||
/**
|
||||
* Updates the project name and coverage folder in the jest.config.js if it exists
|
||||
@ -58,9 +59,9 @@ export function updateJestConfig(
|
||||
}
|
||||
|
||||
// update root jest.config.ts
|
||||
const rootJestConfigPath = '/jest.config.ts';
|
||||
const rootJestConfigPath = findRootJestConfig(tree);
|
||||
|
||||
if (!tree.exists(rootJestConfigPath)) {
|
||||
if (!rootJestConfigPath || !tree.exists(rootJestConfigPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,7 +69,8 @@ export function updateJestConfig(
|
||||
|
||||
const oldRootJestConfigContent = tree.read(rootJestConfigPath, 'utf-8');
|
||||
const usingJestProjects =
|
||||
oldRootJestConfigContent.includes('getJestProjects()');
|
||||
oldRootJestConfigContent.includes('getJestProjects()') ||
|
||||
oldRootJestConfigContent.includes('getJestProjectsAsync()');
|
||||
|
||||
const newRootJestConfigContent = oldRootJestConfigContent.replace(
|
||||
findProject,
|
||||
|
||||
@ -14,11 +14,22 @@ import type {
|
||||
} from 'typescript';
|
||||
import { join } from 'path';
|
||||
import { ensureTypescript } from '../../../utilities/typescript';
|
||||
import { findRootJestConfig } from '../../utils/jest-config';
|
||||
|
||||
let tsModule: typeof import('typescript');
|
||||
|
||||
function isUsingUtilityFunction(host: Tree) {
|
||||
return host.read('jest.config.ts').toString().includes('getJestProjects()');
|
||||
const rootConfigPath = findRootJestConfig(host);
|
||||
if (!rootConfigPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rootConfig = host.read(rootConfigPath, 'utf-8');
|
||||
|
||||
return (
|
||||
rootConfig.includes('getJestProjects()') ||
|
||||
rootConfig.includes('getJestProjectsAsync()')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -27,7 +38,12 @@ function isUsingUtilityFunction(host: Tree) {
|
||||
* in that case we do not need to edit it to remove it
|
||||
**/
|
||||
function isMonorepoConfig(tree: Tree) {
|
||||
return tree.read('jest.config.ts', 'utf-8').includes('projects:');
|
||||
const rootConfigPath = findRootJestConfig(tree);
|
||||
if (!rootConfigPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tree.read(rootConfigPath, 'utf-8').includes('projects:');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,8 +66,10 @@ export function updateJestConfig(
|
||||
} = tsModule;
|
||||
const projectToRemove = schema.projectName;
|
||||
|
||||
const rootConfigPath = findRootJestConfig(tree);
|
||||
|
||||
if (
|
||||
!tree.exists('jest.config.ts') ||
|
||||
!tree.exists(rootConfigPath) ||
|
||||
!tree.exists(join(projectConfig.root, 'jest.config.ts')) ||
|
||||
isUsingUtilityFunction(tree) ||
|
||||
!isMonorepoConfig(tree)
|
||||
@ -59,9 +77,9 @@ export function updateJestConfig(
|
||||
return;
|
||||
}
|
||||
|
||||
const contents = tree.read('jest.config.ts', 'utf-8');
|
||||
const contents = tree.read(rootConfigPath, 'utf-8');
|
||||
const sourceFile = createSourceFile(
|
||||
'jest.config.ts',
|
||||
rootConfigPath,
|
||||
contents,
|
||||
ScriptTarget.Latest
|
||||
);
|
||||
@ -104,7 +122,7 @@ export function updateJestConfig(
|
||||
: project.getStart(sourceFile);
|
||||
|
||||
tree.write(
|
||||
'jest.config.ts',
|
||||
rootConfigPath,
|
||||
applyChangesToString(contents, [
|
||||
{
|
||||
type: ChangeType.Delete,
|
||||
|
||||
13
packages/workspace/src/generators/utils/jest-config.ts
Normal file
13
packages/workspace/src/generators/utils/jest-config.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
|
||||
export function findRootJestConfig(tree: Tree): string | null {
|
||||
if (tree.exists('jest.config.js')) {
|
||||
return 'jest.config.js';
|
||||
}
|
||||
|
||||
if (tree.exists('jest.config.ts')) {
|
||||
return 'jest.config.ts';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user