Skip to content
Open
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
1 change: 1 addition & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry "https://registry.yarnpkg.com"
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,45 @@ If you are using [`ember-cli-pretender`](https://github.com/rwjblue/ember-cli-pr
});
```

## Testing code coverage goals

You can also test for code coverage goals with the included command `ember test-code-coverage`.

It takes the following parameters:

* target-lines: The target percentage for lines covered
* target-functions: The target percentage for functions covered
* target-statements: The target percentage for statements covered
* target-branches: The target percentage for branches covered

For example: `ember test-code-coverage -target-lines=80 -target-branches=85`

You can also configure those in the `config/coverage.js` file, in their camel cased form, like this:

```js
module.exports = {
targetLines: 80,
targetFunctions: 85.5,

// Other configuration
coverageEnvVar: 'COV'
}
```

These values will then be the defaults when running `ember test-code-coverage`.

Running the command will output something like this to your console:

```diff
+ Lines covered: 60.00% 69.17%
+ Functions covered: --.--% 72.18%
+ Statements covered: --.--% 68.93%
- Branches covered: 70.00% 60.16%
- Test coverage check failed
```

For any type of check where no target is specified, it will simply output the actual value without doing any comparison.

## Inspiration

This addon was inspired by [`ember-cli-blanket`](https://github.com/sglanzer/ember-cli-blanket).
Expand Down
6 changes: 6 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,5 +274,11 @@ module.exports = {
}

return this._inRepoAddons;
},

includedCommands: function() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may need to be rebased; there's already an includedCommands hook

return {
'test-code-coverage': require('./lib/commands/test-code-coverage')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer we name it code-coverage:test or code-coverage-test

};
}
};
160 changes: 160 additions & 0 deletions lib/commands/test-code-coverage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
'use strict';

let fs = require('fs');
let path = require('path');
let chalk = require('chalk');
let RSVP = require('rsvp');

function camelize(str) {
str = str.split('-').map((str) => str.charAt(0).toUpperCase() + str.slice(1)).join('');
return str.charAt(0).toLowerCase() + str.slice(1);
}

module.exports = {

name: 'test-code-coverage',
description: 'Test the generated code coverage against given goals.',
works: 'insideProject',

availableOptions: [
{
name: 'coverage-folder',
type: String,
aliases: ['i'],
default: './coverage',
description: 'Directory of the coverage report'
},
{
name: 'target-lines',
type: Number,
aliases: ['tl'],
description: 'The target percentage of lines to reach, e.g. 50 = 50% coverage minimum'
},
{
name: 'target-statements',
type: Number,
aliases: ['ts'],
description: 'The target percentage of statements to reach, e.g. 50 = 50% coverage minimum'
},
{
name: 'target-functions',
type: Number,
aliases: ['tf'],
description: 'The target percentage of functions to reach, e.g. 50 = 50% coverage minimum'
},
{
name: 'target-branches',
type: Number,
aliases: ['tb'],
description: 'The target percentage of branches to reach, e.g. 50 = 50% coverage minimum'
}
],

/**
* Tries to extend `availableOptions` with globals from config.
*
* @public
* @method beforeRun
* @return {Void}
*/
beforeRun() {
this._super.apply(this, arguments);

// try to read global options from `config/coverage.js`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the util at lib/config.js to get the configuration and and the project's configPath for the location of the config (see https://github.com/kategengler/ember-cli-code-coverage/blob/master/index.js#L142)

let configOptions = {};
let module = path.join(this.project.root, 'config', 'coverage');

try {
configOptions = require(module);
if (typeof configOptions === 'function') {
configOptions = configOptions();
}
} catch(e) {
// do nothing, ignore the config
}

// For all options that are specified in config/coverage.js, set the value there to be the actual default value
this.availableOptions.map((option) => {
let normalizedName = camelize(option.name);
let configOption = configOptions[normalizedName];

if (configOption !== undefined) {
option.default = configOption;
return option;
}

return option;
});
},

run(options) {
return new RSVP.Promise((resolve, reject) => {
let jsonSummaryPath = path.join(options.coverageFolder, 'coverage-summary.json');

// Try to read coverage-summary.json
let file = null;
try {
file = fs.readFileSync(jsonSummaryPath, 'utf8');
} catch(e) {
this.ui.writeLine(chalk.red(`Could not read coverage report at ${jsonSummaryPath}, maybe you haven't generated a report yet?`));
return reject();
}

