Testing a Vue component part 3: Creating an instance
Welcome to part 3 of a series on how to test a Vue component.
Here's the table of contents of the series:
- Starting out with tests
- The first test and snapshot testing
- Creating an instance of a component (you're here)
- More tests and faking time
- 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.
What are your thoughts on "Testing a Vue component part 3: Creating an instance"?