3.3 Testing Angular Controllers
Angular Controllers are a challenge to test, due to their tendency to inherit scope and their stateful nature. In this video, we’ll see some tools that we can implement in our tests to let us test our controller.
1.Introduction3 lessons, 07:24
2.Scaffolding a Testable Angular App5 lessons, 46:23
3.Testing Angular Applications5 lessons, 51:44
4.Code Coverage With Istanbul3 lessons, 18:01
5.End-to-End Testing With Protractor4 lessons, 23:27
6.Adding Finishing Touches4 lessons, 23:06
7.Conclusion1 lesson, 04:05
3.3 Testing Angular Controllers
Welcome back, ladies and gentlemen. In this tutorial, we're gonna take our app to the next level. We're going to add a controller to it, and then we're gonna test that controller. We're also gonna update what we see, so the app looks a little more sensible. First, let's go to main.js. Let's add a new controller to our app, the contact controller. And we're going to inject two arguments into our controller, the contact service that we just made. And, scope. This will be very important later. Now, the contact controller is going to do something very simple. It's just going to get the contacts from contact service and add it to the scope. And then, we'll just add to the http.get above, when contact service gets that, to kind of add all the stuff it gets to its list of contacts. So, we're just saying that take all the stuff from res and push it in to the contacts argument that we have. Also, we can't use this the way we did, because the scope of this has changed inside http.get. We'll say var contactService equals this. And now, here we'll just say contactService.push Cool. Now, last time we wrote a test first, so this time, let's implement it first, make sure it works. Go to your index.html for your app. Now, add a div below your Hello World. And make the controller equal to contact controller. And now just put inside an angular statements, contacts. We wanna see a list of contacts in our app. Let's save it and now run gulp regular serve to serve up the app. We've got an error. Looks like we have to stop serving our tests for now, before we serve our full application. Let's stop serving tests and just call gulp serve. So, here we are and it looks like we've got another error. It's saying no access control allow origin as header. Well, we should've expected that because we have enabled cross origin security for our back end. Let's do that now. Open your terminal window. Now type, npm install --save cors. Now, let's go to server.js. And at the top, we'll say, var cors = require cors. And right after var app, we'll say app.use and invoke cors. That's all there it is to it to get cross-origin working. Let's restart our server. It's not working. Looks like we mixed up our http.syntax. The call back shouldn't be the second argument it should go in .then. Let's fix that up. Now, let's restart our file, and now, we're getting the response. We made one more mistake, though. It shouldn't be contactService.push. It should be contactService.contacts.push Did you catch that? That was a secret test. I was testing you. Let's have a look at our app. And we've made one more mistake. We can see here that our data actually isn't the res object. It's the res.data property. Our developer tools are showing us that. So, let's say, contactService.contacts.push res.data.pop. And we'll also say, while res.data 0. I got a good feeling about it this time. Let's give it a shot. All right, so now our controller is displaying a list of our contacts. Let's just clean that up a little bit. We'll just turn this into a repeat. And just show the contact name. So, we're repeating contact and contacts. Let's see how that looks. Looking good. So, now our app's looking okay. So, we've implemented our contact controller, what's next? Well, now we need to implement tests for our contact controller. So, let's go to main.spec.js. Let's create a new describe block parallel with the contactService, and call it the contact controller. Now, let's write a beforeEach block and also modular address book. Now, let's write our inject block. Now, we're gonna need injector and also root scope, so we can pass that right as an argument of the function that goes in inject. Now, when you test an angular controller, what you do is you create a special version of the scope that you actually pass to that controller. So, let's create that. We'll say scope equals root scope.new Now, let's use the injector to get httpBackend and the contact service just like above. We can copy it. And lastly, we're going to get the special service, $controller with injector. So, lets inject that. The controller service creates a controller with a given scope. So, let's write an it statement. Let's say it should store an array of contacts in the scope. So, we'll invoke the controller now with $controller. And it takes an object with arguments and these are the arguments that the function would get. As we know, we're injecting scope and we're also injecting contactService. Now, what's interesting here is the scope property that we've passed the controller has now changed. We can write expectations on it. Above we used expect, so here we'll use a similar assert. We'll say assert scope.contacts. And we'll actually say assert.isarray. With the many different assertion libraries, it's sometimes tricky to get your assertion syntax straight. Don't worry, we'll have many more syntax to learn before the tutorial series is over. So, we'll save this. And now let's run our tests. Looks like we've got an error. $RootScope.new is not a function. Well, that should be $new. Let's fix that up. Save that, and let's try our app again. And it's saying contact list is not a function, got undefined. That's fair, our controller is not called contact list. It's called contact controller. So, let's update that. Save that, and let's check it out again. And it works. So, now we've injected our controller and can run tests on it. In this tutorial, we've learned about the $controller service and how it can be used to inject controllers for testing. We ran an assertion against our controller to make sure that scope.contacts was correct. In this manner, you can test all your controllers.