vuejs / vue-jest

Jest Vue transformer
MIT License
745 stars 157 forks source link

Jest requires `--no-cache` for proper coverage #56

Open awolden opened 6 years ago

awolden commented 6 years ago

I have been digging into why many of our well tested components/views are not showing up on coverage reports, and I noticed that if I applied the --no-cache flag to jest I started getting appropriate coverage numbers. There seems to be an issue with the vue-jest caching mechanism that may be preventing some from getting appropriate coverage numbers.

We copied our settings from https://github.com/eddyerburgh/vue-test-utils-jest-example

chrisvfritz commented 6 years ago

I can confirm this issue on vue-enterprise-boilerplate. I've also noticed tests that should pass sometimes failing unless I clear the cache. If there's some information I can collect the next time it happens, I'm happy to post it here.

eddyerburgh commented 6 years ago

Any info is usefu:

Also, you could delete this line and see if it solves the issue—https://github.com/vuejs/vue-jest/blob/master/vue-jest.js#L6.

chrisvfritz commented 6 years ago

I also just confirmed that deleting that line fixes the issue, so it does seem to be cache-related.

eddyerburgh commented 6 years ago

Does anyone have an example of a test that fails currently if the cache isn't cleared? I'd like to add a test case to the library when I fix the issue

eddyerburgh commented 6 years ago

The best solution right now might be to remove the getCacheKey function.

The getCacheKey function is returning a different hash when the file data changes, so the issue could be with how Jest uses the cache key.

chrisvfritz commented 6 years ago

I don't have an example of a test that fails, as it's not a persistent problem. At some point, a test will start failing when it shouldn't and I'm not sure what the trigger is. Then I clear the cache and it's all good.

The coverage problem is very reproducible though. On vue-enterprise-boilerplate, running yarn jest --coverage will consistently report 0% for every .vue file unless you also add --no-cache.

eddyerburgh commented 6 years ago

I'm unable to reproduce.

I cloned the vue-enterprise-boilerplate (which is great by the way 😀), ran yarn install, and yarn jest --coverage.

Results:

---------------------|----------|----------|----------|----------|-------------------|
File                 |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------------|----------|----------|----------|----------|-------------------|
All files            |      100 |       75 |      100 |      100 |                   |
 components          |      100 |       75 |      100 |      100 |                   |
  _base-icon.vue     |      100 |      100 |      100 |      100 |                   |
  _base-input.vue    |      100 |      100 |      100 |      100 |                   |
  nav-bar-routes.vue |      100 |       75 |      100 |      100 |                19 |
  nav-bar.vue        |      100 |      100 |      100 |      100 |                   |
 router/layouts      |      100 |      100 |      100 |      100 |                   |
  main.vue           |      100 |      100 |      100 |      100 |                   |
 router/views        |      100 |      100 |      100 |      100 |                   |
  home.vue           |      100 |      100 |      100 |      100 |                   |
  login.vue          |      100 |      100 |      100 |      100 |                   |
  profile.vue        |      100 |      100 |      100 |      100 |                   |
---------------------|----------|----------|----------|----------|-------------------|

I think the solution is to remove the getCacheKey method temporarily.

chrisvfritz commented 6 years ago

So weird! I'm not sure if this is another option, but it looks like Facebook offers a createCacheKeyFunction utility that may be useful to us. I apologize if you already know about it and it's not appropriate for our use case - I'm just starting to dig my head into this stuff. 😅

