Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add combined coverage threshold for directories #4885

Merged
merged 4 commits into from
Nov 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

### Features

* `[jest-cli]` Add combined coverage threshold for directories.
([#4885](https://github.com/facebook/jest/pull/4885))
* `[jest-mock]` Add `timestamps` to mock state.
([#4866](https://github.com/facebook/jest/pull/4866))
* `[eslint-plugin-jest]` Add `prefer-to-have-length` lint rule.
Expand Down
59 changes: 44 additions & 15 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,37 @@ _Note: Setting this option overwrites the default values. Add `"text"` or
Default: `undefined`

This will be used to configure minimum threshold enforcement for coverage
results. If the thresholds are not met, jest will return failure. Thresholds,
when specified as a positive number are taken to be the minimum percentage
required. When a threshold is specified as a negative number it represents the
maximum number of uncovered entities allowed. Thresholds can be specified as
`global`, as `glob` paths or just paths. If globs or paths are specified
alongside `global`, coverage data for matching paths will be subtracted from
overall coverage and thresholds will be applied independently. Threshold for
globs is applied to all files matching the glob. If the file specified by path
is not found, error is returned.

For example, statements: 90 implies minimum statement coverage is 90%.
statements: -10 implies that no more than 10 uncovered statements are allowed.
`global` branch threshold 50 will be applied to all files minus matching
`./src/components/**/*.js` and `./src/api/very-important-module.js`.
results. Thresholds can be specified as `global`, as
a [glob](https://github.com/isaacs/node-glob#glob-primer), and as a directory or
file path. If thresholds aren't met, jest will fail. Thresholds specified as a
positive number are taken to be the minimum percentage required. Thresholds
specified as a negative number represent the maximum number of uncovered
entities allowed.

For example, with the following configuration jest will fail if there is less than 80% branch, line, and function coverage, or if there are more than 10 uncovered statements:

```json
{
...
"jest": {
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": -10
}
}
}
}
```

If globs or paths are specified alongside `global`, coverage data for matching
paths will be subtracted from overall coverage and thresholds will be applied
independently. Thresholds for globs are applied to all files matching the
glob. If the file specified by path is not found, error is returned.

For example, with the following configuration:

```json
{
Expand All @@ -191,10 +208,13 @@ statements: -10 implies that no more than 10 uncovered statements are allowed.
"lines": 50,
"statements": 50
},
"./src/components/**/*.js": {
"./src/components/": {
"branches": 40,
"statements": 40
},
"./src/reducers/**/*.js": {
"statements": 90,
},
"./src/api/very-important-module.js": {
"branches": 100,
"functions": 100,
Expand All @@ -206,6 +226,15 @@ statements: -10 implies that no more than 10 uncovered statements are allowed.
}
```

Jest will fail if:

- The `./src/components` directory has less than 40% branch or statement coverage.
- One of the files matching the `./src/reducers/**/*.js` glob has less than 90%
statement coverage.
- The `./src/api/very-important-module.js` file has less than 100% coverage.
- Every remaining file combined has less than 50% coverage (`global`).


### `globals` [object]

Default: `{}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ describe('onRunComplete', () => {
});
});

it('getLastError() returns an error when threshold is not met for global', () => {
test('getLastError() returns an error when threshold is not met for global', () => {
const testReporter = new CoverageReporter(
{
collectCoverage: true,
Expand All @@ -134,7 +134,7 @@ describe('onRunComplete', () => {
});
});

it('getLastError() returns an error when threshold is not met for file', () => {
test('getLastError() returns an error when threshold is not met for file', () => {
const covThreshold = {};
[
'global',
Expand Down Expand Up @@ -164,7 +164,7 @@ describe('onRunComplete', () => {
});
});

it('getLastError() returns `undefined` when threshold is met', () => {
test('getLastError() returns `undefined` when threshold is met', () => {
const covThreshold = {};
[
'global',
Expand Down Expand Up @@ -194,7 +194,7 @@ describe('onRunComplete', () => {
});
});

it('getLastError() returns an error when threshold is for non-covered file', () => {
test('getLastError() returns an error when threshold is not met for non-covered file', () => {
const testReporter = new CoverageReporter(
{
collectCoverage: true,
Expand All @@ -215,4 +215,70 @@ describe('onRunComplete', () => {
expect(testReporter.getLastError().message.split('\n')).toHaveLength(1);
});
});

test('getLastError() returns an error when threshold is not met for directory', () => {
const testReporter = new CoverageReporter(
{
collectCoverage: true,
coverageThreshold: {
'./path-test-files/glob-path/': {
statements: 100,
},
},
},
{
maxWorkers: 2,
},
);
testReporter.log = jest.fn();
return testReporter
.onRunComplete(new Set(), {}, mockAggResults)
.then(() => {
expect(testReporter.getLastError().message.split('\n')).toHaveLength(1);
});
});

test('getLastError() returns `undefined` when threshold is met for directory', () => {
const testReporter = new CoverageReporter(
{
collectCoverage: true,
coverageThreshold: {
'./path-test-files/glob-path/': {
statements: 40,
},
},
},
{
maxWorkers: 2,
},
);
testReporter.log = jest.fn();
return testReporter
.onRunComplete(new Set(), {}, mockAggResults)
.then(() => {
expect(testReporter.getLastError()).toBeUndefined();
});
});

test('getLastError() returns an error when there is no coverage data for a threshold', () => {
const testReporter = new CoverageReporter(
{
collectCoverage: true,
coverageThreshold: {
'./path/doesnt/exist': {
statements: 40,
},
},
},
{
maxWorkers: 2,
},
);
testReporter.log = jest.fn();
return testReporter
.onRunComplete(new Set(), {}, mockAggResults)
.then(() => {
expect(testReporter.getLastError().message.split('\n')).toHaveLength(1);
});
});
});
Loading