Thanks to visit codestin.com
Credit goes to github.com

Skip to content
6 changes: 5 additions & 1 deletion docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ This feature is an escape-hatch. If Jest doesn't exit at the end of a test run,

Show the help information, similar to this page.

### `--igoreProjects <project1> ... <projectN>`

Ignore the tests of the specified projects. Jest uses the attribute `displayName` in the configuration to identify each project. If you use this option, you should provide a `displayName` to all your projects.

### `--init`

Generate a basic configuration file. Based on your project, Jest will ask you a few questions that will help to generate a `jest.config.js` file with a short description for each option.
Expand Down Expand Up @@ -332,7 +336,7 @@ The default regex matching works fine on small runs, but becomes slow if provide

### `--selectProjects <project1> ... <projectN>`

Run only the tests of the specified projects. Jest uses the attribute `displayName` in the configuration to identify each project. If you use this option, you should provide a `displayName` to all your projects.
Run the tests of the specified projects. Jest uses the attribute `displayName` in the configuration to identify each project. If you use this option, you should provide a `displayName` to all your projects.

### `--setupFilesAfterEnv <path1> ... <pathN>`

Expand Down
109 changes: 109 additions & 0 deletions e2e/__tests__/selectProjects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,89 @@ describe('Given a config with two named projects, first-project and second-proje
);
});
});

describe('when Jest is started with `--ignoreProjects first-project', () => {
let result: RunJestJsonResult;
beforeAll(() => {
result = runWithJson('select-projects', [
'--ignoreProjects',
'first-project',
]);
});
it('runs the tests in the second project only', () => {
expect(result.json).toHaveProperty('success', true);
expect(result.json).toHaveProperty('numTotalTests', 1);
expect(result.json.testResults.map(({name}) => name)).toEqual([
resolve(dir, '__tests__/second-project.test.js'),
]);
});
it('prints that only second-project will run', () => {
expect(result.stderr).toMatch(/^Running one project: second-project/);
});
});

describe('when Jest is started with `--ignoreProjects second-project', () => {
let result: RunJestJsonResult;
beforeAll(() => {
result = runWithJson('select-projects', [
'--ignoreProjects',
'second-project',
]);
});
it('runs the tests in the first project only', () => {
expect(result.json).toHaveProperty('success', true);
expect(result.json).toHaveProperty('numTotalTests', 1);
expect(result.json.testResults.map(({name}) => name)).toEqual([
resolve(dir, '__tests__/first-project.test.js'),
]);
});
it('prints that only first-project will run', () => {
expect(result.stderr).toMatch(/^Running one project: first-project/);
});
});

describe('when Jest is started with `--ignoreProjects third-project`', () => {
let result: RunJestJsonResult;
beforeAll(() => {
result = runWithJson('select-projects', [
'--ignoreProjects',
'third-project',
]);
});
it('runs the tests in the first and second projects', () => {
expect(result.json).toHaveProperty('success', true);
expect(result.json).toHaveProperty('numTotalTests', 2);
expect(result.json.testResults.map(({name}) => name).sort()).toEqual([
resolve(dir, '__tests__/first-project.test.js'),
resolve(dir, '__tests__/second-project.test.js'),
]);
});
it('prints that both first-project and second-project will run', () => {
expect(result.stderr).toMatch(
/^Running 2 projects:\n- first-project\n- second-project/,
);
});
});

describe('when Jest is started with `--ignoreProjects first-project second-project`', () => {
let result: RunJestResult;
beforeAll(() => {
result = run('select-projects', [
'--ignoreProjects',
'first-project',
'second-project',
]);
});
it('fails', () => {
expect(result).toHaveProperty('failed', true);
});
// FIXME(F3n67u)
it.skip('prints that no project was found', () => {
expect(result.stdout).toMatch(
/^You provided values for --selectProjects but no projects were found matching the selection/,
);
});
});
});

describe('Given a config with two projects, first-project and an unnamed project', () => {
Expand Down Expand Up @@ -185,4 +268,30 @@ describe('Given a config with two projects, first-project and an unnamed project
);
});
});

describe('when Jest is started with `--ignoreProjects first-project`', () => {
let result: RunJestJsonResult;
beforeAll(() => {
result = runWithJson('select-projects-missing-name', [
'--ignoreProjects',
'first-project',
]);
});
it('runs the tests in the second project only', () => {
expect(result.json.success).toBe(true);
expect(result.json.numTotalTests).toBe(1);
expect(result.json.testResults.map(({name}) => name)).toEqual([
resolve(dir, '__tests__/second-project.test.js'),
]);
});
it('prints that a project does not have a name', () => {
expect(result.stderr).toMatch(
/^You provided values for --ignoreProjects but a project does not have a name/,
);
});
it('prints that only second-project will run', () => {
const stderrThirdLine = result.stderr.split('\n')[2];
expect(stderrThirdLine).toMatch(/^Running one project: second-project/);
});
});
});
6 changes: 6 additions & 0 deletions packages/jest-cli/src/__tests__/cli/args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ describe('check', () => {
);
});

it('raises an exception if ignoreProjects is not provided any project names', () => {
expect(() => check(argv({ignoreProjects: []}))).toThrow(
'The --ignoreProjects option requires the name of at least one project to be specified.\n',
);
});

