Skip to content

feat: support istanbul coverage provider#1676

Merged
antfu merged 35 commits intovitest-dev:mainfrom
AriPerkkio:feat/coverage-provider-istanbul
Aug 15, 2022
Merged

feat: support istanbul coverage provider#1676
antfu merged 35 commits intovitest-dev:mainfrom
AriPerkkio:feat/coverage-provider-istanbul

Conversation

@AriPerkkio
Copy link
Copy Markdown
Member

@AriPerkkio AriPerkkio commented Jul 19, 2022

Closes #1252

Documentation of the istanbul packages is not perfect. I had to do some analyzing of jest and nyc to get things working.

Creates common interface for coverage providers to implement and adds new coverage provider:

  • onFileTransform:

    • c8: No file transforms needed
    • istanbul: Instrument files under testing with istanbul-lib-instrument. Coverage objects are added to globalThis.__VITEST_COVERAGE__
  • onBeforeFilesRun:

    • c8: Instruct v8 to enable coverage collection by setting up process.env.NODE_V8_COVERAGE
    • istanbul: No actions needed
  • onAfterSuiteRun:

    • c8: Write v8 coverage reports to file system using v8.takeCoverage()
    • istanbul: Collect the globalThis.__VITEST_COVERAGE__ from workers through birpc into main thread
  • onAfterAllFilesRun:

    • c8: Create report using c8/lib/report
    • istanbul: Process and merge coverage objects with istanbul-lib-coverage and create report with istanbul-reports

Example

vitest/test/coverage-test/src/utils.ts: Istanbul on the left with 57% coverage, v8 on the right with 70% coverage:

image

@AriPerkkio
Copy link
Copy Markdown
Member Author

This is still a work-in-progress but it might be worth to create a draft PR at this point to prevent duplicate work.

I think the refactor: create interface for coverage logic part is complete, but istanbul integration still requires work. I can continue this later on, but if anyone is eager to finish this PR let me know.

I think it's also good time for Vitest team to take a look at this overall and call for a stop if this doesn't look good.

Comment thread packages/vitest/src/node/core.ts Outdated
Comment thread packages/vitest/src/node/plugins/index.ts Outdated
Comment thread packages/vitest/src/runtime/run.ts Outdated
Comment thread packages/vitest/src/integrations/coverage/c8.ts Outdated
Comment thread packages/vitest/src/integrations/coverage/istanbul.ts Outdated
Comment thread packages/vitest/src/node/cli-api.ts Outdated
Comment on lines +38 to +48
// TODO: Requring all these packages to be installed by users may be too much
const requiredPackages = ctx.config.coverage.provider === 'istanbul'
? [
'istanbul-lib-coverage',
'istanbul-lib-instrument',
'istanbul-lib-report',
'istanbul-reports',
]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can create @vitest/istanbul package that just reexports what is needed.

@vitest-dev/team What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it sounds great to me
#1676 (comment)

@AriPerkkio AriPerkkio force-pushed the feat/coverage-provider-istanbul branch 2 times, most recently from bc73f74 to 36b3f17 Compare July 21, 2022 07:27
Comment thread packages/vitest/src/integrations/coverage/base.ts Outdated
@AriPerkkio AriPerkkio force-pushed the feat/coverage-provider-istanbul branch 3 times, most recently from e657060 to 5b48782 Compare July 22, 2022 11:43
Comment thread packages/vitest/src/node/core.ts Outdated
Comment thread packages/vitest/src/types/coverage.ts Outdated
Comment thread packages/vitest/src/integrations/coverage/istanbul.ts Outdated
@AriPerkkio AriPerkkio force-pushed the feat/coverage-provider-istanbul branch 3 times, most recently from fea9cce to fc13750 Compare July 23, 2022 11:14
this.ctx = ctx
this.options = resolveIstanbulOptions(ctx.config.coverage, ctx.config.root)

const { createInstrumenter } = require('istanbul-lib-instrument')
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a cool idea, thanks for improvement idea @wight554. However I think it might be best if we leave this customization out of this PR and introduce it in a separate feature afterwards.
Do you think there is anything important we need to take into consideration at this point? Leave some abstractions in place, etc?
My Rust knowledge is a bit rusty and to me it's not that clear what exactly import('swc-plugin-coverage-instrument') would return here. Does it match the API of istanbul-lib-instrument?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a cool idea, thanks for improvement idea @wight554. However I think it might be best if we leave this customization out of this PR and introduce it in a separate feature afterwards. Do you think there is anything important we need to take into consideration at this point? Leave some abstractions in place, etc? My Rust knowledge is a bit rusty and to me it's not that clear what exactly import('swc-plugin-coverage-instrument') would return here. Does it match the API of istanbul-lib-instrument?

I've checked how jest handles this, see https://github.com/facebook/jest/blob/24e0472ac41ea03cdd89ffaea8c5f410ecf6054f/packages/jest-transform/src/ScriptTransformer.ts#L410
In this case all that needs to be added is config value to skip instrumenter part and return unmodified map and code in onFileTransform

@wight554
Copy link
Copy Markdown

wight554 commented Jul 26, 2022

