The next question that a lot of people ask, ‘What should I test?’, is not easy to answer, and I won’t attempt to do it here. I’ve listed some further reading that you may find useful below. However, if you already know, here are some patterns that you may find useful.

Testing Rendered HTML

A quick way to test rendered HTML is snapshot testing. This simply serializes a mounted component for comparison later, guarding against unexpected UI changes. First, we run yarn add jest-serializer-vue , and then add a single line to our package.json in the jest section:

Now, we can create a snapshot test very simply:

This just serializes the HTML that is rendered by the component for comparison later. If we actually do change the UI, we can update our snapshots by running yarn test -u . The resulting snapshot files should always be checked in to version control.

Testing Methods

Methods are a perfect candidate for unit testing: when written properly, they depend only on their explicit inputs, and they should return a predictable output based on them. Once you’ve mounted your component, and assigned it to a variable (I have used idiomatic name wrapper ), accessing methods is as simple as calling wrapper.vm.someMethod(arg1, arg2) . You can then test your methods like this:

Obviously, this example is trivial; unit testing methods is only worthwhile if they are complicated enough that they are difficult to refactor anyway.

Testing Computed Properties

Computed properties are more difficult to test, as they rely on some kind of implicit input (either the context they are called in, i.e. this , or some other state in a broader scope than the function). They should, however, be pure functions, so it’s easy to test their output. We can set data in a Vue component using the wrapper.setData , or the wrapper.setProps methods. Both of these initialize the mounted component with data which you can then use to test computed properties. setProps is being deprecated as I write this, so the correct pattern is as follows:

Advanced Bonus Mega Fun

The component we have been testing so far has been very simple: it does not interact with a vuex store, isn’t aware of routing, doesn’t depend on any external libraries, and doesn’t rely on any browser APIs which aren’t provided by Node. Some or all of these things may need to be mocked in a more complex component, or in a router view.

Mocking the $route object

One of the easiest things to mock is the router, or more specifically, the route object that a Vue instance has access to. For example, if a method or computed property accesses this.$route.path , we can create an object with this property and feed it into the options argument of the mount function provided by vue-test-utils.

Mocking Browser APIs

Browser APIs must also be mocked relatively often. If a component relies on localStorage , we need to mock that. At 3YOURMIND, we achieve this using a test helper function to provide stubbed functionality to ensure tests run.

You can now just import this helper in any test which requires it. In this case, the tests don’t actually test the component’s usage of localStorage . Without this mock, however, the component would not mount for testing and therefore its most basic properties must be stubbed. This kind of function could be extended to provide arbitrary functionality to help you test your components.

Mocking a Vuex store

Mocking the store is usually the most time-consuming part of testing a Vue component. However, with a well-designed store, writing factory functions to make mocking the store less painful is not difficult. For a good primer on large-scale Vue app design, I recommend my colleague Kevin’s Medium article. What I’ve tried to do with the following tests, is to match the structure of the real store exactly in the mocks. Below is a naive implementation of a mocked store in a test; later on, I’ll suggest an alternative and list its benefits.

This test passes, but the test looks a little verbose. If we were accessing three or four modules from a component (or more likely a view which has not been refactored into smaller pieces yet), this would quickly become unmanageable, and our test files would become huge. Instead of mocking the store structure in the CoolCardNaive.test.js file, let’s abstract it away and move it into a utility which we can import into all of our tests. Another note: we’ve included a new beforeEach function here. This resets the store before each test to make sure that they are independent of each other. This is an important quality when unit testing.

Factory Functions for mocking the store

Assuming a similar structure to the one that Kevin suggested, here is a very minimal example factory function which will spit out all the mocked getters you need to mount an arbitrarily complex view or component:

You can use this in your tests like so:

Basically, you just need to define mock values for any getters that the component you are testing relies on. It’s completely reusable, as it any getters which are not mocked in the function call return null and don’t affect the component being tested. Any actions which are needed are just mocked with Jest’s jest.fn() mock function, which is all that is necessary, as here we are testing the component, and not our actions. Another advantage is that as our application grows, and more modules are introduced, each test only needs one or two extra lines, instead of mocking the shape of a whole module every time.

The downside, of course, is the time spent to create the store factory function in the first place. For a medium-sized app with 7 modules that I am working on at the moment, it took about half an hour, which I feel is worth it.

Bonus Round: Test Structure

The only other thing I would like to mention when it comes to the structure is naming conventions. We try to keep everything as consistent as possible; for example, if we have a component named SomeComponent.vue , its test will always be named SomeComponent.test.js . It’s little details like this make onboarding new developers as painless as possible, which is a win for everyone.

Bonus Round 2: Nodelectric Boogavue

Set this as an alias in your shell now, and it will save you hours in the future: node --inspect-brk node_modules/.bin/jest --runInBand

You can now throw a debugger statement anywhere in your tests, run this command and go to chrome://inspect in chrome to open a the devtools and debug your tests.

Conclusion

Testing isn’t everyone’s favourite thing to do at work, but thanks to vue-test-utils it can be relatively painless. To finish off, I’d like to recommend some further reading to cover things I didn’t have enough space (or knowledge) to explore properly.

We haven’t covered testing Vuex actions here, as I’ve concentrated on components. Lachlan Miller has written an excellent article about this, which I recommend reading as soon as you’re done here.

Knowing what to test is even more important than being an expert in writing the tests themselves. I’m currently reading blogs by Kent C. Dodds, and Refactoring Javascript by Evan Burchard, both of which have helped me to concentrate on testing only worthwhile things, and reinforced just how important good testing is in the first place. More specifically, the mastermind behind vue-test-utils, Edd Yerburgh, has recently written a book which specifically covers testing Vue applications in far more detail than I could ever match. Check it out.