Search code examples
testingwebpackkarma-runnervue.jsvue-loader

Test vue.js components with vue-loader dependency injection


I'm trying to test my Vue.js component using webpack's loader vue-loader. I was following their tutorial but things didn't work out as expected. Here's my component:

<template>
  <header v-once class="header">
    <router-link to="/" class="brand">
      <span class="brand-name">{{ brand }}</span>
      <span class="brand-version">{{ version }}</span>
    </router-link>
  </header>
</template>

<script>
  import { brand, version } from './Header.json';
  export default {
    name: 'Header',
    data() {
      return {
        brand,
        version
      }
    }
  };
</script>

<style lang="sass" rel="stylesheet/scss" scoped>
  $font-stack: 'Open Sans', sans-serif;
  $primary-color: #2d5079;
  $border-color: #345b88;
  $brand-color: whitesmoke;

  .header {
    .brand {
      .brand-name {
        letter-spacing: -1px;
      }
      .brand-version {
        font-size: 50%;
      }
      display: table-cell;
      padding-left: 10px;
      vertical-align: middle;
      text-decoration: none;
      color: $brand-color;
      text-transform: lowercase;
      font-weight: 100;
      font-size: 120%;
    }
    display: table-row;
    height: 50px;
    font-family: $font-stack;
    background-color: $primary-color;
    border-color: $border-color;
    border-bottom: 1px solid;
    align-items: center;
    padding: 0 10px;
    user-select: none;
  }
</style>

Here's my spec file:

import Vue from 'vue';

const headerInjector = require('!!vue?inject!./Header.vue');
const header = headerInjector({
  './Header.json': {
    brand: "Test",
    version: "1.2.3"
  }
});

describe('Header', () => {
  it('should be named Header', () => {
    expect(header.name).toEqual('Header');
  });
  it('should render', () => {
    const vm = new Vue({
      template: '<div><header></header></div>',
      components: {
        header
      }
    }).$mount();
    expect(vm.$el.querySelector('.brand-name').textContent).toBe('Test');
    expect(vm.$el.querySelector('.brand-version').textContent).toBe('1.2.3');
  });
});

I use karma to run my tests. Here's karma config file:

const conf = require('./gulp.conf');

module.exports = function (config) {
  const configuration = {
    basePath: '../',
    singleRun: false,
    autoWatch: true,
    logLevel: 'INFO',
    junitReporter: {
      outputDir: 'test-reports'
    },
    browsers: [
      'PhantomJS'
    ],
    frameworks: [
      'jasmine'
    ],
    files: [
      'node_modules/es6-shim/es6-shim.js',
      conf.path.src('app.spec.js')
    ],
    preprocessors: {
      [conf.path.src('app.spec.js')]: [
        'webpack'
      ]
    },
    reporters: ['progress', 'coverage'],
    coverageReporter: {
      type: 'html',
      dir: 'coverage/'
    },
    webpack: require('./webpack-test.conf'),
    webpackMiddleware: {
      noInfo: true
    },
    plugins: [
      require('karma-jasmine'),
      require('karma-junit-reporter'),
      require('karma-coverage'),
      require('karma-phantomjs-launcher'),
      require('karma-phantomjs-shim'),
      require('karma-webpack')
    ]
  };

  config.set(configuration);
};

and here's the used webpack config for the pre-processing:

module.exports = {
  module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint'
      }
    ],
    loaders: [
      {
        test: /.json$/,
        loader: 'json'
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      },
      {
        test: /.vue$/,
        loader: 'vue'
      }
    ]
  },
  plugins: [],
  debug: true,
  devtool: 'source-map'
};

Here's app.spec.js which is the entry point for the tests which karma loads. It's responsible for loading all spec files:

const context = require.context('./components', true, /\.spec\.js$/);
context.keys().forEach(context);

Now, when I run the tests with karma, I get the following error:

PhantomJS 2.1.1 (Windows 8 0.0.0) ERROR
  TypeError: Object is not a constructor (evaluating '__vue_exports__(injections)')
  at src/app.spec.js:1271

I have no clue for why this is happening, or what this error means, it's a bit cryptic to me. Could someone pinpoint my error and explain it?


Solution

  • Was experiencing the same thing, seems to be an issue with version 3+ of inject loader. Perhaps the vuejs testing with mocks docs needs to be updated.

    force the version in your package.json

    "inject-loader": "^2.0.1",