jest
jest copied to clipboard
Add One Double Zero as coverage provider
Summary
As explained in the issue, v8 coverage provider comes with some important tradeoffs compared to the babel/istanbul one. One Double Zero is a code coverage tool and API that consumes V8 coverage data and targets the accuracy and correctness of istanbul. It does this by operating at the AST level.
This PR adds One Double Zero as a coverage provider.
It also updates the documentation, and explains the tradeoffs of the v8 coverage provider.
Test plan
The plan is to execute odz on each e2e test executed by the v8 coverage provider test suite, and use the output result as the snapshot for e2e/__tests__/coverageProviderODZ.test.ts. The test script of each e2e has to be changed to be executable wth either node or ts-node, which does not impact the coverage result.
- e2e/coverage-provider-v8/cjs-native-without-sourcemap
e2e/coverage-provider-v8/cjs-native-without-sourcemap$ odz --sources=module.js --sources=uncovered.js node __tests__/test.js
this will print
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 60 | 50 | 50 | 60 |
module.js | 66.66 | 50 | 50 | 66.66 | 14-15,19
uncovered.js | 0 | 100 | 100 | 0 | 8
--------------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/cjs-with-babel-transformer
e2e/coverage-provider-v8/cjs-with-babel-transformer$ odz --sources=module.ts --sources=uncovered.ts --sources=types.ts ts-node -T __tests__/test.ts
this will print
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 62.5 | 50 | 50 | 62.5 |
module.ts | 62.5 | 50 | 50 | 62.5 | 16-17,21
types.ts | 0 | 0 | 0 | 0 |
uncovered.ts | 0 | 0 | 0 | 0 |
--------------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/empty-sourcemap
e2e/coverage-provider-v8/empty-sourcemap$ odz --sources=types.ts ts-node -T __tests__/test.ts
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
types.ts | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/esm-native-without-sourcemap
e2e/coverage-provider-v8/esm-native-without-sourcemap$ odz --sources=module.js node __tests__/test.js
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 62.5 | 50 | 50 | 62.5 |
module.js | 62.5 | 50 | 50 | 62.5 | 14-15,19
uncovered.js | 0 | 0 | 0 | 0 |
--------------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/esm-with-custom-transformer
e2e/coverage-provider-v8/esm-with-custom-transformer$ odz --sources=module.ts --sources=uncovered.ts --sources=types.ts ts-node -T __tests__/test.ts
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 62.5 | 50 | 50 | 62.5 |
module.ts | 62.5 | 50 | 50 | 62.5 | 16-17,21
types.ts | 0 | 0 | 0 | 0 |
uncovered.ts | 0 | 0 | 0 | 0 |
--------------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/no-sourcemap
e2e/coverage-provider-v8/no-sourcemap$ odz --sources=Thing.js --sources=x.css node __tests__/Thing.test.js
42
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
Thing.js | 100 | 100 | 100 | 100 |
x.css | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------
- e2e/coverage-provider-v8/with-resetModules
e2e/coverage-provider-v8/with-resetModules$ odz --sources=module.js --sources=uncovered.js node __tests__/test.js
this will print
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 60 | 50 | 50 | 60 |
module.js | 66.66 | 50 | 50 | 66.66 | 14-15,19
uncovered.js | 0 | 100 | 100 | 0 | 8
--------------|---------|----------|---------|---------|-------------------
- e2e/vmscript-coverage
e2e/vmscript-coverage$ odz --sources=module.js --sources=package/vmscript.js node __tests__/extract-coverage.test.js
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 80 | 75 | 66.66 | 80 |
vmscript.js | 80 | 75 | 66.66 | 80 | 20-21
-------------|---------|----------|---------|---------|-------------------
A few changes had to be made, like passing the list of files to cover to the _getCoverageResult method, but globally the changes required to add odz were minimal.
The committers listed above are authorized under a signed CLA.
- :white_check_mark: login: ericmorand / name: Eric MORAND (cf49e944f7e20a6fe5cd3158478d1ab2280f699d, 278a534ceb38883e47d8497d105e4912be11bd7f)
Deploy Preview for jestjs ready!
Built without sensitive environment variables
| Name | Link |
|---|---|
| Latest commit | 278a534ceb38883e47d8497d105e4912be11bd7f |
| Latest deploy log | https://app.netlify.com/sites/jestjs/deploys/67915455e2ca6f0008b22eea |
| Deploy Preview | https://deploy-preview-15356--jestjs.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify site configuration.
Another interesting test is using jest to check the coverage of the jest project itself, with every istanbul ignore pragma removed for consistency.
Using
babelas provider
$ yarn jest --coverage --coverageProvider=babel
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
All files | 68.51 | 65.55 | 65.33 | 68.54 |
Test Suites: 1 failed, 470 passed, 471 total
Tests: 1 failed, 51 skipped, 5132 passed, 5184 total
Snapshots: 1766 passed, 1766 total
Time: 96.649 s
Ran all test suites in 15 projects.
Using
v8as provider
$ yarn jest --coverage --coverageProvider=v8
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
All files | 68.33 | 86.69 | 75.97 | 68.33 |
Test Suites: 1 failed, 470 passed, 471 total
Tests: 1 failed, 51 skipped, 5132 passed, 5184 total
Snapshots: 1766 passed, 1766 total
Time: 81.74 s, estimated 90 s
Ran all test suites in 15 projects.
Using
odzas provider
$ yarn jest --coverage --coverageProvider=odz
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------------------------------|---------|----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------
All files | 65.68 | 61.61 | 64.67 | 65.76 |
Test Suites: 1 failed, 470 passed, 471 total
Tests: 1 failed, 51 skipped, 5132 passed, 5184 total
Snapshots: 1766 passed, 1766 total
Time: 76.922 s, estimated 79 s
Ran all test suites in 15 projects.
The most striking difference is the function and branch coverage reported by v8 that is way too high compared to the two others. This is expected and is a well-known issue:
- the
v8provider doesn't consider the relevancy of lines: empty lines and comments are considered as covered. - the
v8provider considers that every single file contains at least one covered function.
Using v8 coverage data without knowledge of the meaning of each line of code makes for a very inaccurate coverage computation. Both babel and odz know about the meaning of each line of code: babel parses the code at instrumentation phase; odz parses the source files after the execution of the script.
The differences between babel and odz, minor, may come from how the tools work: babel parses and instruments the executed script; odz parses the source files. It is likely that both approaches lead to slightly different results. In any case, the ultimate goal of One Double Zero is to match istanbul accuracy, so the differences here are likely to become less and less important as One Double Zero continues to improve.
About performance differences: without a proper benchmark under some controlled environment and context, and multiple executions, they don't mean much. But it is likely that babel is slower in the end: instrumenting and running an instrumented code is more taxing than just executing the code and parsing the source files.
@SimenB,
Thanks a lot for the review.
typescript dependency was removed entirely.
I replaced one-double-zero dependency with one-double-zero-core, the API that fuels one-double-zero. It embeds its own parser, removing the need to depend on the typescript package. The API is stable and supports Node.js 16 (as you can see there), honoring Jest V30 commitments.
I rebased my PR on the head of main, and added a unit test to pass the coverage check.
Let me know what you think.
Does one double zero have flaky coverage as reported in https://github.com/jestjs/jest/issues/14766 ?
Closing due to inactivity. Happy to reopen if somebody picks this back up, or send a new PR.
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.