looks good overall, noticed few issues:

  1. exclude option seems to be ignored when using instanbul
  2. when setting provider to c8 explicitly vitest run --coverage skips coverage
  3. vitest doesn't suggest installing missing istanbul packages and skips coverage instead
  4. c8 randomly ignores coverage for 1 file in 100% covered code when using c8 with these changes

codebase I used for testing: https://github.com/wight554/blog-template
You might notice schemas are added to coverage report when using istanbul [1] if you try

Upd. I use typescript instead of esbuild for compiling tests but ts-jest does the same and uses default jest instrument, so shouldn't be an issue
Upd2. if matters:

  System:
    OS: Windows 10 10.0.22622
    CPU: (16) x64 AMD Ryzen 7 3700X 8-Core Processor
    Memory: 17.38 GB / 31.93 GB
  Binaries:
    Node: 16.14.0 - c:\program files\nodejs\node.EXE
    Yarn: 3.1.1 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 8.3.1 - c:\program files\nodejs\npm.CMD
  Browsers:
    Chrome: 103.0.5060.134
    Edge: Spartan (44.22621.436.0), Chromium (103.0.1264.71)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    vite: ^3.0.3 => 3.0.3
    vitest: 0.19.1 => 0.19.1

@antfu
Copy link
Copy Markdown
Member

antfu commented Jul 26, 2022

The overall direction looks great to me. Please ping me when you think the work on your side is done, and I can help to do the refactoring and make the packages more general as @vitest/coverage-istanbul and even @vitest/coverage-c8 later.

@AriPerkkio
Copy link
Copy Markdown
Member Author

AriPerkkio commented Jul 26, 2022

From my side all that is left to do is unit+manual testing and add documentation. I think everything else (besides refactoring into separate packages) is done. I'm happy to leave these tasks to other people as well. 😄

I'm currently travelling and won't be doing anything for the next ~10 days. @antfu if you'd like to start working on this now, feel free to take over the PR. 👍

@antfu
Copy link
Copy Markdown
Member

antfu commented Jul 26, 2022

Great, thanks! Have a good time traveling!

@AriPerkkio AriPerkkio force-pushed the feat/coverage-provider-istanbul branch 2 times, most recently from 1bfd7e0 to 15d1ddc Compare August 2, 2022 15:30
Comment thread packages/vitest/src/types/coverage.ts Outdated
@AriPerkkio AriPerkkio force-pushed the feat/coverage-provider-istanbul branch 3 times, most recently from 4c060d9 to 0d28eb2 Compare August 4, 2022 18:26
@AriPerkkio
Copy link
Copy Markdown
Member Author

There's now some initial documentation and unit tests in place. I think the next logical step is to refactor these coverage providers into their own packages - #1676 (comment).

@sheremet-va
Copy link
Copy Markdown
Member

There's now some initial documentation and unit tests in place. I think the next logical step is to refactor these coverage providers into their own packages - #1676 (comment).

I think we should have these packages:

  • @vitest/coverage-v8
  • @vitest/coverage-istanbul

Then Vitest checks for coverage field, if package is installed. We might also expose this as CoverageProvider for extending with custom provider.

@antfu antfu requested a review from Demivan August 15, 2022 09:32
@Demivan
Copy link
Copy Markdown
Member

Demivan commented Aug 15, 2022

@antfu coverage-c8 and coverage-istanbul build is failing locally.

src/provider.ts(6,10): error TS2305: Module '"vitest/config"' has no exported member 'configDefaults'.

@Demivan
Copy link
Copy Markdown
Member

Demivan commented Aug 15, 2022

@antfu antfu enabled auto-merge (squash) August 15, 2022 18:19
@antfu antfu disabled auto-merge August 15, 2022 18:20
@antfu antfu merged commit 265fdbe into vitest-dev:main Aug 15, 2022
@AriPerkkio AriPerkkio deleted the feat/coverage-provider-istanbul branch August 15, 2022 18:40
@JounQin
Copy link
Copy Markdown

JounQin commented Aug 17, 2022

It should be noticed provider: 'istanbul' is required if the user wants to use istanbul, ideally, if @vitest/coverage-istanbul is detected, istanbul should be used by default IMO.

@antfu
Copy link
Copy Markdown
Member

antfu commented Aug 18, 2022

I thought about it as once, but it could be complex to handle, like if you have both c8 and Istanbul packages installed, or if we have more providers in the future. Also, it might be dangerous to have dependencies change the behavior implicitly.

@JounQin
Copy link
Copy Markdown

JounQin commented Aug 18, 2022

@antfu

But the current behavior is very strange.

When provide: 'Istanbul' is not enabled but @vitest/coverage-istanbul installed

 MISSING DEP  Can not find dependency '@vitest/coverage-c8'

✖ Do you want to install @vitest/coverage-c8? … no

There is no choice or notice to add provide: 'Istanbul'.

When provide: 'Istanbul' enabled with @vitest/coverage-istanbul installed

Coverage enabled with istanbul

This message is very redundant to appear every time.

if you have both c8 and Istanbul packages installed, or if we have more providers in the future

IMO, something like Coverage enabled with istanbul is just for this case, for the default fallback or conflict providers installed message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coverage: give the choice between c8 and nyc

6 participants