Vue unit testing Guide with jest - part 1

mennaaly

Mennaali

Posted on October 23, 2022

Vue unit testing Guide with jest - part 1

This will be a series of testing guide to how to write a unit test in vue and how can you test your vue components.

We will go through the concepts in this article. and what actually we need to understand to create an environment for your component to be tested.

Stub component

This is first step before we dig into writing tests itself. This step is basically preparing the vue.js component to be in a wrapper which have some functionality to interact with while testing.

Mount :

Creates a wrapper for that contains the mounted and rendered vue component.

import { mount } from '@vue/test-utils'
import Foo from './Foo.vue'

describe('Foo', () => {
  it('renders a div', () => {
    const wrapper = mount(Foo)
    expect(wrapper.contains('div')).toBe(true)
  })
})
Enter fullscreen mode Exit fullscreen mode

Mount has several options I won’t go through all of them but I’ll take the most used ones in the test

  • Data

    • This allow to us to mock our data and it’ll be merged to the existing data object in the component itself.
    const Component = {
      template: `
        <div>
          <span id="foo">{{ foo }}</span>
          <span id="bar">{{ bar }}</span>
        </div>
      `,
      data() {
        return {
          foo: 'foo',
          bar: 'bar'
        }
      }
    }
    const wrapper = mount(Component, {
      data() {
        return {
          bar: 'my-override'
        }
      }
    })
    wrapper.find('#foo').text() // 'foo'
    wrapper.find('#bar').text() // 'my-override'
    
  • stubs

    • As we said the Mount just stub the component itself so if we want to test the component’s children we need to stub them as well. stubs option allow to us to stub child components.
    import Foo from './Foo.vue'
    
    mount(Component, {
      stubs: ['registered-component']
    })
    
  • mocks

    • It’s useful to mock the global injections which means any global property for the vue component could be mocked here.
    • example : if your component use state to go to another route so you need to stub the this.$state in your wrapper also. this could be done here in mocks.
    // In component 
    this.$state.go(this.cellRouteName, { id, filters: this.detailsPageFilters});
    
    // In unit test 
    mocks:{
          $state:{
            go:()=>{},
            href: ()=>{},
            params: {filters: '{}', sort: '{}'},
          },
    },
    
  • another example we can use the mocks is the $route. The $route is global property for any vue component it basically show your current route and the params in the url. if you want to mock the current url with its params you can mock it here because sometimes you need to do something with the parameters the $router object.

$route: {
    name: 'your-route-name',
    params: {
      id: '123',
    }
  }
Enter fullscreen mode Exit fullscreen mode
  • propsData

    • From its name you can mock the props data for your component by this option.
    const Component = {
      template: '<div>{{ msg }}</div>',
      props: ['msg']
    }
    const wrapper = mount(Component, {
      propsData: {
        msg: 'aBC'
      }
    })
    expect(wrapper.text()).toBe('aBC')
    
  • Filters

    • You can mock the filters used in the component
filters: { filter1, filter2 },
Enter fullscreen mode Exit fullscreen mode

Shallow Mount:

It’s like Mount. it gives us a wrapper to the vue component without mounting all its child components and vue stubs the child components for us. mounting all child components may make your tests slow especially for the components have a lot of child components.

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

const wrapper = shallowMount(Component)
Enter fullscreen mode Exit fullscreen mode

for the options . it has mostly the same options we discussed last section in Mount.


Vuex mocking

If we are dealing with vuex we will have our store with state , getters , actions and my we have modules.

To pass this values we need to send the store in a vue constructor. so we create a local vue component and pass the vuex to it.

const localVue = createLocalVue()

localVue.use(Vuex)
Enter fullscreen mode Exit fullscreen mode

To mock the state , getters and actions.

beforeEach(() => {
    actions = {
      actionClick: jest.fn(),
      actionInput: jest.fn()
    }

    getters = {
      clicks: () => 2,
      inputValue: () => 'input'
    }

   state = {
      clicks: 2
    } 

    store = new Vuex.Store({
      actions,
      getters,
      state
    })
  })

const wrapper = shallowMount(MyComponent, { store, localVue })
Enter fullscreen mode Exit fullscreen mode

also if you are dealing with modules.

import myModule from '../../../src/store/myModule';

beforeEach(() => {
    state = {
      clicks: 2
    }

    actions = {
      moduleActionClick: jest.fn()
    }

    store = new Vuex.Store({
      modules: {
        myModule: {
          state,
          actions,
          getters: myModule.getters,
          namespaced: true
        }
      }
    })
  })
Enter fullscreen mode Exit fullscreen mode

What to test in vue unit test ?

Vue documentation have a recommendation for what we should test in nutshell. It said

Instead, we recommend writing tests that assert your component's public interface, and treat its internals as a black box. A single test case would assert that some input (user interaction or change of props) provided to the component results in the expected output (render result or emitted custom events).

What this means ?

It means we don’t need to concentrate of the actual implementation of our methods in the component. what we want to rely on is testing the input for the component and how the component will react on this input. The benefit from this is we are dealing with our component as an interface so how ever the implementation changes the tests should pass.

Image description

As recommended from vue official documentation. This presentation has a very well description for what we should test in vue.


Testing using the wrapper after mocking it using shallow mount or mount

There’s a list of wrapper utilities able you to access different things inside the wrapper itself upon your needs . but the most important things is you can access to all our methods and properties using wrapper.vm.


Vue unit tests with jest.

Jest is a testing framework it works with different frameworks like angular, vue.

Mainly we use jest to assert over the expected behavior. This is list for the utilities you can use for assertion.


💖 💪 🙅 🚩
mennaaly
Mennaali

Posted on October 23, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related