Skip to content

Commit

Permalink
Add coverage logic for gjs/gts files (#405)
Browse files Browse the repository at this point in the history
Update pnpm version to fix invalid string error

Fix emroider comparibility

bump @embroider/addon-dev and assert sorcemap remap is working

Add a comment why we need to cleanup .embroider folder between test runs

Improve docs and add more comment explanations

remove explicit extensions from test app

bring back babel transpilation plugin

Fix type



Fix typo 2

Co-authored-by: Sergey Astapov <SergeAstapov@gmail.com>
  • Loading branch information
vstefanovic97 and SergeAstapov committed Feb 22, 2024
1 parent ab83a79 commit 32ef303
Show file tree
Hide file tree
Showing 81 changed files with 21,078 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8.10.3
version: 8.15.1
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ Configuration is optional. It should be put in a file at `config/coverage.js` (`

- `excludes`: Defaults to `['*/mirage/**/*']`. An array of globs to exclude from instrumentation. Useful to exclude files from coverage statistics.

- `extension`: Defaults to `['.gjs', '.gts', '.js', '.ts', '.cjs', '.mjs', '.mts', '.cts']`. Tell Istanbul to instrument only files with the provided extensions.

- `coverageFolder`: Defaults to `coverage`. A folder relative to the root of your project to store coverage results.

- `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 `_<random_string>` 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`).
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"test": "vitest"
},
"devDependencies": {
"@babel/core": "^7.23.9",
"@release-it-plugins/lerna-changelog": "^6.0.0",
"@release-it-plugins/workspaces": "^4.0.0",
"chai-files": "^1.4.0",
Expand Down Expand Up @@ -46,6 +47,6 @@
"version": "2.0.3",
"volta": {
"node": "16.20.2",
"pnpm": "8.10.2"
"pnpm": "8.15.1"
}
}
24 changes: 23 additions & 1 deletion packages/ember-cli-code-coverage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ module.exports = {
buildBabelPlugin(opts = {}) {
let cwd = opts.cwd || process.cwd();
let exclude = ['*/mirage/**/*', '*/node_modules/**/*'];
let extension = [
'.gjs',
'.gts',
'.js',
'.ts',
'.cjs',
'.mjs',
'.mts',
'.cts',
];
let coverageEnvVar = 'COVERAGE';
let configBase = 'config';

Expand All @@ -48,19 +58,25 @@ module.exports = {
if (config.coverageEnvVar) {
coverageEnvVar = config.coverageEnvVar;
}

if (config.extension) {
extension = config.extension;
}
}

if (process.env[coverageEnvVar] !== 'true') {
return [];
}

let useStringLookupForPlugin = false;
if (opts.embroider === true) {
try {
// Attempt to import the utility @embroider/compat uses in >3.1 to locate the embroider working directory
// the presence of this `locateEmbroiderWorkingDir` method coincides with the shift to utilize `rewritten-app` tmp dir
// eslint-disable-next-line node/no-missing-require
let { locateEmbroiderWorkingDir } = require('@embroider/core');
cwd = path.resolve(locateEmbroiderWorkingDir(cwd), 'rewritten-app');
useStringLookupForPlugin = true;
} catch (err) {
// otherwise, fall back to the method used in embroider <3.1
let {
Expand All @@ -72,7 +88,13 @@ module.exports = {
}

const IstanbulPlugin = require.resolve('babel-plugin-istanbul');
return [[IstanbulPlugin, { cwd, include: '**/*', exclude }]];
return [
// String lookup is needed to workaround https://github.com/embroider-build/embroider/issues/1525
useStringLookupForPlugin
? 'ember-cli-code-coverage/lib/gjs-gts-istanbul-ignore-template-plugin'
: require('./lib/gjs-gts-istanbul-ignore-template-plugin'),
[IstanbulPlugin, { cwd, include: '**/*', exclude, extension }],
];
},

includedCommands() {
Expand Down
20 changes: 14 additions & 6 deletions packages/ember-cli-code-coverage/lib/attach-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const getConfig = require('./config');
const path = require('path');
const crypto = require('crypto');
const fs = require('fs-extra');
const libSourceMaps = require('istanbul-lib-source-maps');

const sourceMapStore = libSourceMaps.createSourceMapStore();

const WRITE_COVERAGE = '/write-coverage';

Expand Down Expand Up @@ -134,17 +137,22 @@ function adjustCoverage(coverage, options) {
namespaceMappings,
modifyAssetLocation
);
coverage[filePath].path = path.relative(root, relativeToProjectRoot);
memo[path.relative(root, relativeToProjectRoot)] = coverage[filePath];
coverage[filePath].data.path = path.relative(root, relativeToProjectRoot);
memo[path.relative(root, relativeToProjectRoot)] = coverage[filePath].data;
return memo;
}, {});

return adjustedCoverage;
}

function writeCoverage(coverage, options, map) {
async function writeCoverage(coverage, options, map) {
let { root } = options;
const adjustedCoverage = adjustCoverage(coverage, options);

const remappedCoverage = await sourceMapStore.transformCoverage(
libCoverage.createCoverageMap(coverage)
);

const adjustedCoverage = adjustCoverage(remappedCoverage.data, options);

Object.entries(adjustedCoverage).forEach(([relativePath, cov]) => {
// this filters out files that dont reside within the project
Expand Down Expand Up @@ -187,8 +195,8 @@ function reportCoverage(map, root, configPath) {
});
}

function coverageHandler(map, options, req, res) {
writeCoverage(req.body, options, map);
async function coverageHandler(map, options, req, res) {
await writeCoverage(req.body, options, map);
reportCoverage(map, options.root, options.configPath);

res.send(map.getCoverageSummary().toJSON());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* When gjs/gts is converted to js it looks like this
*
* @example
* template(`
* <div>
* template code
* </div>`
* , {
* eval() {
* return eval(arguments[0]);
* }
*});
*
* The problem is Istanbul's babel plugin will try to instrument the `eval` method which can skew coverage results.
* In order to avoid this we add this plugin to add Istanbul ignore comments above `eval` to make sure it won't be instrumented by babel
*/
const gjsGtsTemplateIgnoreVisitor = {
CallExpression(path) {
const { node } = path;
let { callee } = node;

if (callee.name !== 'template') {
return;
}

const callScopeBinding = path.scope.getBinding('template');

if (
callScopeBinding.kind === 'module' &&
callScopeBinding.path.parent.source.value === '@ember/template-compiler'
) {
const babelIgnoreComment = {
type: 'CommentBlock',
value: ' istanbul ignore next ',
};

if (!path.findParent((path) => path.isStatement()).node.leadingComments) {
path.findParent((path) => path.isStatement()).node.leadingComments = [];
}
path
.findParent((path) => path.isStatement())
.node.leadingComments.push(babelIgnoreComment);
}
},
};

module.exports = function () {
return {
visitor: {
Program: {
enter(path, state) {
const filename = state.file.opts.filename;

if (!filename?.match(/\.g[tj]s$/)) {
return;
}

// We need to do early traverse to make sure this runs before istanbuls plugin
path.traverse(gjsGtsTemplateIgnoreVisitor, state);
},
},
},
};
};
1 change: 1 addition & 0 deletions packages/ember-cli-code-coverage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"istanbul-lib-coverage": "^3.2.1",
"istanbul-lib-report": "^3.0.1",
"istanbul-reports": "^3.1.6",
"istanbul-lib-source-maps": "^4.0.1",
"node-dir": "^0.1.17",
"walk-sync": "^2.1.0"
},
Expand Down
14 changes: 14 additions & 0 deletions packages/ember-cli-code-coverage/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 32ef303

Please sign in to comment.