-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] module api for intergrators #116
Comments
@Toxicable I would look at how we approach collecting coverage for Node.js: https://github.com/nodejs/node/blob/master/Makefile#L245 You can use |
@bcoe My understanding is that you can activate code coverage collection via the |
(I posted this on Slack, but I can post it here as well as it's probably a better place). Background: I'm looking into integrating V8 coverage into Jest (jestjs/jest#7062). Sample code I want to collect coverage for: const vm = require('vm');
const script = new vm.Script(`
function thing() {
if (Math.random() > 0.5) {
output = 'success!';
} else {
output = 'failure';
}
}
thing();
`);
const context = vm.createContext({ output: '' });
script.runInContext(context); The catch here is that I'm just interested in coverage for I played around with using the inspector API mentioned in the above blog post, and I got it to sorta work. I get this output: {
"scriptId": "69",
"url": "evalmachine.<anonymous>",
"functions": [
{
"functionName": "",
"ranges": [{ "startOffset": 0, "endOffset": 125, "count": 1 }],
"isBlockCoverage": false
},
{
"functionName": "thing",
"ranges": [{ "startOffset": 1, "endOffset": 114, "count": 1 }],
"isBlockCoverage": false
}
]
} If I instead set {
"scriptId": "70",
"url": "evalmachine.<anonymous>",
"functions": [
{
"functionName": "",
"ranges": [{ "startOffset": 0, "endOffset": 125, "count": 1 }],
"isBlockCoverage": true
},
{
"functionName": "thing",
"ranges": [
{ "startOffset": 1, "endOffset": 114, "count": 1 },
{ "startOffset": 47, "endOffset": 77, "count": 0 }
],
"isBlockCoverage": true
}
]
} Differences being that Running with It might be that it doesn't work properly for me due to the fact we use My testing code, for completeness: const inspector = require('inspector');
const vm = require('vm');
const { builtinModules } = require('module');
const session = new inspector.Session();
session.connect();
const script = new vm.Script(`
function thing() {
if (Math.random() > 0.5) {
output = 'success!';
} else {
output = 'failure';
}
}
thing();
`);
const context = vm.createContext({ output: '' });
session.post('Profiler.enable', () => {
session.post('Profiler.startPreciseCoverage', () => {
script.runInContext(context);
session.post('Profiler.takePreciseCoverage', (err, { result }) => {
if (err) {
console.error(err);
process.exitCode = 1;
return;
}
const filtered = result.filter(
({ url }) =>
!builtinModules.some(builtin => builtin + '.js' === url) &&
!url.startsWith('internal/')
);
console.log(JSON.stringify(filtered));
session.post('Profiler.stopPreciseCoverage', err => {
if (err) {
console.error(err);
process.exitCode = 1;
}
});
});
});
}); |
@Toxicable Node.js has an inspector session running by default in most platforms, which Creating a new inspector session and negotiating the connection with Node.js is a pain, and much more error prone. I think it's much better to spawn Node.js with a flag or environment variable, then try to negotiate the inspector dance in userland (this is actually what the first pass at this library did, and it worked terribly). |
@bcoe Thats interesting, thanks for the background on that. Just for context; one of the main reasons we don't want to do a sub process is becasue we currently override the module resolution functionality of However, we could add coverage support further up the chain - at the original nodejs spawn, rather than at the test runners execution, ill explore this design a bit more. With that constrat in mind, how about Reporting and Merging? Are there currently any tools for merging v8 coverage of common libs together for a final version? |
@Toxicable you should be able to use As for spawning subprocesses, you shouldn't need to do this. You just need to make sure that the initial process spawned has NODE_V8_COVERAGE set (you don't need to use
Most of the heavy lifting is in Node.js itself, via the inspector session. |
I should add, if there is a way we can better expose this information from Node.js, happy to try to figure something out with you -- but setting NODE_V8_COVERAGE seemed like one of the easier interfaces to me (this in turn turns on coverage in the inspector session running in Node.js). |
Just took a shot at implementing NODE_V8_COVERAGE but ran into the issue that I realised was the reason for wanting to use the inspector api way back when I first looked at this. Im not sure adding another program for handling coverage after the primary one is a good design. If you're curious this is the work so far on this: bazel-contrib/rules_nodejs#874 |
That's also needed for Jest's use case - we support coverage in watch mode. I also need to generate the reports in-process since the location of sourcemaps are in a temp cache somewhere (which we manage in memory) |
@Toxicable @SimenB might be worth moving this feature request to Node.js? could imagine this being possible with a signal, not sure what signal. |
@bcoe That sounds reasonable, do you have permissions to move this issue? |
Made a new one here: nodejs/node#28283 |
I opened up istanbuljs/v8-to-istanbul#33. By using that, and copying some The part I copied from c8: const map = libCoverage.createCoverageMap({});
v8CoverageResult.forEach(res => map.merge(res));
const context = libReport.createContext({
dir: globalConfig.coverageDirectory,
});
const tree = libReport.summarizers.pkg(map);
tree.visit(reports.create('html'), context); Not too much. So I don't think we necessarily need to put any more code in c8 - making The Usage: const v8CoverageInstrumenter = new CoverageInstrumenter();
await v8CoverageInstrumenter.startInstrumenting();
// do your work that you want instrumented here
const v8CoverageResult = await v8CoverageInstrumenter.stopInstrumenting(); Note that this does not at all have to live in Jest, it was just easiest for me when doing this work to have it there. It might live in the istanbul org, maybe? (this is just |
@SimenB cool, let's move this conversation to |
Im integrating code coverage into Bazel: https://github.com/bazelbuild/rules_nodejs
However, rather than reimplementing the internal logic we see in this lib it would be great if there was a public facing API that could be used by downstream integrators.
For this kind of integration the main functionality needed
A code example of the api we're after might look like this
Some important points here:
I'd be happy to contribute to this design or implementation if needed.
Let me know if this is something we'd like to do with this lib
The text was updated successfully, but these errors were encountered: