Choosing Testing Tools0:00
If you're hoping to test your Vue projects, or even TDD your Vue components, you've come to the right place. Now, the recommended and official unit testing library for Vue is called Vue TestUtils. However, this is just a library, you still need to pick a dedicated test framework, like Mocha, or Jasmine, or Jest, or Tape, or Ava, any of them will do. We'll be using Mocha and Mocha Webpack. So let's get started. I'm going to make a project here called testing-vue, and open it up in code. Now, we'll be pulling in a lot of packages, so let's go ahead and run npm init -y, and that will quickly scaffold a package.json file.
Now, we'll be pulling in a lot of packages, so let's go ahead and run npm init -y, and that will quickly scaffold a package.json file. Okay. Next, if we're going to be using this, let's just go ahead and pull it in, and save it to my dev dependencies list. But now we probably need a couple of other things, right? If we're testing Vue, well then, of course, this project requires Vue. Next, if we're going to use Mocha, we'll take a look at this. Within the documentation, there is an example of how we can do this. Now, you'll notice we're going to pull in Mocha, but also Mocha Webpack, and what this
Creating Counter Component1:00
Within the documentation, there is an example of how we can do this. Now, you'll notice we're going to pull in Mocha, but also MochaWebpack, and what this will allow us to do is compile or precompile .vue files down for the purposes of our test, so it can be very useful. Okay, so let's go ahead and run that, and these will be saved to our devDependencies list as well. Next, let's set up our source file. So we're going to have a src, and we're going to start with that typical Counter component. So we'll put this in components, Counter, and we'll start with .js, and then later switch over to precompiling a .vue file.
So we'll put this in components, counter, and we'll start with .js, and then later switch over to precompiling a .vue file. Okay, so to start, this is going to export some kind of Vue component. Great. Next, what about my testing? Well, let's set up a test directory, and if we're testing our counter, I could do counter.spec.js. Now, before I write anything here, I want to make it very simple to trigger our tests. Ideally, I would just say npm test, and everything would work. But right now, we see error, no test specified, and that's because, by default, that's what we have here.
Configuring Mocha Webpack2:00
But right now, we see error, no test specified, and that's because, by default, that's what we have here. So anything we put within the test npm script will automatically be triggered, as you would have guessed, when I run npm test. So let's set this up. We're going to trigger Mocha Webpack, and if Mocha Webpack allows us to precompile any of our assets, well, then we have to tell it the path to our Webpack configuration file. So generally, that will be in your project root, and very likely, you already have one. But in our case, we don't. So I will create that.
But in our case, we don't. So I will create that. And if we're going to use Webpack, well, then, of course, we've got to pull in Webpack as well. So npm install Webpack. Next, what are we testing? Well, we're going to test any of the files within the test directory. So let's say test/*.spec.js. So now, let's give it a shot, npm test, and in this case, we get zero passing because we literally have nothing here.
Writing First Unit Test2:52
So now, let's give it a shot, npm test, and in this case, we get zero passing because we literally have nothing here. Okay. Let's get started by pulling in our counter. So if I want to test counter, now we're in the test directory, so let's go up into the src/components/counter.js file. Now we will describe counter. So describe is coming from the Mocha test framework. So when we run Mocha, this will be available to us. So let's just say, what does a counter do?
So when we run Mocha, this will be available to us. So let's just say, what does a counter do? Well, at the very least, the count defaults to zero. So let's say that it defaults to a count of zero. Now, how do we get access to our counter here? Well, this is where Vue Test Utils comes into play. So I can say import, and we'll grab the mount. So what this will do is it'll mount the component in isolation. So it'll mock any of the inputs like the props or anything like that automatically for you.
So it'll mock any of the inputs like the props or anything like that automatically for you. So it's very useful. So we'll pull that from Vue Test Utils. Next, I can say I want to mount the counter. Now when you do this, it's going to return a wrapper of sorts. It gives you a bunch of helper methods, but just think of it as a wrapper around the component and the root DOM node. So we'll call that a wrapper. Okay.
So we'll call that a wrapper. Okay. Now, if we want to access the data properties on the Vue component, you can always say wrapper.vm. So maybe the count should default to zero. So I could say, well, I need an assertion library. And there's some we can pull in out of the box, but one that's very popular is expect that comes with Jest. So I could say import expect from 'expect'. And we do need to pull that in. Great.
And we do need to pull that in. Great. And now, if you're ever curious about these APIs, of course, you can review the documentation to see everything available to you, but in our case, I can help you out. So we'll say expect the count to be, well, zero by default. All right. So let's give this a run. Ah, it fails. Module not found. So cannot resolve Vue template compiler.
Setting Up jsdom5:34
jsdomglobal. All right. So we need to pull this in to allow Vue Test Utils to run properly. So we'll pull that in. And next you'll see we need to have a setup file. So a setup file would be something that runs before all of your tests, and it's really good for initial setup that you want to do right before your test suite is triggered. And it looks like we need to pull in, or require, jsdomglobal. Okay. Let's do this.
Okay. Let's do this. a test setup.js file where we will require it. And of course, you can do anything else you need to here for a real project. But now how do we tell Mocha that I want it to trigger this file? Well, we can come back to our script and we can say right here, before you run the test, I want to require test setup.js. Okay. Great. So let's give this another run.
Great. So let's give this another run. And now we're in business. So it did fail. We expected zero, but at the moment we're returning undefined. Nothing. Okay. Let's get started on this. So we'll say, well, if the defaultCount is zero, well then let's return a count of zero. Give it another run.
Testing Rendering and Clicks7:06
it like this, or in some situations you don't have to create a whole new wrapper. It just depends on what you're testing. I happen to know ultimately we will want to do it this way, but to start, let's just pull this out for the time being. Okay. Anyways, we can access a number of helpers off of the wrapper object. And in fact, if we switch back to the documentation, you can find your wrapper object here as well as all of the methods. And you'll often use contains, find to find an element, HTML to get the full rendered HTML.
And you'll often use contains, find to find an element, HTML to get the full rendered HTML. You can even trigger events like trigger that this button was clicked. Okay. Let's give it a shot. Now, if it presents the current count, maybe we're going to have some kind of element with a class of count. And when you call find, that's going to return its own wrapper. So at that point, I could say, well, give me the HTML of that count element. And I'm going to expect that HTML to contain the current count.
So at that point, I could say, well, give me the HTML of that count element. And I'm going to expect that HTML to contain the current count. All right. So let's give this a run. And it fails. So find did not return count. So we're trying to call an HTML method on an empty wrapper. Fair enough. So let's do this. We'll say template.
So let's do this. We'll say template. And I'll just do this all in line for the time being. And let's see. If we're presenting the count, we'll just have a span with a class of count. And the v-text will be bound to the count data property. All right. Let's give it another run. Excellent. We're at green.
Excellent. We're at green. Now one thing, though. If it does present the current count, I do want to make sure that when we increment it, that count that we display is updated. But we'll come back to that in just a second. Why don't we add a new test here for it increments the count when the button is clicked. OK. Well, let's say wrapper.find('mebutton'). And again, you can be as specific as you need to.
Well, let's say wrapper.findMeButton. And again, you can be as specific as you need to. But here I can be fairly generic. And if I want to trigger a click, then we're going to trigger a click. And remember, trigger, when you're reviewing this on your own, you can just review the documentation right here. OK. So simulate that we are clicking on this button. And what we'll see, ideally, is that the count will go from 0 to 1. So we'll do a before and an after here.
And what we'll see, ideally, is that the count will go from 0 to 1. So we'll do a before and an after here. So we'll give this a run. And it should fail. find did not return a button. So you're trying to call trigger on an empty wrapper. All right. Let's add our button down here. And we'll say when you click on it, count will be increased. All right.
And we'll say when you click on it, count will be increased. All right. Let's give it another run. And hopefully we should be at green. And we're not. So expected this string to contain the value 0. Ah, yeah. OK. So this is a good example. So in our case, we are using the exact same wrapper for all of the tests.
So this is a good example. So in our case, we are using the exact same wrapper for all of the tests. So notice here, we triggered a click. So at this point, the count within our VM is set to 1. But now here, we expected everything to be reset. But it's not reset because we did it out here. So here is where we're going to do it each time. And I'll show you two ways to do this. Here's the manual way. So let's give that a run.
Here's the manual way. So let's give that a run. And we should get green. And we do. Or in situations like this, you can, of course, use beforeEach. So I could say beforeEach, I want to set the wrapper to mount the counter. And then we'll define it up here. All right. So before every single test, we will refresh our wrapper. So now I can get rid of that each time.
So before every single test, we will refresh our wrapper. So now I can get rid of that each time. Give it another run. And we're at green. OK. So now we're sure this is working. Let's just make sure that it refreshes the DOM to show that to the user. Trigger a click. And now this should contain 1. So in this case, we're testing the underlying logic.
And now this should contain 1. So in this case, we're testing the underlying logic. And in this case, we're testing what actually is presented to the user. Because the user doesn't care if we update some underlying data property if they don't actually see that, if it's not visible to them. So if we give this a run, we should be at green. And we've now successfully used TDD to drive out our Counter component, as simple as it might be. So in the next episode, let's turn this into a .vue component and figure out how we test that.
So in the next episode, let's turn this into a .vue component and figure out how we test that.
