Testing Vue Components with Jest – Part 1

check-3183193_1920

Testing Vue Components with Jest – Part 1

Have you been writing VueJS without proper tests in place? That is a dangerous path especially if you have any reasonable amount of business logic to handle. VueJS has been our tool of choice and combined with Laravel, it has delivered great results but all too often, it has kept us with our fingers crossed everything is tight as it seems on the UI. So it was with much joy that we bumped into Vue Test Utils quite recently, and got stuck in wiring tests. We learned a ton and would like to show how you can test VueJS using Jest framework by Facebook. Of course you can use other testing frameworks (Mocha, Ava, Tape, etc) as well, but we want to keep this post as straightforward as possible. In other words this is a crash course. And it will be in two parts as there is a bit to cover.

Setting up for testing

Follow the guide here: https://vue-test-utils.vuejs.org/en/guides/testing-SFCs-with-jest.html which will get webpack properly handling vue files as well as installing the node modules we are going to use.

Unit Testing

We are going to create a very basic component that grows as we scale up our test so follow closely:

UserProfile.Vue

First off we want to be able to display the value of the “name” binding in our html. The point of a unit test here is to see if we have the binding in VueJS working properly. We are not concerned with what the html looks like, as this is not an integration test, however Vue Test Utils does have that functionality baked in which we will explore in the second part.

Here is what our test looks like to test for the binding above:

Couple of things here:

  1. Rendering a component shallow means we are not concerned with that component’s children, which results in a more focused unit test for each component, besides the obvious speed gain.
  2. Wrapper.vm gives us direct access to the Vue instance which has all the data and all the other goodies from the component.

Let’s expand our component and include some props that it should expect:

We can easily set our propsdata at declaration and test for that too:

Testing lifecycle hooks

So far we have been dealing with data that we assume is on the component, and that has nothing to do with Vue’s lifecycle methods. It’s often normal to have an API fetch something that we set on the component so how do we handle that?

Let’s expand and fetch the user’s likes via an axios call, add the following to our snippet:

We have a couple of ways to handle this scenario, the best one I think is to spy on our component and make sure that the method is called in the first place as follows:

That is not the last of our problems however because of the axios.get method which the created hook actually calls at runtime. We will get an error in the terminal with something along the lines of: ReferenceError: axios is not defined

Setting up mocks with Jest

My solution is to mock or stub any functionality with potential side effects. Depending on what your wepback configuration is, I have Jest setup to run a file before all tests to set up the testing environment. This allows one to have stuff like axios, localStorage / global set up and nicely mocked. Using https://facebook.github.io/jest/docs/en/configuration.html#setuptestframeworkscriptfile-string I have a mocked implementation of axios as follows:

Now if you run the test, it should succeed because when the created lifecycle hook is run, it simply calls global.axios which doesn’t return anything from that call. Is that a problem, no, because we can mock that call’s implementation too to see the route called and any other parameters each axios call should get as follows:

Testing vue’s methods

We also can have methods on the vue’s instance that require special handling. With unit testing after all, the idea is to test how our functions behave and what data they output. Let’s expand the example to include a method that depends on a computed property and tells the user a custom message:

Testing this kind of functionality requires us to have predictable code, however a computed property will always change due to a certain condition, in this case: time. The best way to test what setGreeting() produces is to supply different timeOfDay values to it. Therefore we have to stub it instead as follows:

wrapper = shallow(UserProfile)
let afternoon = sinon.stub(UserProfile.computed, 'timeOfDay').returns("afternoon")
let afternoonMsg = wrapper.vm.setGreeting()
expect(afternoonMsg).toBe('hey Chiko, time to go for a swim!')
let evening = sinon.stub(UserProfile.computed, 'timeOfDay').returns("evening")
eveningMsg = wrapper.vm.setGreeting()
expect(eveningMsg).toBe('hey Chiko, close the windows and curtains!')

In the next post I will go into detail concerning testing refs and emitted events as well as mounting a full component. If you have any questions, comments or any feedback please leave a comment below. Thanks for reading!

Chiko Mukwenha
chiko@onesheep.org
No Comments

Sorry, the comment form is closed at this time.