it('raises an exception if config is not a valid JSON string', () => {
expect(() => check(argv({config: 'x:1'}))).toThrow(
'The --config option requires a JSON string literal, or a file path with one of these extensions: .js, .ts, .mjs, .cjs, .json',
Expand Down
21 changes: 18 additions & 3 deletions packages/jest-cli/src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import type {Options} from 'yargs';
import type {Config} from '@jest/types';
import {constants, isJSONString} from 'jest-config';

Expand Down Expand Up @@ -68,6 +69,13 @@ export function check(argv: Config.Argv): true {
);
}

if (argv.ignoreProjects && argv.ignoreProjects.length === 0) {
throw new Error(
'The --ignoreProjects option requires the name of at least one project to be specified.\n' +
'Example usage: jest --ignoreProjects my-first-project my-second-project',
);
}

if (
argv.config &&
!isJSONString(argv.config) &&
Expand Down Expand Up @@ -95,7 +103,7 @@ export const usage =
export const docs = 'Documentation: https://jestjs.io/';

// The default values are all set in jest-config
export const options = {
export const options: {[key: string]: Options} = {
all: {
description:
'The opposite of `onlyChanged`. If `onlyChanged` is set by ' +
Expand Down Expand Up @@ -301,6 +309,13 @@ export const options = {
'A JSON string with map of variables for the haste module system',
type: 'string',
},
ignoreProjects: {
description:
'Ignore the tests of the specified projects.' +
'Jest uses the attribute `displayName` in the configuration to identify each project.',
string: true,
type: 'array',
},
init: {
description: 'Generate a basic configuration file',
type: 'boolean',
Expand Down Expand Up @@ -502,7 +517,7 @@ export const options = {
},
selectProjects: {
description:
'Run only the tests of the specified projects.' +
'Run the tests of the specified projects.' +
'Jest uses the attribute `displayName` in the configuration to identify each project.',
string: true,
type: 'array',
Expand Down Expand Up @@ -695,4 +710,4 @@ export const options = {
'--no-watchman.',
type: 'boolean',
},
} as const;
};
16 changes: 9 additions & 7 deletions packages/jest-core/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,18 @@ export async function runCLI(
exit(0);
}

let configsOfProjectsToRun = configs;
if (argv.selectProjects) {
const namesMissingWarning = getProjectNamesMissingWarning(configs);
const configsOfProjectsToRun = getConfigsOfProjectsToRun(configs, {
ignoreProjects: argv.ignoreProjects,
selectProjects: argv.selectProjects,
});
if (argv.selectProjects || argv.ignoreProjects) {
const namesMissingWarning = getProjectNamesMissingWarning(configs, {
ignoreProjects: argv.ignoreProjects,
selectProjects: argv.selectProjects,
});
if (namesMissingWarning) {
outputStream.write(namesMissingWarning);
}
configsOfProjectsToRun = getConfigsOfProjectsToRun(
argv.selectProjects,
configs,
);
outputStream.write(getSelectProjectsMessage(configsOfProjectsToRun));
}

Expand Down
32 changes: 29 additions & 3 deletions packages/jest-core/src/getConfigsOfProjectsToRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,38 @@ import type {Config} from '@jest/types';
import getProjectDisplayName from './getProjectDisplayName';

export default function getConfigsOfProjectsToRun(
namesOfProjectsToRun: Array<string>,
projectConfigs: Array<Config.ProjectConfig>,
opts: {
ignoreProjects: Array<string> | undefined;
selectProjects: Array<string> | undefined;
},
): Array<Config.ProjectConfig> {
const setOfProjectsToRun = new Set<string>(namesOfProjectsToRun);
const projectFilter = createProjectFilter(opts);
return projectConfigs.filter(config => {
const name = getProjectDisplayName(config);
return name && setOfProjectsToRun.has(name);
return projectFilter(name);
});
}

function createProjectFilter(opts: {
ignoreProjects: Array<string> | undefined;
selectProjects: Array<string> | undefined;
}) {
const {selectProjects, ignoreProjects} = opts;

const always = () => true;

const selected = selectProjects
? (name: string | undefined) => name && selectProjects.includes(name)
: always;

const notIgnore = ignoreProjects
? (name: string | undefined) => !name || !ignoreProjects.includes(name)
: always;

function test(name: string | undefined) {
return selected(name) && notIgnore(name);
}

return test;
}
13 changes: 12 additions & 1 deletion packages/jest-core/src/getProjectNamesMissingWarning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,26 @@ import getProjectDisplayName from './getProjectDisplayName';

export default function getProjectNamesMissingWarning(
projectConfigs: Array<Config.ProjectConfig>,
opts: {
ignoreProjects: Array<string> | undefined;
selectProjects: Array<string> | undefined;
},
): string | undefined {
const numberOfProjectsWithoutAName = projectConfigs.filter(
config => !getProjectDisplayName(config),
).length;
if (numberOfProjectsWithoutAName === 0) {
return undefined;
}
const args: Array<string> = [];
if (opts.selectProjects) {
args.push('--selectProjects');
}
if (opts.ignoreProjects) {
args.push('--ignoreProjects');
}
return chalk.yellow(
`You provided values for --selectProjects but ${
`You provided values for ${args.join(' and ')} but ${
numberOfProjectsWithoutAName === 1
? 'a project does not have a name'
: `${numberOfProjectsWithoutAName} projects do not have a name`
Expand Down
1 change: 1 addition & 0 deletions packages/jest-types/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ export type Argv = Arguments<
roots: Array<string>;
runInBand: boolean;
selectProjects: Array<string>;
ignoreProjects: Array<string>;
setupFiles: Array<string>;
setupFilesAfterEnv: Array<string>;
shard: string;
Expand Down