(And as an aside about the boilerplate, please don't hesitate to let me know if you have any suggestions/questions about how I'm managing unit tests there, including the global helpers in tests/unit/setup.js. I'd be honored to get feedback from the test master himself!)

eddyerburgh commented 6 years ago

Thanks @chrisvfritz , I wasn't aware of that method. Would you be able to use it on this line—https://github.com/vuejs/vue-jest/blob/master/vue-jest.js#L6- and see if it fixes the issue. I'm still unable to reproduce the bug locally

chrisvfritz commented 6 years ago

Definitely! It looks like we need a list of files whose content can be used as a key. What do you recommend we use in our case?

eddyerburgh commented 6 years ago

Sorry, I didn't see this message! I've removed cacheing as a temporary fix in 2.1.1.

I believe we just use the filename, and then set getCacheKey to createCacheKeyFunction. It should be called with the correct arguments

robcresswell commented 6 years ago

I've been running --no-cache for some time to get around this issue, if a second confirmation helps. Just stumbled across this bug as I was looking for the reason for the cache removal in 2.1.1.

websmurf commented 6 years ago

Same issue here, --no-cache avoids the issue as well

Eitz commented 6 years ago

After creating a project using vue init webpack my-project I was getting 0% coverage for some Vue components. Just reporting in that --no-cache fixed the issue as well. Hope this can help anyone who searches for this in Google.

TheCycoONE commented 6 years ago

I've also encountered @chrisvfritz 's issue with tests failing until the cache is cleared or jest is called with no-cache. Other people here are also encountering it on the same tests.

DamianMullins commented 5 years ago

I also recently had this issue which was causing none of the .vue files to show in the coverage reports. Running with --no-cache resolved the issue.

ashmenon commented 5 years ago

I can confirm this issue still exists on vue-jest@3.0.0 and vue-test-utils@1.0.0-beta.11 (and also with @vue/test-utils@1.0.0-beta.25). Using --no-cache resolves the problem.

bennettdams commented 5 years ago

This issue came out of nowhere for me, took me way too long to recognize that it's a cache error.

FIX

All tests work again with adding --no-cache to the test script:

"test:unit": "vue-cli-service test:unit --no-cache"

SETUP

"devDependencies": {
    ....
    "@vue/cli-plugin-babel": "^3.0.5",
    "@vue/cli-plugin-unit-jest": "^3.0.5",
    "@vue/cli-service": "^3.0.5",
    "@vue/test-utils": "^1.0.0-beta.20",
    "babel-core": "7.0.0-bridge.0",
    "babel-jest": "^23.0.1",
    ...
  }

jest.config.js

module.exports = {
  moduleFileExtensions: ["js", "jsx", "json", "vue"],
  verbose: true,
  transform: {
    "^.+\\.vue$": "vue-jest",
    ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$":
      "jest-transform-stub",
    "^.+\\.jsx?$": "babel-jest"
  },
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  snapshotSerializers: ["jest-serializer-vue"],
  testMatch: [
    "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
  ],
  testURL: "http://localhost/"
};

ERROR

Here is the error from console:

jest-haste-map: @providesModule naming collision:
  Duplicate module name: _my-module_
  Paths: C:\...\frontend\package.json collides with C:\...\frontend\src\package.json

This warning is caused by a @providesModule declaration with the same name across two different files.
 FAIL  tests/unit/App.spec.js
  ● Test suite failed to run

    Cannot find module 'C:\...\frontend\node_modules\@babel\runtime/helpers/builtin/interopRequireDefault' from 'App.spec.js'

      1 | import { shallowMount, createLocalVue } from "@vue/test-utils";
      2 | import VueRouter from "vue-router";
    > 3 | import App from "@/App.vue";
        |                              ^
      4 |
      5 | const localVue = createLocalVue();
      6 | localVue.use(VueRouter);

      at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:221:17)
      at Object.<anonymous> (tests/unit/App.spec.js:3:30)

TEST

@eddyerburgh

Does anyone have an example of a test that fails currently if the cache isn't cleared? I'd like to add a test case to the library when I fix the issue

Even the most simple isVueInstance test fails:

import { shallowMount, createLocalVue } from "@vue/test-utils";
import VueRouter from "vue-router";
import App from "@/App.vue";

const localVue = createLocalVue();
localVue.use(VueRouter);
const router = new VueRouter();

describe("App", () => {
  test("is a Vue instance", () => {
    const wrapper = shallowMount(App, { localVue, router });
    expect(wrapper.isVueInstance()).toBeTruthy();
  });
});

..but again, other tests fail, too.

Royalone94 commented 5 years ago

