Welcome to part 3 of a series on how to test a Vue component.

Here's the table of contents of the series:

  1. Starting out with tests
  2. The first test and snapshot testing
  3. Creating an instance of a component (you're here)
  4. More tests and faking time
  5. Jest awesomeness and a skeleton to get started

Creating an instance of the Vue component

Now you know what snapshot testing is, let's take a fresh look at that first test:

it('can mount tabs', async () => {
    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});

The component itself is created in the createVm() function. We'll explain that await thingie a bit later. Let's take a look at createVm first. You can find it's implementation at the end of the file.

async function createVm() {
    const vm = new Vue({
        el: '#app',
    });

    await Vue.nextTick();

    return vm.$children[0];
}

Here we actually create a Vue instance. It will operate on the #app node. Remember we set the dom to some html earlier in the test. Vue will go do it's business and replace tabs and tab tags by the templates inside the Tabs and Tab components. It will not do this immediately but in an asynchronous way. We need to wait until Vue is ready. That's what that Vue.nextTick() line is all about. This will resolve after Vue's done with it's rendering work and all it's magic.

If you read the documentation regarding nextTick you'll learn it returns a promise when you don't pass it any parameters. So you can use then() on it. If you're not familiar with promises, read this article about them.

Vue.nextTick().then(function() {
  //do stuff when Vue is ready
});

The problem if we were to use it that way is that only inside the callback we would know that Vue has done it's job.

Luckily there is a new JavaScript feature that we can make use of: async/await. In short it lets you write asynchronous code in a synchronous way. Instead of having to pass a function to then when can put the await keyword before Vue.nextTick(). The code underneath that line will only execute when Vue.nextTick() is done.

await Vue.nextTick();

//do stuff when Vue is ready

Cool, so now we lose one level of indentation. You might think: "Freek, this is madness, now the code is blocking". But rest assured that behind the curtains JavaScript will still use promises and run asynchronously. Async/await is just syntactic sugar. You should also know that any function that uses await should be marked as async. That's why you see async appear in createVm()s function declaration.

If you want to know more about async/await read this article on PonyFoo or this one on Hackernoon.

This is the last line of the createVm function:

return vm.$children[0];

This line returns the first child of the Vue instance, which is the initialized Tabs component.

Back to the first test

Let's take a a third and final look at the our first test.

it('can mount tabs', async () => {
    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});

Now you should understand more or less everything that is going on. First we create a new Vue instance that will operate on the dom we set in the beforeEach each method. With that await keyword we will wait (in an asynchronous way) until Vue has done it's business. And finally we assert that the html matches the content of the snapshot.

Congratulations for reading until here. I hope you learned a lot by diving into that first test. I promise that with this new knowledge the rest of the test are now easier to understand.


Understanding that first test was hard, but now you've taken that hurdle, grasping the next tests will be easier. If you're eager to know more head over to the fourth part of this series: More tests and faking time.