diff --git a/README.md b/README.md index 3ee53007..8a8f8029 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,8 @@ Configuration is optional. It should be put in a file at `config/coverage.js` (` - `parallel`: Defaults to `false`. Should be set to true if parallel testing is being used for separate test runs, for example when using [ember-exam](https://github.com/trentmwillis/ember-exam) with the `--partition` flag. This will generate the coverage reports in directories suffixed with `_` to avoid overwriting other threads reports. These reports can be joined by using the `ember coverage-merge` command (potentially as part of the [posttest hook](https://docs.npmjs.com/misc/scripts) in your `package.json`). +- `modifyAssetLocation`: Optional function that will allow you to override where a file actually lives inside of your project. See [Advanced customization](#modifyassetlocation) on how to use this function in practice. + #### Example ```js module.exports = { @@ -190,7 +192,9 @@ If you are using [`ember-cli-pretender`](https://github.com/rwjblue/ember-cli-pr ## Advanced customization -The `forceModulesToBeLoaded` can potientally cause unindented side effects when executed. You can pass custom filter fuctions that allow +### `forceModulesToBeLoaded` + +The `forceModulesToBeLoaded` function can potentially cause unintended side effects when executed. You can pass custom filter fuctions that allow you to specify which modules will be force loaded or not: ```js @@ -201,28 +205,28 @@ QUnit.done(async () => { }); ``` +### `modifyAssetLocation` + Under the hood, `ember-cli-code-coverage` attempts to "de-namespacify" paths into their real on disk location inside of `project.root` (ie give a namespaced path like lib/inrepo/components/foo.js would live in lib/inrepo/addon/components/foo.js). It makes some assumptions (where files live in in-repo addons vs app code for example) and sometimes those assumptions might not hold. Passing a -function `modifyAssetLocation` will allow you to override where a file actually lives inside of your project. The returned string should -be relative to your project root. +function `modifyAssetLocation` in your [configuration file](#configuration) will allow you to override where a file actually lives inside +of your project. The returned string should be relative to your project root. ```js -const app = new EmberApp(defaults, { - 'ember-cli-code-coverage': { - modifyAssetLocation(root, relativePath) { - let appPath = relativePath.replace('my-project-name', 'app'); - - // here is an example of saying that `app/components/foo.js` actually - // lives in `lib/inrepo/app/components/foo.js` on disk. - if (fs.existsSync(path.join(root, 'lib/inrepo', appPath))) { - return path.join('lib/inrepo', appPath); - } - - return false; - }, +module.exports = { + modifyAssetLocation(root, relativePath) { + let appPath = relativePath.replace('my-project-name', 'app'); + + // here is an example of saying that `app/components/foo.js` actually + // lives in `lib/inrepo/app/components/foo.js` on disk. + if (fs.existsSync(path.join(root, 'lib', 'inrepo', appPath))) { + return path.join('lib', 'inrepo', appPath); + } + + return false; }, -}); +}; ``` ## Inspiration diff --git a/packages/ember-cli-code-coverage/index.js b/packages/ember-cli-code-coverage/index.js index 35918811..1ac62d50 100644 --- a/packages/ember-cli-code-coverage/index.js +++ b/packages/ember-cli-code-coverage/index.js @@ -71,12 +71,6 @@ module.exports = { }; }, - included(app) { - this._super.included.apply(this, arguments); - let config = app.options[this.name] || {}; - this.modifyAssetLocation = config && config.modifyAssetLocation; - }, - buildNamespaceMappings() { let rootNamespaceMappings = new Map(); function recurse(item) { @@ -124,9 +118,7 @@ module.exports = { attachMiddleware.serverMiddleware(startOptions.app, { configPath: this.project.configPath(), root: this.project.root, - fileLookup: this.fileLookup, namespaceMappings: this.buildNamespaceMappings(), - modifyAssetLocation: this.modifyAssetLocation, }); }, @@ -134,9 +126,7 @@ module.exports = { const config = { configPath: this.project.configPath(), root: this.project.root, - fileLookup: this.fileLookup, namespaceMappings: this.buildNamespaceMappings(), - modifyAssetLocation: this.modifyAssetLocation, }; // if we're running `ember test --server` use the `serverMiddleware`. if (process.argv.includes('--server') || process.argv.includes('-s')) { diff --git a/packages/ember-cli-code-coverage/lib/attach-middleware.js b/packages/ember-cli-code-coverage/lib/attach-middleware.js index 39b0887c..a27af1c0 100644 --- a/packages/ember-cli-code-coverage/lib/attach-middleware.js +++ b/packages/ember-cli-code-coverage/lib/attach-middleware.js @@ -112,7 +112,9 @@ function adjustCoverageKey( } function adjustCoverage(coverage, options) { - let { root, namespaceMappings, modifyAssetLocation } = options; + let { root, namespaceMappings, configPath } = options; + let { modifyAssetLocation } = getConfig(configPath); + const adjustedCoverage = Object.keys(coverage).reduce((memo, filePath) => { let relativeToProjectRoot = adjustCoverageKey( root, diff --git a/test-packages/__snapshots__/in-repo-addon-test.js.snap b/test-packages/__snapshots__/in-repo-addon-test.js.snap index 3346f738..676b60fe 100644 --- a/test-packages/__snapshots__/in-repo-addon-test.js.snap +++ b/test-packages/__snapshots__/in-repo-addon-test.js.snap @@ -342,3 +342,346 @@ Object { }, } `; + +exports[`in-repo addon coverage generation runs coverage when the path option is used 1`] = ` +Object { + "app/app.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "lines": Object { + "covered": 4, + "pct": 100, + "skipped": 0, + "total": 4, + }, + "statements": Object { + "covered": 4, + "pct": 100, + "skipped": 0, + "total": 4, + }, + }, + "app/router.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 1, + "pct": 33.33, + "skipped": 0, + "total": 3, + }, + "statements": Object { + "covered": 1, + "pct": 33.33, + "skipped": 0, + "total": 3, + }, + }, + "app/services/my-service.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + }, + "app/utils/my-covered-util-app.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + }, + "app/utils/my-uncovered-util-app.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + }, + "lib/my-in-repo-addon/addon-test-support/uncovered-test-support.js": Object { + "branches": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 2, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 2, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 4, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 4, + }, + }, + "lib/my-in-repo-addon/addon/services/my-service.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + }, + "lib/my-in-repo-addon/addon/utils/my-covered-util.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + }, + "lib/my-in-repo-addon/addon/utils/my-uncovered-util.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 1, + }, + }, + "lib/my-in-repo-addon/app/utils/my-covered-util.js": Object { + "branches": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + }, + "lib/my-in-repo-addon/app/utils/my-in-repo-addon-app-covered-util.js": Object { + "branches": Object { + "covered": 0, + "pct": 100, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "lines": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + "statements": Object { + "covered": 1, + "pct": 100, + "skipped": 0, + "total": 1, + }, + }, + "lib/my-in-repo-addon/app/utils/my-uncovered-util.js": Object { + "branches": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "functions": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "lines": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + "statements": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 0, + }, + }, + "total": Object { + "branches": Object { + "covered": 0, + "pct": 0, + "skipped": 0, + "total": 2, + }, + "functions": Object { + "covered": 4, + "pct": 40, + "skipped": 0, + "total": 10, + }, + "lines": Object { + "covered": 9, + "pct": 50, + "skipped": 0, + "total": 18, + }, + "statements": Object { + "covered": 9, + "pct": 50, + "skipped": 0, + "total": 18, + }, + }, +} +`; diff --git a/test-packages/in-repo-addon-test.js b/test-packages/in-repo-addon-test.js index 98dffa2b..d22698bb 100644 --- a/test-packages/in-repo-addon-test.js +++ b/test-packages/in-repo-addon-test.js @@ -35,4 +35,17 @@ describe('in-repo addon coverage generation', function () { const summary = fs.readJSONSync(`${BASE_PATH}/coverage/coverage-summary.json`); expect(summary).toMatchSnapshot(); }); + + it('runs coverage when the path option is used', async function () { + dir(`${BASE_PATH}/coverage`).assertDoesNotExist(); + + let env = { COVERAGE: 'true' }; + await execa('ember', ['build', '--output-path=test-dist'], { cwd: BASE_PATH, env }); + await execa('ember', ['test', '--path=test-dist'], { cwd: BASE_PATH, env }); + file(`${BASE_PATH}/coverage/lcov-report/index.html`).assertIsNotEmpty(); + file(`${BASE_PATH}/coverage/index.html`).assertIsNotEmpty(); + + let summary = fs.readJSONSync(`${BASE_PATH}/coverage/coverage-summary.json`); + expect(summary).toMatchSnapshot(); + }); }); diff --git a/test-packages/my-app-with-in-repo-addon/config/coverage.js b/test-packages/my-app-with-in-repo-addon/config/coverage.js index e3724c51..e13cb695 100644 --- a/test-packages/my-app-with-in-repo-addon/config/coverage.js +++ b/test-packages/my-app-with-in-repo-addon/config/coverage.js @@ -1,3 +1,16 @@ +const fs = require('fs'); +const path = require('path'); + module.exports = { - reporters: ['lcov', 'html', 'text', 'json-summary'] + reporters: ['lcov', 'html', 'text', 'json-summary'], + + modifyAssetLocation(root, relativePath) { + let appPath = relativePath.replace('my-app-with-in-repo-addon', 'app'); + + if (!fs.existsSync(appPath) && fs.existsSync(path.join(root, 'lib', 'my-in-repo-addon', appPath))) { + return path.join('lib', 'my-in-repo-addon', appPath); + } + + return false; + } }; diff --git a/test-packages/my-app-with-in-repo-addon/ember-cli-build.js b/test-packages/my-app-with-in-repo-addon/ember-cli-build.js index 9c8ecf5a..2a14f907 100644 --- a/test-packages/my-app-with-in-repo-addon/ember-cli-build.js +++ b/test-packages/my-app-with-in-repo-addon/ember-cli-build.js @@ -1,8 +1,6 @@ 'use strict'; const EmberApp = require('ember-cli/lib/broccoli/ember-app'); -const fs = require('fs'); -const path = require('path'); module.exports = function(defaults) { let app = new EmberApp(defaults, { @@ -11,17 +9,6 @@ module.exports = function(defaults) { ...require('ember-cli-code-coverage').buildBabelPlugin(), ], }, - 'ember-cli-code-coverage': { - modifyAssetLocation(root, relativePath) { - let appPath = relativePath.replace('my-app-with-in-repo-addon', 'app'); - - if (!fs.existsSync(appPath) && fs.existsSync(path.join(root, 'lib/my-in-repo-addon', appPath))) { - return path.join('lib/my-in-repo-addon', appPath); - } - - return false; - } - } }); // Use `app.import` to add additional libraries to the generated