vitest-dev / vitest

Next generation testing framework powered by Vite.
https://vitest.dev
MIT License
12.61k stars 1.13k forks source link

Coverage Reports 0 for a Vue Component with No Functions #3607

Open merlinstardust opened 1 year ago

merlinstardust commented 1 year ago

Describe the bug

I have a UI component that has no functions in it but vitest run --coverage reports 0% coverage for functions.

If there are no functions to test, the coverage reporter should report 100%

 % Coverage report from v8
---------------------|---------|----------|---------|---------|-------------------
File                 | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------------|---------|----------|---------|---------|-------------------
All files            |     100 |      100 |      80 |     100 |                   
 components          |     100 |      100 |   66.66 |     100 |                   
  BasicButton.vue    |     100 |      100 |     100 |     100 |                   
  ...omButtonNav.vue |     100 |      100 |       0 |     100 |                   
 store               |     100 |      100 |     100 |     100 |                   
  index.ts           |     100 |      100 |     100 |     100 |                   
---------------------|---------|----------|---------|---------|-------------------

Reproduction

BottomButtonNav.vue

<template>
  <div class="row bottom-button-nav">
    <div class="row left-container" data-testid="left-container">
      <slot name="leftSide"></slot>
    </div>
    <div class="row right-container" data-testid="right-container">
      <slot name="rightSide"></slot>
    </div>
  </div>
</template>

<style scoped>
.bottom-button-nav {
  position: absolute;
  bottom: 0;
  display: flex;
  justify-content: space-between;
  width: calc(100% - 80px);
  margin: 0 40px 40px;
}
</style>

BottomButtonNav.test.ts

import { render, screen } from '@testing-library/vue';
import BottomButtonNav from '~/components/BottomButtonNav.vue';

describe('BottomButtonNav', () => {
  it('renders left and right slots correctly', () => {
    const leftSlotContent = 'Left Slot Content';
    const rightSlotContent = 'Right Slot Content';

    render(BottomButtonNav, {
      slots: {
        leftSide: leftSlotContent,
        rightSide: rightSlotContent,
      },
    });

    const leftContainer = screen.getByTestId('left-container');
    const rightContainer = screen.getByTestId('right-container');

    expect(leftContainer).toHaveTextContent(leftSlotContent);
    expect(rightContainer).toHaveTextContent(rightSlotContent);
  });
});

System Info

System:
    OS: macOS 13.4
    CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
    Memory: 472.32 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.6.0 - ~/.nvm/versions/node/v18.6.0/bin/node
    npm: 8.14.0 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Browsers:
    Chrome: 114.0.5735.133
    Edge: 114.0.1823.51
    Firefox: 114.0.1
    Safari: 16.5
  npmPackages:
    @vitejs/plugin-vue: ^4.0.0 => 4.2.3 
    @vitest/coverage-v8: ^0.32.0 => 0.32.0 
    vite: ^4.2.1 => 4.3.9 
    vitest: ^0.32.0 => 0.32.0 


### Used Package Manager

npm

### Validations

