Vue unit testing Guide with jest - part 1
Tags: vue, javascript, testing, jest
Published: 2022-10-23 18:23:59

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.

```jsx
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)
  })
})
```

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.
    
    ```jsx
    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.
    
    ```jsx
    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.
    
    ```jsx
    // 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.

```jsx
$route: {
    name: 'your-route-name',
    params: {
      id: '123',
    }
  }
```

- **propsData**
    - From its name you can mock the props data for your component by this option.
    
    ```jsx
    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

```jsx
filters: { filter1, filter2 },
```

---

**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.

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

const wrapper = shallowMount(Component)
```

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.

```jsx
const localVue = createLocalVue()

localVue.use(Vuex)
```

To mock the state , getters  and actions. 

```jsx
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 })
```

also if you are dealing with modules.

```jsx
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
        }
      }
    })
  })
```

---

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37b0ubldjwlicjpiem0m.png)

As recommended from vue official documentation. This [presentation](https://www.youtube.com/watch?v=OIpfWTThrK8) 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](https://v1.test-utils.vuejs.org/api/wrapper/#properties) 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](https://jestjs.io/docs/expect) for the utilities you can use for assertion.

---