Initialize Testing Project 0:00So now, let's begin learning the essentials of writing tests specifically for your various Vue components. Now, lots of tools you can use, Mocha, Karma, Ava. I happen to like the latter, so I'm going to pull that in. You'll see that I have a brand new folder here, nothing in it. So let's initialize a package.json file. We have that now. Next, I'm going to pull in Ava, which I've used a number of times at Laracast, so it might be familiar to you. All right, but next, of course, we're working with Vue, so let's grab that in the process. And then finally, open this in Sublime. Okay, so we've pulled in our various dependencies. Why don't we set up a source folder, and we're going to test a component called Notification. So we'll start with a regular component, and then we will review Vue files. So let's just export an empty object for the time being. Okay, next, I'm going to set up a Write First Component Test 0:44So we'll start with a regular component, and then we will review Vue files. So let's just export an empty object for the time being. Okay, next, I'm going to set up a test folder specifically for our Notification, and then we will import Ava. Okay, so we could say test that it renders a Notification, something like this. Now, I think you're going to find that in many ways, it's very, very simple to test your Vue components, almost as simple as creating an object and then asserting what exists on it. So let's do this. We're going to use Vue, of course, so I will pull that in. And now, we're testing our Notification, so we'll pull that in. So go back to the home directory, into source, and we are testing Notification. So yeah, before we even get started writing the test, of course, if we want to assert that a particular piece of data exists on it, message, hello world, yeah, of course, we canSo yeah, before we even get started writing the test, of course, if we want to assert that a particular piece of data exists on it, message, hello world, yeah, of course, we can grab that right off of the data method. So t.is, and we're going to say Notification.data.message, and we expect that to say hello world. Okay, let's run our test. Now, this will be in your node modules bin, and you want the Ava executable, or you'll see for the rest of this video, I'm just going to call Ava, and it will automatically add the path. But yeah, it's failing right off the bat, and if we scroll up, we see export default. Now, the issue is, Ava allows us to use the ECMAScript 2017 syntax in all of your tests, but it's not going to be applied to any other source files that you import. So in this case, I want to pull in Notification to test so it doesn't recognize this. It sounds like we'll need to manually transpile this on Enable Babel Transpilation 2:15applied to any other source files that you import. So in this case, I want to pull in Notification to test so it doesn't recognize this. It sounds like we'll need to manually transpile this on the fly. Now, we can do that with Babel using the Babel register plugin, like this. Babel register, I'll save that to my dev dependencies list, and then I'm going to tell Ava to use this. Let's go to package.json, and then right here, we can say for our Ava specific configuration, I want to require Babel register. And again, this will allow us to automatically transpile on the fly. But next, if we run it, it's still not going to work. So let's give it a shot, and yeah, we're still going to get the exact same thing. And that's because we want to specify that we want Babel support, yes, in our tests, but also for anything else that we import. So let's set up our Babel config here, or we could also, of course, set up a Babel RCwe want Babel support, yes, in our tests, but also for anything else that we import. So let's set up our Babel config here, or we could also, of course, set up a Babel RC in the project root. Either one works. Anyways, we'll be specific that we want ES2015 compilation. Okay, so that should take care of our setup. Let's give it a run, and yeah, we are getting green now. So if we were to change this at all, of course, it's going to fail and point out where the error is. Okay, great. So with all that setup out of the way, yeah, how do we end up testing more significant things? Like, yes, we can test that data is set here, but what if we want to test that the compiled template ends up looking a certain way? Okay, let's try that out. Let's imagine that we have a template here, and we're just going to spit out the message to start. Now, adding this alone, I think, is going to make it fail. Let me show you. Let's come back and sayimagine that we have a template here, and we're just going to spit out the message to start. Now, adding this alone, I think, is going to make it fail. Let me show you. Let's come back and say we're going to build up a new view instance using the notification object that we're exporting here, and then let's call mount to mount it to the page. But yeah, this can get tricky too, because it's going to assume globals like the window and the document object. So if we run this, let's give it a shot, you are using the runtime only build a view where the template option is not available. And we've already reviewed a lot of this at the beginning of the series. We learned that there were two different builds. There is the runtime only build, which is what we have, and that doesn't allow us to use the template property. And there's also the standalone build. Now, we learned when we were setting up Webpack how to be explicit that we want the Use Standalone Vue Build 4:22we have, and that doesn't allow us to use the template property. And there's also the standalone build. Now, we learned when we were setting up Webpack how to be explicit that we want the standalone build. But in our particular case, how do we fix this? Some test frameworks give you the option of running everything through Webpack. In our case, let's just reference the specific standalone build file. Now, you want to make sure you don't do this in production. And that's because you could end up in situations where two different installs of view takes place. But I think when it comes to running a test like this, it doesn't really matter. So we should be okay. Let's go ahead and run it again now. We should be using the standalone build. But now, it's squawking at something else. So yeah, you can see when you're trying to get set up, there's a number of little things you need to know and need to research. So hopefully, Mock Browser Environment 5:03it's squawking at something else. So yeah, you can see when you're trying to get set up, there's a number of little things you need to know and need to research. So hopefully, this video will guide you through those steps. Now, in this case, it's getting mad because it doesn't know what document is. Remember, we're not running this in a browser. We're doing it through Node. So document, as a result, is not defined, and our view code is blowing up. Okay, well, it sounds like we need to mock a browser environment. We can do that with a package called browserenv. So let's save that. And then next, if we go back to package.json, we're going to tell Ava to automatically require a little helper file for our tests. Maybe test. We'll create a helpers folder, and we'll call this setup browserenv.js. So we want to make sure that Ava automatically requires this for our tests. So we'll set that up. Helpers setup browserenv.js. And now, the onlyfolder, and we'll call this setup browserenv.js. So we want to make sure that Ava automatically requires this for our tests. So we'll set that up. Helpers setup browserenv.js. And now, the only thing we have to do here is import it, like so. And then finally, call the function that's returned or imported. And that should do it for us. So now, we are mocking a browser environment and mocking the document and window objects and such. So it does pass like we'd expect. Okay, so now, we can actually focus on our test. For example, we could say create an invariable. And if I were to console.log, grab the root element and its text content, this will give us the text alone minus the markup for the render template. And sure enough, we see Hello World. So if we take a look at that, yep, that's exactly what we would want. Or of course, we could say, give me the inner HTML. And in this case, we'll get the same thing. But if we did have like an h1 Test Props and Rendering 6:39take a look at that, yep, that's exactly what we would want. Or of course, we could say, give me the inner HTML. And in this case, we'll get the same thing. But if we did have like an h1 here, then naturally, you'll see the h1 tag as well. So this alone will take you a long way. But another thing you might want to do is test properties. So for example, for a notification, it stands to reason that you will accept a property for the notification message, right? And that way, you might say something like notification message equals, thanks so much, or something like that. So if we want to do that, how can we write a test for this? Okay, well, let's try it out. We know that ultimately, we want to check to see if the n.l.text content is equal to foobar. And of course, it's not going to at this point, right? Because we haven't passed that in as a property. So if we run it, it should in fact fail. And itn.l.text content is equal to foobar. And of course, it's not going to at this point, right? Because we haven't passed that in as a property. So if we run it, it should in fact fail. And it does. So now, I bet you may not know how to pass properties through to the constructor, you know how to do it in HTML form. But what if you are doing up the component itself? Well, we can do that through the props data option in the constructor, like this. Let's extend our notification component. And we'll call it n or constructor or anything we want. That way, I can say, create a new instance of our notification. But then I'm going to pass through the props data option. And this is where we can specify any properties that we want to send through, in this case, foobar. So we can save that as our VM. And then we can update this like so. And now of course, we need to mount it explicitly. So let's give it a run. And I think at this point,through, in this case, foobar. So we can save that as our VM. And then we can update this like so. And now of course, we need to mount it explicitly. So let's give it a run. And I think at this point, it should return green, and it does. Alright, so that can be a little confusing at first, but hopefully it makes sense. We are extending view with our notification. And that way, it can be its own constructor. And then we new up that view instance, and we explicitly pass through any properties that it requires. So in this case, message is what we want to send through. Next, we mount and compile everything down. And finally, we assert that the text content is equal to foobar. And as a result, we do get green. So now imagine you wanted to do one more, maybe it capitalizes the notification message. So test that it capitalizes the message. And this could even be part of your first test. But just to give you a couple examples.maybe it capitalizes the notification message. So test that it capitalizes the message. And this could even be part of your first test. But just to give you a couple examples. Well, once again, you would set up your VM. And of course, you could even extract this to a little helper function to clean up the code a bit. But anyways, this time, if we give it foobar, ultimately, we expect the compiled text content to equal foobar. And we would have to do this one as well, which makes the test a little redundant. But anyways, we'll remove it in just a minute. If we run it, sure enough, it fails, because this is what we got. But foobar is what we expected. So now at this point, we could maybe set up a filter here, or a computed property would be just as fine. Anyways, we'll say capitalize that will accept the message,we could maybe set up a filter here, or a computed property would be just as fine. Anyways, we'll say capitalize that will accept the message, and then it will simply return to uppercase. Okay, that should now return green. And it does. And like I said, it's a little redundant, since this would automatically be included in our first test. So we could keep it just like this, unless you want to be explicit that capitalization is a feature that should be documented, which it wouldn't be in this case. Now though, it does stand to reason that in real life, you'll have a number of tests here. And you're probably going to redo this over and over. So you have a couple options. One, you could just throw this in a before each block, or you could extract it to a little helper function so that you can build it up on the fly.So you have a couple options. One, you could just throw this in a before each block, or you could extract it to a little helper function so that you can build it up on the fly. If you wanted to do the before each, you could just say before each, maybe ultimately, we want our view model, our VM. And then we could grab this, like so. So before every single test, extend notification, create a new instance, pass through some properties, and then compile and mount it. And we're going to save that to VM. So now at the point that this test runs, the VM variable will be populated. So if we run it again, we should still get green. But yeah, this will make your future tests a little bit easier, because you can immediately assume a VM instance to work with, a fresh VM instance to work with. Now, in closing, yeah, this exact same workflow is going to be true for testing data properties,because you can immediately assume a VM instance to work with, a fresh VM instance to work with. Now, in closing, yeah, this exact same workflow is going to be true for testing data properties, or the text content, the rendered text content itself. The same would be true for computed properties. So for example, what if this was a computed prop instead? And let's call this notification. Now, we can explicitly reference the message. And then up here, we could update this to notification. Okay, so if we come back, we shouldn't have to change any of our test code, because we weren't relying on the implementation details at all. We were just saying compile it down. And we expect this to say foobar. And it does. But now, yeah, if you do, for some reason, want to test the computed property itself, then you can totally do that. You could say test that it computes the notification. And then we'll say I expect to equal the VM dot notification.want to test the computed property itself, then you can totally do that. You could say test that it computes the notification. And then we'll say I expect to equal the VM dot notification. And that should be foobar. All right, so let's run that. And I'm sure we'll get green. And we do. Okay, so in closing, we're of course going to talk about this quite a bit more and some of the various things you'll need to know, how you can stub or mock various imports and things like that. But in closing, I'll put this up on GitHub. But the things you need to remember is that one, I happen to like AVA, but you can use any test framework that you want. So here, we're specifying our AVA specific configuration. And in our case, we want to transpile on the fly. And that's what allows us to use things like this, where we can import ECMAScript 2015 code. Next, if we switch back, we also wanted to mock a browser environment. So we did npm install browserenv. And then we setallows us to use things like this, where we can import ECMAScript 2015 code. Next, if we switch back, we also wanted to mock a browser environment. So we did npm install browserenv. And then we set up its instantiation like so. And then back in package.json, we told AVA to require that file and process it. And that's what basically mocks out the document object. And it allows us to work with it. Finally, we have our Babel config. This could be in a .babelrc file in your project root, or you could declare it here. And that'll do it.