// Try to load JSON content from the file
let jsonSummary = null;
try {
jsonSummary = JSON.parse(file);
} catch(e) {
this.ui.writeLine(chalk.red(`Could not read JSON content from the file at ${jsonSummaryPath}.`));
return reject();
}

// Check lines, functions, statements & branches covered
let linesCovered = this._comparePercentages(jsonSummary.total.lines.pct, options.targetLines, 'Lines covered: ');
let functionsCovered = this._comparePercentages(jsonSummary.total.functions.pct, options.targetFunctions, 'Functions covered: ');
let statementsCovered = this._comparePercentages(jsonSummary.total.statements.pct, options.targetStatements, 'Statements covered:');
let branchesCovered = this._comparePercentages(jsonSummary.total.branches.pct, options.targetBranches, 'Branches covered: ');

if (!linesCovered || !functionsCovered || !statementsCovered || !branchesCovered) {
this.ui.writeLine(chalk.red('Test coverage check failed'));
return reject();
}

resolve();
});
},

/**
* Compare a given percentage with a comparison percentage.
* If no comparisonValue is given, it will just print out the actual value,
* without doing any assertions.
*
* This will print a line like this:
* Lines covered: 80.00% 81.23%
*
* @method _comparePercentages
* @param {Number} value The actual percentage value
* @param {Number} comparisonValue The percentage value that should be reached
* @param {String} title The prefix to add before the values, e.g. "Lines covered: "
* @return {Boolean}
* @private
*/
_comparePercentages(value, comparisonValue, title) {
if (!comparisonValue) {
this.ui.writeLine(chalk.green(`${title} --.--% ${value.toFixed(2)}%`));
return true;
}

// Normalize 0.5 to 60
if (value < 1) {
value *= 50;
}

let isSuccess = value >= comparisonValue;
let chalkColor = isSuccess ? chalk.green : chalk.red;

this.ui.writeLine(chalkColor(`${title} ${comparisonValue.toFixed(2)}% ${value.toFixed(2)}%`));

return isSuccess;
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-transform-async-to-generator": "^6.24.1",
"body-parser": "^1.15.0",
"chalk": "^2.3.1",
"co": "^4.6.0",
"ember-cli-babel": "^6.6.0",
"ember-cli-htmlbars": "^2.0.1",
Expand Down
26 changes: 19 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"

ansi-styles@^3.0.0, ansi-styles@^3.1.0:
ansi-styles@^3.0.0, ansi-styles@^3.1.0, ansi-styles@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
Expand Down Expand Up @@ -1508,6 +1508,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"

chalk@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
dependencies:
ansi-styles "^3.2.0"
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"

chardet@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
Expand Down Expand Up @@ -3450,6 +3458,10 @@ has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"

has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"

has-symbol-support-x@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz#66ec2e377e0c7d7ccedb07a3a84d77510ff1bc4c"
Expand Down Expand Up @@ -5031,12 +5043,6 @@ no-case@^2.2.0:
dependencies:
lower-case "^1.1.1"

node-dir@^0.1.16:
version "0.1.17"
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
dependencies:
minimatch "^3.0.2"

node-fetch-npm@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7"
Expand Down Expand Up @@ -6486,6 +6492,12 @@ supports-color@^5.1.0:
dependencies:
has-flag "^2.0.0"

supports-color@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
dependencies:
has-flag "^3.0.0"

symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.3, symlink-or-copy@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3"
Expand Down