- [X] Follow our [Code of Conduct](https://github.com/vitest-dev/vitest/blob/main/CODE_OF_CONDUCT.md)
- [X] Read the [Contributing Guidelines](https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md).
- [X] Read the [docs](https://vitest.dev/guide/).
- [X] Check that there isn't [already an issue](https://github.com/vitest-dev/vitest/issues) that reports the same bug to avoid creating a duplicate.
- [X] Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions) or join our [Discord Chat Server](https://chat.vitest.dev).
- [X] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
github-actions[bot] commented 1 year ago

Hello @merlinstardust. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with need reproduction will be closed if they have no activity within 3 days.

merlinstardust commented 1 year ago

@AriPerkkio Here's a minimal reproduction repo with PR

https://github.com/merlinstardust/coverage-zero-vitest-example/pull/1

AriPerkkio commented 1 year ago

Vue compiler is outputting source maps which are off by one line. This is similar as https://github.com/vitest-dev/vitest/discussions/2874 and https://github.com/vuejs/vue-loader/issues/1778.

Here is what Vue is generating from BottomButtonNav.vue:

const _sfc_main = {}
import { renderSlot as _renderSlot, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue"

const _withScopeId = n => (_pushScopeId("data-v-3da707db"),n=n(),_popScopeId(),n)
const _hoisted_1 = { class: "row bottom-button-nav" }
const _hoisted_2 = {
  class: "row left-container",
  "data-testid": "left-container"
}
const _hoisted_3 = {
  class: "row right-container",
  "data-testid": "right-container"
}

function _sfc_render(_ctx, _cache) {
  return (_openBlock(), _createElementBlock("div", _hoisted_1, [
    _createElementVNode("div", _hoisted_2, [
      _renderSlot(_ctx.$slots, "leftSide", {}, undefined, true)
    ]),
    _createElementVNode("div", _hoisted_3, [
      _renderSlot(_ctx.$slots, "rightSide", {}, undefined, true)
    ])
  ]))
}

import "/x/y/coverage-zero-vitest-example/src/components/BottomButtonNav.vue?vue&type=style&index=0&scoped=3da707db&lang.css"

import _export_sfc from 'plugin-vue:export-helper'
export default /*#__PURE__*/_export_sfc(_sfc_main, [['render',_sfc_render],['__scopeId',"data-v-3da707db"],['__file',"/x/y/coverage-zero-vitest-example/src/components/BottomButtonNav.vue"]])
{
  "version": 3,
  "sources": [
    "/x/y/coverage-zero-vitest-example/src/components/BottomButtonNav.vue"
  ],
  "names": [],
  "mappings": ";;;qBACO,KAAK,EAAC,uBAAuB;;EAC3B,KAAK,EAAC,oBAAoB;EAAC,aAAW,EAAC,gBAAgB;;;EAGvD,KAAK,EAAC,qBAAqB;EAAC,aAAW,EAAC,iBAAiB;;;;wBAJhE,oBAOM,OAPN,UAOM;IANJ,oBAEM,OAFN,UAEM;MADJ,YAA6B;;IAE/B,oBAEM,OAFN,UAEM;MADJ,YAA8B",
  "file": "/x/y/coverage-zero-vitest-example/src/components/BottomButtonNav.vue",
  "sourceRoot": "",
  "sourcesContent": [
    "<template>\n  <div class=\"row bottom-button-nav\">\n    <div class=\"row left-container\" data-testid=\"left-container\">\n      <slot name=\"leftSide\"></slot>\n    </div>\n    <div class=\"row right-container\" data-testid=\"right-container\">\n      <slot name=\"rightSide\"></slot>\n    </div>\n  </div>\n</template>\n\n<script setup lang=\"ts\"></script>\n\n<style scoped>\n.bottom-button-nav {\n  position: absolute;\n  bottom: 0;\n  display: flex;\n  justify-content: space-between;\n  width: calc(100% - 80px);\n  margin: 0 40px 40px;\n}\n</style>\n"
  ]
}

When inspecting the source map it's clearly visible that it's off: https://ariperkkio.github.io/source-map-debugger?s=N4Ig.... Notice how the line 4's _withScopeId helper function is incorrectly included in source maps. This is the uncovered function that your coverage report includes.

  {
    "functionName": "_withScopeId",
    "ranges": [
      {
        "startOffset": 587,
        "endOffset": 689,
        "count": 0
      }
    ],
    "isBlockCoverage": false
  }

Now when we add one extra line to mappings everything looks much better:

-  "mappings": ";;;qBACO,...",
+  "mappings": ";;;;qBACO,...",
---------------------|---------|----------|---------|---------|-------------------
File                 | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------------|---------|----------|---------|---------|-------------------
All files            |     100 |      100 |     100 |     100 |                   
 BottomButtonNav.vue |     100 |      100 |     100 |     100 |                   
---------------------|---------|----------|---------|---------|-------------------

https://ariperkkio.github.io/source-map-debugger?s=N4Ig...

This needs to be fixed in one of the Vue compiler related dependencies that your project is using. Maybe it's the vuejs/vue-loader linked above.

ThomasBerneHCSE commented 4 months ago

Any news on this?

zeropaull commented 3 months ago

+1, having the same issue with coverage for components with no functions in them

jordanMeo commented 2 months ago

Having the same issue. Any potential fix or workarounds on the horizon?

bartspiering commented 1 month ago

This worked for me:

<script setup lang="ts">
/* without this comment coverage will report 0% for functions */
</script>
y-takebe commented 10 hours ago

+1