"test:unit": "vue-cli-service test:unit --no-cache" worked for me!! Thanks.

Jack-Barry commented 5 years ago

This one is a little frustrating for me. Using --no-cache fixes the test, but if I'm using it in conjunction with --watch then changes aren't picked up as I make them, so the only way to see if I've broken something is to manually run jest. First world problems, but it'd be nice to have my test runner up while building so as to make the flow a bit less tedious.

example.spec.ts

import { shallowMount } from '@vue/test-utils'
import Example from './example.vue'

describe('stuff', () => {
  it('works', () => {
    const wrapper = shallowMount(Example);
    expect(wrapper.text()).toMatch('Hello')
  })
})

example.vue

<template>
  <div class="primary">{{ msg }}</div>
</template>

<script lang="ts" src="./example.ts"></script>
<style lang="scss" src="./example.scss"></style>

example.ts

export default {
  data() {
    return {
      msg: 'Hello Vue'
    }
  }
}

So if I have jest --watch --no-cache running, and change msg in example.ts to 'Hey Vue' the change isn't picked up and jest still thinks it's passing. Not sure if there's a way around that in jest or if it's the purview of vue-jest but seems relevant to the conversation here.

couellet commented 5 years ago

@Jack-Barry I'm experiencing the exact same issue, did you find a workaround?

Jack-Barry commented 5 years ago

@couellet For me it was a matter of giving up on keeping my TypeScript in a separate file, and might have also been partly due to pulling in updated dependencies.

If I put my business logic between the <script> tags instead of in its own file it's working for me using Jest 23.6.0, vue-jest 3.0.3, ts-jest 23.10.5, @vue/test-utils 1.0.0-beta.29.

Not a huge deal for our project, just was hoping to keep the business logic in a proper .ts file since the VS Code support for linting those tends to work a bit more predictably than when TS is in a .vue file.

couellet commented 5 years ago

@Jack-Barry We're using the same setup, with the .ts file in a separate file for better TypeScript support in unit tests. I guess we'll live with that until the next version of Vue which will have a better TypeScript support. Thanks!

bameda commented 5 years ago

I have the same problem with .pug files. My components usually have this structure:

Header/
  Header.css
  Header.pug
  Header.spec.ts
  Header.vue
JGJP commented 3 years ago

For others struggling with the cache not being cleared during --watchAll here is my solution (hack) to get around this issue:

package.json

{
  "scripts": {
    "test": "jest --no-cache -u",
    "test:watch": "onchange 'src/**/*' -i -- yarn test",
  },
  "devDependencies": {
    "onchange": "^7.0.2",
  },
}
yarn test:watch
michaelmoneypenny commented 3 years ago

Is this issue linked to code coverage reporting import statements as uncovered lines? I'm encountering this with a vue/gridsome project.

jest: 26.6.3 vue-jest: 3.0.7 node: v10.16.2 (windows)

no cache doesn't seem to help, this is my jest config:


module.exports = {
  moduleFileExtensions: ["js", "jsx", "json", "vue"],
  transform: {
    "^.+\\.vue$": require.resolve("vue-jest"),
    "^.+\\.jsx?$": require.resolve("babel-jest"),
  },
  transformIgnorePatterns: ["/node_modules/"],
  moduleNameMapper: {
    "^~/(.*)$": "<rootDir>/src/$1",
  },
  testMatch: ["**/tests/unit/**/*.spec.[jt]s?(x)", "**/__tests__/*.[jt]s?(x)"],
  collectCoverage: true,
  collectCoverageFrom: [
    "src/**/*.{js,vue}",
    "!src/main.js", // No need to cover bootstrap file
  ],
};
ricardovanlaarhoven commented 3 years ago

Even with "vue-jest": "^4.0.0-rc.0", my command vue-cli-service test:unit --no-cache --collect-coverage results in line 122 being uncovered, while line 122 doesn't even exist. The other lines are weird as well

image

lmiller1990 commented 3 years ago

I think the source map is incorrect, which results in the incorrect coverage...