Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code coverage with vue 2, typescript, mocha and karma

We are using Vue 2 in combination with Typescript and webpack 3. Vuex is used for state management. Our tests is run with Karma together with Mocha, Sinon, Expect and Avoriaz. Everything works great but I trying to get code coverage using Istanbul to work to get a better visual representation of what tests are missing.

Small representation of the folder structure

  • src

    • components
      • shared
      • button
        • button.vue
        • button.ts
    • index.ts
    • ...
  • tests

    • unit
      • components
        • shared
        • button
          • button.spec.test.ts
    • karma.conf.js
    • karma.coverage.js
    • index.ts
    • ...

button.vue

<template>
    <button onClick="handleClick" visible="visible"></button>
</template>

<script lang="ts" src="./button.ts"></script>

button.ts

import { Component, Prop, Vue } from 'vue-property-decorator';

@Component({})
export default class Button extends Vue {

    @Prop({ default: false })
    public visible: boolean;

    private onClick() {
       // do stuff
    }
}

I currently have not even created a button.spec.ts at all which is something I am trying to get the team to tackle using this informatoin and this is the result from the code coverage:

Code coverage

The coverage in general in the project:

✔ 332 tests completed
=============================== Coverage summary ===============================
Statements   : 43.88% ( 1847/4209 )
Branches     : 36.83% ( 952/2585 )
Functions    : 32.97% ( 456/1383 )
Lines        : 45.28% ( 1732/3825 )
================================================================================

But in general, the results are not actually showing the code coverage at all. Every file is like this:

Code lines

My questions

  • How do I get a better result for this? Am I missing something basic about code coverage?
  • How do I code cover functions that are only run in .vue-files?

Other files that might be related:

karma.coverage.js

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['mocha', 'chai', 'sinon'],
    files: [
      'index.ts'
    ],
    reporters: reporters,
    preprocessors: {
      'index.ts': ['webpack']
    },
    webpack: webpackConfig,
    webpackServer: {
      noInfo: true
    },
    junitReporter: {
      outputDir: 'reports/'
    },
    coverageReporter: {
      reporters: [{
        type: 'json',
        dir: '../../coverage/',
        subdir: '.'
      },
      {
        type: 'text-summary'
      },
    ]
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['PhantomJS_custom'],
    customLaunchers: {
        'PhantomJS_custom': {
            base: 'PhantomJS',
            options: {
                windowName: 'my-window',
                settings: {
                    webSecurityEnabled: false
                },
            },
            flags: ['--remote-debugger-port=9003', '--remote-debugger-autorun=yes'],
            debug: false
        }
    },
    phantomjsLauncher: {
        // Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
        exitOnResourceError: true
    },
    mime: {
      'text/x-typescript': ['ts']
    },
    singleRun: true,
    concurrency: Infinity
  });
};

unit/index.ts

import 'babel-polyfill';
import Vue from 'vue';

Vue.config.productionTip = false;

function requireAll(r: any): any {
    r.keys().forEach(r);
}

requireAll((require as any).context('./', true, /spec.ts$/));
requireAll((require as any).context('../../src/', true, /^(?!.*(main)).*ts$/));
like image 527
Viktor Sarström Avatar asked Feb 09 '18 09:02

Viktor Sarström


1 Answers

I would suggest, that you should use use vue-unit.

For example your test case could look like:

import { beforeEachHooks, afterEachHooks, mount, waitForUpdate, simulate } from 'vue-unit'
import Button from '@/components/Button'

describe('Button', () => {
  beforeEach(beforeEachHooks)

 it('should render with hidden class if visible is set to false', () => {
     const vm = mount(Button, {
         visible: false //you can ass properties
     })

     expect(vm.$el).to.have.class('hidden') //example assertions, needs chai-dom extension
  })

  afterEach(afterEachHooks)
})

You can also check result of single methods:

 const vm = mount(Button)

 expect(vm.$el.somemethod('val')).to.be('result')
 //method declared in methods block

You should also consider adding extensions to chai, like chai-dom or sinon-chai, which would allow you to create more flexible assertions:

it('should invoke onClick handler when button is clicked', () => {
    const spy = sinon.spy()

    const vm = mount(Button, {
      onClick: spy
    })

    simulate(vm.$el, 'click')

    expect(spy).to.be.called
  })

You can configure it in karma.conf.js:

//karma.conf.js
...
frameworks: ['mocha', 'chai-dom', 'sinon-chai', 'phantomjs-shim'],
...

IMHO Your code coverage configuration looks fine, so if you add tests for your components it should boost your stats.

like image 93
Krzysztof Atłasik Avatar answered Sep 19 '22 21:09

Krzysztof Atłasik