Skip to content

Commit 5cca005

Browse files
committed
add threshold-uncovered option
allows threshold to be set by number of uncovered lines instead of percentage of coverage. In a codebase which continuously grows, if you fix the number of lines uncovered then you (loosely) enforce that all new code should be covered. closes #168
1 parent ea09e05 commit 5cca005

20 files changed

+5978
-28
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"scripts": {
1616
"ava": "nyc ava --verbose",
1717
"build": "rimraf dist && babel -d dist src --only src/lib --source-maps",
18+
"dev": "babel -d dist src --only src/lib --source-maps --watch",
1819
"update-flow-typed": "rimraf flow-typed && flow-typed install -s -i dev",
1920
"flow-coverage": "bin/flow-coverage-report.js",
2021
"flow-check": "flow check",

src/__tests__/fixtures.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const FLOW_COVERAGE_SUMMARY_DATA = {
3333
covered_count: 5,
3434
uncovered_count: 5,
3535
threshold: 40,
36+
uncoveredThreshold: 3,
3637
percent: 50,
3738
globIncludePatterns: [firstGlob, secondGlob],
3839
files: allFiles.reduce((acc, filename) => {

src/__tests__/react-components/__snapshots__/test-coverage-meter-bar.js.snap

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`<FlowCoverageMeterBar /> 1`] = `
3+
exports[`<FlowCoverageMeterBar /> percent <= threshold 1`] = `
44
<div
55
className="row red"
66
style={
@@ -11,3 +11,15 @@ exports[`<FlowCoverageMeterBar /> 1`] = `
1111
}
1212
/>
1313
`;
14+
15+
exports[`<FlowCoverageMeterBar /> uncoveredCount <= thresholdUncovered 1`] = `
16+
<div
17+
className="row green"
18+
style={
19+
Object {
20+
"height": 12,
21+
"padding": 0,
22+
}
23+
}
24+
/>
25+
`;

src/__tests__/react-components/__snapshots__/test-coverage-summary-table.js.snap

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,45 @@ exports[`<FlowCoverageSummaryTable /> 2`] = `
8383
</tbody>
8484
</table>
8585
`;
86+
87+
exports[`<FlowCoverageSummaryTable /> 3`] = `
88+
<table
89+
className="ui small celled table"
90+
>
91+
<thead>
92+
<tr>
93+
<th>
94+
Percent
95+
</th>
96+
<th>
97+
Total
98+
</th>
99+
<th>
100+
Covered
101+
</th>
102+
<th>
103+
Uncovered
104+
</th>
105+
</tr>
106+
</thead>
107+
<tbody>
108+
<tr
109+
className="positive"
110+
>
111+
<td>
112+
50
113+
%
114+
</td>
115+
<td>
116+
10
117+
</td>
118+
<td>
119+
5
120+
</td>
121+
<td>
122+
5
123+
</td>
124+
</tr>
125+
</tbody>
126+
</table>
127+
`;

src/__tests__/react-components/test-coverage-meter-bar.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,26 @@ import {BASE_DIR} from './common';
99

1010
const REACT_COMPONENT = `${BASE_DIR}/coverage-meter-bar`;
1111

12-
test('<FlowCoverageMeterBar />', () => {
13-
const FlowCoverageMeterBar = require(REACT_COMPONENT).default;
14-
const props = {
15-
percent: 20,
16-
threshold: 80
17-
};
18-
const tree = renderer.create(<FlowCoverageMeterBar {...props}/>).toJSON();
19-
expect(tree).toMatchSnapshot();
12+
describe('<FlowCoverageMeterBar />', () => {
13+
test('percent <= threshold', () => {
14+
const FlowCoverageMeterBar = require(REACT_COMPONENT).default;
15+
const props = {
16+
percent: 20,
17+
threshold: 80
18+
};
19+
const tree = renderer.create(<FlowCoverageMeterBar {...props}/>).toJSON();
20+
expect(tree).toMatchSnapshot();
21+
});
22+
23+
test('uncoveredCount <= thresholdUncovered', () => {
24+
const FlowCoverageMeterBar = require(REACT_COMPONENT).default;
25+
const props = {
26+
uncoveredCount: 20,
27+
thresholdUncovered: 30
28+
};
29+
const tree = renderer.create(<FlowCoverageMeterBar {...props}/>).toJSON();
30+
expect(tree).toMatchSnapshot();
31+
});
2032
});
2133

2234
test.skip('<FlowCoverageMeterBar /> with missing props');

src/__tests__/react-components/test-coverage-summary-table.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,19 @@ test('<FlowCoverageSummaryTable />', () => {
2121
const positiveSummaryTree = renderer.create(<FlowCoverageSummaryTable {...positiveSummaryProps}/>).toJSON();
2222
expect(positiveSummaryTree).toMatchSnapshot();
2323

24-
// Expect positive with higher threshold.
24+
// Expect negative with higher threshold.
2525
const negativeSummaryProps = {
2626
coverageSummaryData: {...FLOW_COVERAGE_SUMMARY_DATA, threshold: 90}
2727
};
2828
const negativeSummaryTree = renderer.create(<FlowCoverageSummaryTable {...negativeSummaryProps}/>).toJSON();
2929
expect(negativeSummaryTree).toMatchSnapshot();
30+
31+
// Expect negative with uncovered_count >= thresholdUncovered
32+
const negativeSummaryUncoveredProps = {
33+
coverageSummaryData: {...FLOW_COVERAGE_SUMMARY_DATA, uncoveredThreshold: 4}
34+
};
35+
const negativeSummaryUncoveredTree = renderer.create(<FlowCoverageSummaryTable {...negativeSummaryUncoveredProps}/>).toJSON();
36+
expect(negativeSummaryUncoveredTree).toMatchSnapshot();
3037
});
3138

3239
test.skip('<FlowCoverageSummaryTable /> with missing props');

src/__tests__/test-flow.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ const testCollectFlowCoverage = async ({
430430
globIncludePatterns,
431431
globExcludePatterns,
432432
threshold: 80,
433+
thresholdUncovered: 3,
433434
concurrentFiles: 5,
434435
strictCoverage,
435436
excludeNonFlow
@@ -462,6 +463,7 @@ const testCollectFlowCoverage = async ({
462463
concurrentFiles: 5,
463464
percent: 50,
464465
threshold: 80,
466+
thresholdUncovered: 3,
465467
/* eslint-disable camelcase */
466468
covered_count: excludeNonFlow ? 4 : 5,
467469
uncovered_count: excludeNonFlow ? 4 : 5,

src/__tests__/test-index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,14 @@ it('generateFlowCoverageReport', async () => {
116116
expect(exception3 && exception3.message).toMatch(
117117
/empty globIncludePatterns option/
118118
);
119+
120+
let exception4;
121+
try {
122+
await generateFlowCoverageReport({...options, threshold: undefined, thresholdUncovered: undefined});
123+
} catch (err) {
124+
exception4 = err;
125+
}
126+
expect(exception4 && exception4.message).toMatch(
127+
/threshold or thresholdUncovered option is mandatory/
128+
);
119129
});

src/lib/cli/args.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export default function processArgv(argv: Array<string>): any {
7373
type: 'number',
7474
describe: `the minimum coverage percent requested (defaults to ${defaultConfig.threshold})`
7575
})
76+
.options('threshold-uncovered', {
77+
type: 'number',
78+
describe: `the maximum number of uncovered lines`
79+
})
7680
.options('percent-decimals', {
7781
alias: ['percentDecimanls'],
7882
type: 'number',

src/lib/cli/config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type ConfigParams = {|
1919
globExcludePatterns?: Array<string>,
2020
globIncludePatterns: Array<string>,
2121
threshold: number,
22+
thresholdUncovered: number,
2223
percentDecimals: number,
2324
outputDir: string,
2425
concurrentFiles?: number,
@@ -58,11 +59,12 @@ export const defaultConfig: DefaultConfigParams = {
5859
projectDir: path.resolve(process.cwd()),
5960
globExcludePatterns: ['node_modules/**'],
6061
globIncludePatterns: [],
61-
threshold: 80,
6262
percentDecimals: 0,
6363
outputDir: './flow-coverage',
6464
concurrentFiles: 1,
6565
strictCoverage: false,
66+
threshold: 80,
67+
thresholdUncovered: 0,
6668
excludeNonFlow: false,
6769
noConfig: false,
6870
htmlTemplateOptions: {

0 commit comments

Comments
 (0)