vue-testing

0.0.3 • Public • Published

Vue Testing

Let's make Vue Testing And Mocking Become Easier And Much Fun.

Installation

npm install vue-testing inject-loader --save-dev

Motivation

If you're testing without vue-testing you'll realize that you have a long boilerplate code to mock up your component. Let me show you how it looks. It's taken from https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html

<!-- example.vue -->
<template>
  <div class="msg">{{ msg }}</div>
</template>
 
<script>
// this dependency needs to be mocked
import SomeService from '../service'
 
export default {
  data () {
    return {
      msg: SomeService.msg
    }
  }
}
</script> 
// example.spec.js
 
// Import the component and make the injection preparation
const ExampleInjector = require('!!vue?inject!./example.vue')
 
// Inject and Mock External Resource
const ExampleWithMocks = ExampleInjector({
  // mock it
  '../service': {
    msg: 'Hello from a mocked service!'
  }
})
 
it('should render', () => {
  // Render the component manually
  const vm = new Vue({
    template: '<div><test></test></div>',
    components: {
      'test': ExampleWithMocks
    }
  }).$mount()
  expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!')
})

Magic Vue Properties

Probably, you'll not get frustated with that code. Cause it's simple. until your component uses vue properties that magically injected by some plugin. For example vue-router injects this.$router and this.$route Or vuex injects this.$store. It will throw error variable undefined since we not render the whole app. So, How do you handle it without touching your component code? It needs some effort.

<!-- example.vue -->
<template>
  <div class="msg">{{ msg }}</div>
</template>
 
<script>
// this dependency needs to be mocked
import SomeService from '../service'
 
export default {
  data () {
    return {
      msg: SomeService.msg
    }
  },
 
  created() {
    // Use Magic Properties
    if(this.$route.params === someCondition) this.$router.push('/login')
  }
}
</script> 
// example.spec.js
 
// Import the component and make the injection preparation
const ExampleInjector = require('!!vue?inject!./example.vue')
 
// Inject and Mock External Resource
const ExampleWithMocks = ExampleInjector({
  // mock it
  '../service': {
    msg: 'Hello from a mocked service!'
  }
})
 
// You can inject magic properties this way
ExampleWithMocks.beforeCreate = function () {
  this.$route = { params: {} }
  this.$router = { push: () => {} }
}
 
it('should render', () => {
  // Render the component manually
  const vm = new Vue({
    template: '<div><test></test></div>',
    components: {
      'test': ExampleWithMocks
    }
  }).$mount()
 
  expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!')
})

Vuex Helper Function

Oke, let's say that you always pass the router params via props since vue-router@2.2.x. But you'll still get the problem when you're using vuex helper function like mapActions, mapStates, mapGetters. Sure, you need write more.

<!-- example.vue -->
<template>
  <div class="msg">{{ msg }}</div>
</template>
 
<script>
// this dependency needs to be mocked
import SomeService from '../service'
 
// Vuex Helper Function
import { mapActions } from 'vuex'
 
export default {
  data () {
    return {
      msg: SomeService.msg
    }
  },
 
  methods: {
    // Use It!
    ...mapActions({
      test: 'SOME_ACTION'
    })
  },
 
  created() {
    // Use Magic Properties
    if(this.$route.params === someCondition) this.$router.push('/login')
    // Bind It!
    this.test()
  }
}
</script> 
// example.spec.js
 
// Import the component and make the injection preparation
const ExampleInjector = require('!!vue?inject!./example.vue')
 
// Inject and Mock External Resource
const ExampleWithMocks = ExampleInjector({
  // mock it
  '../service': {
    msg: 'Hello from a mocked service!'
  },
 
  'vuex': {
    mapActions: () => {}
  }
})
 
// Mock The Method To Put Your Spy
ExampleWithMocks.methods = {
  ...ExampleWithMocks.methods,
  test: function() {
    return spy
  }
}
 
// You can inject magic properties this way
ExampleWithMocks.beforeCreate = function () {
  this.$route = { params: {} }
  this.$router = { push: () => {} }
}
 
it('should render', () => {
  // Render the component manually
  const vm = new Vue({
    template: '<div><test></test></div>',
    components: {
      'test': ExampleWithMocks
    }
  }).$mount()
 
  expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!')
})

Let's Make It Simple!

Let's make it simple with vue-testing. You'll just need little effort to mock your component constructor. Take a peek.

// example.spec.js
 
// Import Vue Testing Helpers
import { mockComponent, mount } from 'vue-testing';
 
// Import the component and make the injection preparation
const ExampleInjector = require('!!vue?inject!./example.vue')
 
// Mock It!
let Component = mockComponent(ExampleInjector, {
 
  // You can inject component properties via propsData
  propsData: {
    msg: 'hai'
  },
 
  // Even You can inject the local state without breaking your beforeCreate function
  // It will save you from mapStates and mapGetters vuex function error in testing
  states: {
    localState: 'hello',
    $route: {
      params: {}
    },
    $router: {
      push: () => {}
    }
  },
 
  // You can inject the actions to be your local methods!
  // It will save you from mapActions vuex function error in testing
  actions: {
    test: () => spy
  },
 
 
  // Default integrated with vuex-saga
  // It will save you from mapSagas vuex-saga function error in testing
  sagas: {
    test: () => {}
  },
 
 
  // Mock the external module
  // You can just put all in one scope
  '../service': {
    msg: 'Hello from a mocked service!'
  },
  'jquery': () => {}
  'external-module': {}
})
 
 
describe('ExampleComponent', function () {
 
  let vm;
  beforeEach(function () {
    // Mount it!
    // Mount it in every test scope. So you'll get fresh component
    vm = mount(Component)
  })
 
  // Focus On Your Test!
  it('Some Test', function () {
    const actual = vm.$el.querySelector('.msg').textContent
    const expected = 'Hello from a mocked service!'
    expect(actual).toBe(expected)
  })
 
})

Have You Tested Your Components? You Should Be~

Thank You for Making this useful~

Let's talk about some projects with me

Just Contact Me At:

License

MIT Copyright (c) Naufal Rabbani

Package Sidebar

Install

npm i vue-testing

Weekly Downloads

2

Version

0.0.3

License

MIT

Last publish

Collaborators

  • bosnaufal