Knowing What To Test — Vue Component Unit Testing
A tutorial for reviewing components and knowing what to test and how frequently they need testing. Includes reviewing inputs and outputs.
Join the DZone community and get the full member experience.Join For Free
You may also like: How and Why We Moved to Vue.js
The most common question about unit testing Vue components I see out there is "what exactly should I test?"
While it's possible to test either too much or too little, my observation is that developers will usually err on the side of testing too much. After all, no one wants to be the guy or girl whose under-tested component crashed the app in production.
In this article, I'll share with you some guidelines I use for unit testing components that ensure I don't spend forever writing tests but provide enough coverage to keep me out of trouble.
I'll assume you've already had an introduction to Jest and Vue Test Utils.
Before we get to the guidelines, let's first get familiar with the following example component that we'll be testing. It's called Item.vue and is a product item in an eCommerce app.
Here's the component's code. Note there are three dependencies: Vuex (
$store), Vue Router (
$router) and Vue Auth (
Spec File Setup
Here's the spec file for the tests. In it, we'll shallow mount our components with Vue Test Utils, so I've imported that, as well as the Item component we're testing.
I've also created a factory function that will generate an overrideable config object, saving us having to specify props and mocking the three dependencies in each test.
Identify the Business Logic
The first and most important question to ask about a component you want to test is "what is the business logic?", in other words, what is the component meant to do?
For Item.vue, here is the business logic:
- It will display an item based on the
- If the user is a guest, clicking the Add to Cart button redirects them to the login page.
- If the user is logged in, clicking the Add to Cart button will trigger a Vuex mutation
Identify the Inputs and Outputs
When you unit test a component, you treat it as a black box. Internal logic in methods, computed properties, etc, only matter insofar as they affect output.
So, the next important thing is to identify the inputs and outputs of the component, as these will also be the inputs and outputs of your tests.
In the case of Item.vue, the inputs are:
- State from Vuex and Vue Auth.
- User input via button clicks.
While the outputs are:
- Rendered markup.
- Data sent to Vuex mutation or Vue Router push.
Some components may also have forms and events as inputs, and emit events as outputs.
Test One: Router Called When Guest Clicks Button
We'll set up the test by shallow mounting the component, then finding and clicking the Add to Cart button.
We'll add an assertion in a moment.
Don't Go Beyond the Boundaries of the Input and Output
It'd be tempting in this test to check that the route changed to that of the login page after clicking the button e.g.
While this does test the component output implicitly, it's relying on the router to work, which should not be the concern of this component.
It's better to directly test the output of this component, which is the call to
$router.push. Whether the router completes that operation is beyond the scope of this particular test.
So let's spy on the
push method of the router, and assert that it gets called with the login route object.
Test Two: Vuex Called When Auth User Clicks Button
Next, let's test the business logic for "If the user is logged in, clicking the Add to Cart button will trigger a Vuex mutation
To re-iterate the above lesson, you don't need to check if the Vuex state gets modified. We would have a separate test for the Vuex store to verify that.
This component's job is simply to make the commit, so we just need to test it does it that.
So let's first override the
$auth.check mock so it returns
true (as it would for a logged-in user). We'll then spy on the
commit method of the store, and assert it was called after the button is clicked.
Don't Test Functionality of Other Libraries
The Item component displays a store item's data, specifically the title, and image. Maybe we should write a test to specifically check these? For example:
This is another unnecessary test as it's just testing Vue's ability to take in data from Vuex and interpolate it in the template. The Vue library already has tests for that mechanism so you should rely on that.
Test Three: Renders Correctly
But hang on, what if someone accidentally renames
name and then forgets to update the interpolation? Isn't that something worth testing for?
Yes, but if you test every aspect of your templates like this, where do you stop?
The best way to test markup is to use a snapshot test to check the overall rendered output. This will cover not just the title interpolation, but also the image, the button text, any classes, etc.
Here are some examples of other things there is no need to test:
- If the
srcproperty is bound to the img element.
- If data added to the Vuex store is the same data that gets interpolated.
- If the computed property returns the correct item.
- If the router push redirects to the correct page.
I think those three relatively simple tests are sufficient for this component.
A good mindset to have when unit testing components is to assume a test is unnecessary until proven otherwise.
Here are the questions you can ask yourself:
- Is this part of the business logic?
- Does this directly test the inputs and outputs of the component?
- Is this testing my code, or third-party code?
Published at DZone with permission of Anthony Gore, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.