Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  • Overview
  • Transcript

1.2 Testing Angular Directives

In this lesson, we’re going to add unit tests for one of the directives in a simple JavaScript app using Sinon, Jasmine and Karma.

Code Snippet

In this snippet, we first create a test element that has our directive applied. In this case it’s a <textarea> with an id attribute, and is associated with a scope. We then use Jasmine’s expect method in conjunction with the toEqual matcher to test that the id attribute in the $scope matches that of the test element.

Related Links

1.Testing Angular Directives
2 lessons, 11:17

Free Lesson

Testing Angular Directives

1.2 Testing Angular Directives

[SOUND]. Hi folks, welcome to Testing Angular Directives. Let's make a start by taking a quick look at the reference application we'll be adding tests for. It's a really basic little app I put together called notes. Which is used to compose and read simple plain text notes. Let's take a moment to walk through the different components inside the repository. The code for the app itself including Angular, is in the app directory. All of the tasks used to develop the app, such as SAS, Clean, Karma and JSHint tasks, are in the grunt-tasks folder. And the grunt file is set up so that any JavaScript file in the grunt-task folder will be loaded by grunt automatically and inserted into the grunt config. The test directory is where we will be adding our tests. The structure of the subdirectories in here, mirrors the structure within the app folder. There's also a coverage directory here, where karma creates a coverage report for our app. And we'll take a look at this in more detail later on. We'll be using Jasmine and Sinon to write our tests because this is a great and very common set up for unit testing in JavaScript. We use comma to run the test from the command line because doing this is much quicker than messing about with the browser. There is all ready a test directory with a subdirectory for unit tests. And then here we have the comma configuration file and all of the test files. The rear test folder also contains a special angular file used for testing purposes, code angular-mox. So let's make a start. First of all we can get rid of the example, Test fil. And now let's create a new directory in here called directives. So let's now add a new test file to the directives directory, that we just created inside the test unit app js folder. The name of this file should match the name of the directive that it's testing but end in .spec.js. We can attest for the enable save on edit directive. So, let's call the new file enablesaveonedit.spec.js. We can start out with a standard iffy in here to keep the code isolated from the global scope, and make sure that the code is running in strict mode. The first thing that we need to do is load the module4oapp, which we can do using Jasmine's before each method. Next we can use Jasmine's describe method to create a new test suite. The first argument is a string describing the test suite. The second argument is a callback which the test for the suite can be added to. There will be some common variables that we'll want to use in most, if not all, of the tests in this suite, so we should define these first. Now, we need to create a scope for the directive and get a reference to the angular compile service, which we'll need in just a moment. We can use the global inject method to do this. And we can just pass in the services that we want to inject into the callback function. We can now create a new scope for the directive to use and store our reference to the compile service. We use the new method of the rootScope service to generate the new scope. The compile services is injected with underscores at the start and end because otherwise we wouldn't be able to save the parameter to a variable of the same name. Angular knows to unwrap these services from within the underscores for us to use. Lastly, we can also create the sinon.sandbox which is useful for mocking and stubbing. We're now ready to start writing some tests. One thing the directive we're testing does is store a reference to the element the directive is attached to, in the parent scope of the directive scope. So we can add our first test for this. We use Jasmine's IT's method to define a single test case. The first argument is a string description of the behavior on the test and the second argument is a callback function that we can use to implement the test. So first let's compile a string of HTML with the directives that we want to test and associate it with the script we created just a minute ago. And we can now make an assertion. We use Jasmin's expect method to test that the ID property of the editor property of the parent scope of the directive scope, matches the ID of the test element that we're creating for the test. So, we can run this test now from the command line. And we just use the grunt test command. So we see that the test passes, and there is a short summary of the coverage in the console window output here. There is also an HTML report generated by grant for us, so let's take a quick look at that. We need to go in to the coverage directory, and if we find the index.html page, run that, we should see the coverage report And let's just drill down into the directive section. And into the directive that we're actually testing. And we can see which lines of the file are exercised. And therefore, which are covered by tests. So, the directive being tested, also adds an event listener for the input event on the element the directive is attached to. And when this event occurs, another property on the parents scope is set. We can also test that this occurs. We need to do a little bit more in this test, than we did in our first test. First of all, let's just create some variables. Instead of just compiling a string of HTML, we need to actually create a new domain element for this test. We use the createElement method to create the text area and then use the setAttribute method to add the directive. Now we can stop the addEventlist method with the element we just created. We use the stub method of the sinon.sandbox to stub the method and provide the object that contains the method as the first argument. And the name of the method we want to stub as the second argument. We also store a reference to these stubbed method which we'll need in just a moment. So, now we're ready to compile the test element. We used the method in the same way we did in the first test. Compiling the method like this, will cause the ad event listener method to be invoked, and since we stopped that, we can have access to the arguments that were passed to the method when the directive was compiled. We can get the handle function from the actual enable save on edit directive and then evoke it ourselves manually. The aux property of the stub is a multidimensional array where the first array is for each time the stubbed method is called. The subarray are the arguments passed to the method that was stubbed. We should now be able to make our assertion. We just need to check that the edited property gets updated correctly. And now, let's run the tests. Again. So both of the tests pass, and if we go back to the coverage HTML report. We find that our directive now has 100% coverage. Fantastic! So in this lesson we saw how to unit test an Angular directive. We learned how to inject any dependencies using the inject method, and how to create a sinon.sandbox for mocking and stubbing. We learned how to write our test suites and test cases using Jasmine describe and it methods. And we saw how to use Angular's compile service to create the directive that we want to test and associate it with a scope object. If you get stuck and you're seeing errors or weird test results in the console, the repository contains a branch called directive-tests, so just check out that branch and take a look at the code in there. I'm Dan Wellman. You can reach me on Twitter using @danwellman. From all of us here at Tuts+, thanks for watching.

Back to the top