Skip to content
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
142 changes: 81 additions & 61 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var attachMiddleware = require('./lib/attach-middleware');
var config = require('./lib/config');
const walkSync = require('walk-sync');
const VersionChecker = require('ember-cli-version-checker');
const concat = require('lodash.concat');

function requireBabelPlugin(pluginName) {
let plugin = require(pluginName);
Expand All @@ -22,6 +23,12 @@ function requireBabelPlugin(pluginName) {
return plugin;
}

function getPlugins(appOrAddon) {
let options = appOrAddon.options = appOrAddon.options || {};
options.babel = options.babel || {};
return options.babel.plugins = options.babel.plugins || [];
}

// Regular expression to extract the file extension from a path.
const EXT_RE = /\.[^\.]+$/;

Expand All @@ -45,11 +52,19 @@ module.exports = {
let checker = new VersionChecker(this.parent).for('ember-cli-babel', 'npm');

if (checker.satisfies('>= 6.0.0')) {
this.IstanbulPlugin = requireBabelPlugin('babel-plugin-istanbul');
const IstanbulPlugin = requireBabelPlugin('babel-plugin-istanbul');
const exclude = this._getExcludes();
const include = this._getIncludes();

concat(
this.app,
this._findCoveredAddon(),
this._findInRepoAddons()
)
.filter(Boolean)
.map(getPlugins)
.forEach((plugins) => plugins.push([IstanbulPlugin, { exclude, include }]));

this._instrumentAppDirectory();
this._instrumentAddonDirectory();
this._instrumentInRepoAddonDirectories();
} else {
this.project.ui.writeWarnLine(
'ember-cli-code-coverage: You are using an unsupported ember-cli-babel version,' +
Expand Down Expand Up @@ -96,83 +111,71 @@ module.exports = {
// Custom Methods

/**
* Instrument the "app" directory.
* Thin wrapper around exists-sync that allows easy stubbing in tests
* @param {String} path - path to check existence of
* @returns {Boolean} whether or not path exists
*/
_instrumentAppDirectory() {
const dir = path.join(this.project.root, 'app');
let prefix = this.parent.isEmberCLIAddon() ? 'dummy' : this.parent.name();
this._instrumentDirectory(this.app, dir, prefix);
_existsSync: function(path) {
return existsSync(path);
},

/**
* Instrument the "addon" directory.
* Get project configuration
* @returns {Configuration} project configuration
*/
_instrumentAddonDirectory() {
let addon = this._findCoveredAddon();
if (addon) {
const dir = path.join(this.project.root, 'addon');
this._instrumentDirectory(addon, dir, addon.name);
}
_getConfig: function() {
return config(this.project.configPath());
},

/**
* Instrument the in-repo-addon directories in "lib/*".
* Get paths to include for coverage
* @returns {Array<String>} include paths
*/
_instrumentInRepoAddonDirectories() {
const pkg = this.project.pkg;
if (pkg['ember-addon'] && pkg['ember-addon'].paths) {
pkg['ember-addon'].paths.forEach((addonPath) => {
let addonName = path.basename(addonPath);
let addonDir = path.join(this.project.root, addonPath);
let addon = this.project.findAddonByName(addonName);
let addonAppDir = path.join(addonDir, 'app');
let addonAddonDir = path.join(addonDir, 'addon');
this._instrumentDirectory(this.app, addonAppDir, this.parent.name());
this._instrumentDirectory(addon, addonAddonDir, addonName);
});
}
_getIncludes: function() {
return concat(
this._getIncludesForAppDirectory(),
this._getIncludesForAddonDirectory(),
this._getIncludesForInRepoAddonDirectories()
).filter(Boolean);
},

/**
* Instrument directory helper.
* @param {Object} appOrAddon The Ember app or addon config.
* @param {String} dir The path to the Ember app or addon.
* @param {String} modulePrefix The prefix to the ember module ('app', 'dummy' or the name of the addon).
* Get paths to include for covering the "app" directory.
* @returns {Array<String>} include paths
*/
_instrumentDirectory(appOrAddon, dir, modulePrefix) {
if (existsSync(dir)) {
let options = appOrAddon.options = appOrAddon.options || {};
options.babel = options.babel || {};
let plugins = options.babel.plugins = options.babel.plugins || [];
let include = this._getIncludes(dir, modulePrefix);
let plugin = plugins.find((plugin) => plugin[0] === this.IstanbulPlugin);
if (plugin) { // plugin already exists, so amend it rather than adding another one
plugin[1].include = plugin[1].include.concat(include);
} else {
plugins.push([this.IstanbulPlugin, {
exclude: this._getExcludes(),
include
}]);
}

}
_getIncludesForAppDirectory: function() {
const dir = path.join(this.project.root, 'app');
let prefix = this.parent.isEmberCLIAddon() ? 'dummy' : this.parent.name();
return this._getIncludesForDir(dir, prefix);
},

/**
* Thin wrapper around exists-sync that allows easy stubbing in tests
* @param {String} path - path to check existence of
* @returns {Boolean} whether or not path exists
* Get paths to include for covering the "addon" directory.
* @returns {Array<String>} include paths
*/
_existsSync: function(path) {
return existsSync(path);
_getIncludesForAddonDirectory: function() {
let addon = this._findCoveredAddon();
if (addon) {
const dir = path.join(this.project.root, 'addon');
return this._getIncludesForDir(dir, addon.name);
}
},

/**
* Get project configuration
* @returns {Configuration} project configuration
* Get paths to include for covering the in-repo-addon directories in "lib/*".
* @returns {Array<String>} include paths
*/
_getConfig: function() {
return config(this.project.configPath());
_getIncludesForInRepoAddonDirectories: function() {
return this._findInRepoAddons().reduce((acc, addon) => {
let addonDir = path.join(this.project.root, 'lib', addon.name);
let addonAppDir = path.join(addonDir, 'app');
let addonAddonDir = path.join(addonDir, 'addon');
return concat(
acc,
this._getIncludesForDir(addonAppDir, this.parent.name()),
this._getIncludesForDir(addonAddonDir, addon.name)
);
}, []);
},

/**
Expand All @@ -181,7 +184,7 @@ module.exports = {
* @param {String} prefix The prefix to the ember module ('app', 'dummy' or the name of the addon).
* @returns {Array<String>} include paths
*/
_getIncludes: function(dir, prefix) {
_getIncludesForDir: function(dir, prefix) {
let dirname = path.relative(this.project.root, dir);
let globs = this.registry.extensionsForType('js').map((extension) => `**/*.${extension}`);

Expand Down Expand Up @@ -236,5 +239,22 @@ module.exports = {
}

return this._coveredAddon;
},

/**
* Find the app's in-repo addons (if any).
* @returns {Array<Addon>} the in-repo addons
*/
_findInRepoAddons: function() {
if (!this._inRepoAddons) {
const pkg = this.project.pkg;
const inRepoAddonPaths = pkg['ember-addon'] && pkg['ember-addon'].paths;
this._inRepoAddons = (inRepoAddonPaths || []).map((addonPath) => {
let addonName = path.basename(addonPath);
return this.project.findAddonByName(addonName);
});
}

return this._inRepoAddons;
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"extend": "^3.0.0",
"fs-extra": "^5.0.0",
"istanbul-api": "^1.1.14",
"lodash.concat": "^4.5.0",
"node-dir": "^0.1.16",
"rsvp": "^4.8.1",
"walk-sync": "^0.3.2"
Expand Down
2 changes: 1 addition & 1 deletion test/integration/app-coverage-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let app;
describe('app coverage generation', function() {
this.timeout(10000000);
beforeEach(function() {
app = new AddonTestApp();
app = new AddonTestApp({ skipNpm: true });
return app.create('my-app', {
emberVersion: '2.16.0'
}).then(() => {
Expand Down
6 changes: 4 additions & 2 deletions test/integration/in-repo-addon-coverage-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let app;
describe('in-repo addon coverage generation', function() {
this.timeout(10000000);
beforeEach(function() {
app = new AddonTestApp();
app = new AddonTestApp({ skipNpm: true });
return app.create('my-app-with-in-repo-addon', {
emberVersion: '2.16.0'
}).then(() => {
Expand Down Expand Up @@ -50,7 +50,9 @@ describe('in-repo addon coverage generation', function() {
expect(file(`${app.path}/coverage/lcov-report/index.html`)).to.not.be.empty;
expect(file(`${app.path}/coverage/index.html`)).to.not.be.empty;
var summary = fs.readJSONSync(`${app.path}/coverage/coverage-summary.json`);
expect(summary.total.lines.pct).to.equal(83.33);
expect(summary.total.lines.pct).to.equal(75);
expect(summary['app/utils/my-covered-util-app.js'].lines.total).to.equal(1);
expect(summary['lib/my-in-repo-addon/addon/utils/my-covered-util.js'].lines.total).to.equal(1);
});
}));
});
Loading