Skip to content

Commit

Permalink
v8 report for c8
Browse files Browse the repository at this point in the history
  • Loading branch information
cenfun committed Jan 25, 2024
1 parent bf3073b commit b72b84d
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
151 changes: 151 additions & 0 deletions lib/commands/report.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
const { checkCoverages } = require('./check-coverage')
const Report = require('../report')
const Exclude = require('test-exclude')
const fs = require('fs');
const path = require('path');
const { fileURLToPath, pathToFileURL } = require('url');
const { CoverageReport } = require("monocart-coverage-reports");
const EC = require("eight-colors");

exports.command = 'report'

Expand All @@ -9,7 +15,146 @@ exports.handler = async function (argv) {
await exports.outputReport(argv)
}

const runV8Report = async (argv) => {

This comment has been minimized.

Copy link
@bcoe

bcoe Jan 26, 2024

c8 uses v8 output for its existing reporting, it just transforms it into an istanbul format for reporting.

Perhaps we could instead call this runMonocartReport, and expose the functionality as --experimental-monocart or something like this?

This comment has been minimized.

Copy link
@cenfun

cenfun Jan 27, 2024

Author Owner

Agree, will update it

// console.log(argv);
const exclude = new Exclude({
exclude: argv.exclude,
include: argv.include,
extension: argv.extension,
relativePath: !argv.allowExternal,
excludeNodeModules: argv.excludeNodeModules
})

// adapt coverage options
const coverageOptions = getCoverageOptions(argv, exclude);
const coverageReport = new CoverageReport(coverageOptions);
coverageReport.cleanCache();

// --all: add empty coverage for all files
if (argv.all) {
await addEmptyCoverage(coverageReport, argv, exclude);
}

// read v8 coverage data from tempDirectory
await addV8Coverage(coverageReport, argv);

// generate report
await coverageReport.generate();

};

function getCoverageOptions(argv, exclude) {
return {
name: argv.name || "My C8 Coverage Report",
outputDir: argv.reportsDir,

reports: argv.reporter,

entryFilter: (entry) => {
return exclude.shouldInstrument(entry.url);
},

sourceFilter: (sourcePath) => {
if (argv.excludeAfterRemap) {
return exclude.shouldInstrument(sourcePath);
}
return true;
},

onEnd: (coverageResults) => {
console.log(`Coverage report generated: ${coverageResults.reportPath}`);

if (!argv.checkCoverage) {
return;
}
// check thresholds
const thresholds = {};
['bytes', "lines", "functions", "branches"].forEach(k => {
if (argv[k]) {
thresholds[k] = argv[k];
}
});

console.log('check thresholds ...', thresholds);
const errors = [];
const { summary } = coverageResults;
Object.keys(thresholds).forEach((k) => {
const pct = summary[k].pct;
if (pct < thresholds[k]) {
errors.push(`Coverage threshold for ${k} (${pct} %) not met: ${thresholds[k]} %`);
}
});
if (errors.length) {
process.exitCode = 1
const errMsg = errors.join('\n');
EC.logRed(errMsg);
}

}
}
}

async function addEmptyCoverage(coverageReport, argv, exclude) {
const src = argv.src;
const workingDirs = Array.isArray(src) ? src : (typeof src === 'string' ? [src] : [process.cwd()]);
const list = [];
for (const workingDir of workingDirs) {
exclude.globSync(workingDir).forEach((f) => {
const fullPath = path.resolve(workingDir, f);
const source = fs.readFileSync(fullPath).toString('utf-8');
const extname = path.extname(fullPath)
const url = pathToFileURL(fullPath).toString();
if (['.css'].includes(extname)) {
list.push({
empty: true,
type: 'css',
url,
text: source
});
} else {
list.push({
empty: true,
type: 'js',
url,
source
});
}
})
}
await coverageReport.add(list);
}

async function addV8Coverage(coverageReport, argv) {
const dir = argv.tempDirectory;
const files = fs.readdirSync(dir);
for (const filename of files) {
const content = fs.readFileSync(path.resolve(dir, filename)).toString('utf-8');
const json = JSON.parse(content);
let coverageList = json.result;

// filter node internal files
coverageList = coverageList.filter((entry) => entry.url && entry.url.startsWith('file:'));

if(!coverageList.length) {
continue
}

// attached source content
coverageList.forEach((entry) => {
const filePath = fileURLToPath(entry.url);
if (fs.existsSync(filePath)) {
entry.source = fs.readFileSync(filePath).toString('utf8');
} else {
console.log('not found file', filePath);
}
});

await coverageReport.add(coverageList);
}
}

exports.outputReport = async function (argv) {

// TODO: this is a workaround until yargs gets upgraded to v17, see https://github.com/bcoe/c8/pull/332#discussion_r721636191
if (argv['100']) {
argv.checkCoverage = 100
Expand All @@ -18,6 +163,12 @@ exports.outputReport = async function (argv) {
argv.branches = 100
argv.statements = 100
}

if(argv.mode === "v8") {
await runV8Report(argv);
return;
}

const report = Report({
include: argv.include,
exclude: argv.exclude,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"url": "git@github.com:bcoe/c8.git"
},
"scripts": {
"test-v8": "cross-env TS_NODE_SKIP_PROJECT=true node ./bin/c8.js --mode=v8 -o=coverage-v8 -r=v8 -r=console-summary mocha --timeout=10000 ./test/*.js",
"test": "cross-env TS_NODE_SKIP_PROJECT=true node ./bin/c8.js mocha --timeout=10000 ./test/*.js",
"coverage": "cross-env TS_NODE_SKIP_PROJECT=true node ./bin/c8.js --check-coverage mocha --timeout=10000 ./test/*.js",
"test:snap": "cross-env CHAI_JEST_SNAPSHOT_UPDATE_ALL=true npm test",
Expand Down Expand Up @@ -40,6 +41,7 @@
"istanbul-lib-coverage": "^3.2.0",
"istanbul-lib-report": "^3.0.1",
"istanbul-reports": "^3.1.6",
"monocart-coverage-reports": "^2.3.1",
"test-exclude": "^6.0.0",
"v8-to-istanbul": "^9.0.0",
"yargs": "^17.7.2",
Expand Down

0 comments on commit b72b84d

Please sign in to comment.