Skip to content

Commit

Permalink
Add combined coverage threshold for directories (#4885)
Browse files Browse the repository at this point in the history
* Add combined coverage threshold for directories

Add unit test for passing directory coverage

Add test for when there is no coverage data available

Fix type errors and make code more familiar

Run prettier on changed files

* Fix Windows bug

* Update changelog

* Update docs
  • Loading branch information
ttmarek authored and cpojer committed Nov 21, 2017
1 parent 0d065fb commit ddac1cf
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 75 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,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

0 comments on commit ddac1cf

Please sign in to comment.