# Testing AngularJS With Protractor and Karma - Part 1

This article details how to test a simple AngularJS application using unit tests and end-to-end (E2E) tests.

• Part 1 - In the first part we’ll look at unit tests, which ensure that small, isolated pieces of code (e.g., a unit) behave as expected (current).
• Part 2 - In part two we’ll address E2E tests, which verify that all the pieces of code (units) fit together by simulating the user experience through browser automation.

Updates: December 3rd, 2016 - bumped dependencies

To accomplish this we will be using Karma v0.12.31 (test runner) and Chai v2.2.0 (assertions) for the unit tests (along with Karma-Mocha) and Protractor v2.0.0 for the E2E tests. This article also uses Angular v1.3.15. Be sure to take note of all dependencies and their versions in the package.json and bower.json files in the repo.

The repo includes the following tags:

## Project Setup

Start by cloning the repo, checkout out the first tag, and then install the dependencies:

Run the app:

Navigate to http://localhost:8888 to view the live app.

Test it out. Once done, kill the server and checkout the second tag:

There should now be a “tests” folder and a few more tasks in the Gulpfile.

Run the unit tests:

They should pass:

Now for the e2e tests:

1. 1st terminal window: webdriver-manager start
2. 2nd terminal window (within the project directory): gulp
3. 3rd terminal window (within the project directory): gulp e2e

They should pass as well:

So, what’s happening here…

## Configuration Files

There are two configuration files in the “tests” folder - one for Karma and the other for Protractor.

### Karma

Karma is a test runner built by the AngularJS team that executes the unit tests and reports the results.

Let’s look the config file, karma.conf.js:

You can also run karma init to be guided through the creation of a config file.

### Protractor

Protractor provides a nice wrapper around WebDriverJS, the JavaScript bindings for Selenium Webdriver, to run tests against an AngularJS application running live in a browser.

Turn your attention to the Protractor config file, protractor.conf.js:

This tells protractor where to find the test files (called specs) and specifies the address that the Selenium server is running on. Simple.

## Unit Tests

We’ll start with unit tests since they are much easier to write, debug, and maintain.

Keep in mind that unit tests, by definition, only test isolated units of code so they rely heavily on mocking fake data. This can add much complexity to your tests and can decrease the effectiveness of the actual tests. For example, if you’re mocking out an HTTP request to a back-end API, then you’re not really testing your application. Instead you’re simulating the request and then using fake JSON data to simulate the response back. The tests may run faster, but they are much less effective.

When starting out, mock out only the most expensive requests and make the actual API call in other situations. Over time you will develop a better sense of which requests should be mocked and which should not.

Finally, if you decide not to mock a request in a specific test, then the test is no longer a unit test since it’s not testing an isolated unit of code. Instead you are testing multiple units, which is an integration test. For simplicity, we will continue to refer to such tests as unit tests.

With that, let’s create some tests, broken up by controller!

### TestOneController

Take a look at the code in the first controller:

What’s happening here? Confirm your answer by running your app and watching what happens. Now, what can/should we test?

1. greeting has an initial value of "Hello, World!", and
2. The changeGreeting function updates greeting.

You probably noticed that we are already testing this in the spec:

What’s happening?

1. The describe block is used to group similar tests.
2. The module, myApp, is loaded, into each test, in the first beforeEach block, which instantiates a clean testing environment.
3. The dependencies are injected, a new scope is created, and the controller is instantiated in the second beforeEach.
4. Each it function is a separate test, which includes a title, in human readable form, and a function with the actual test code.
5. The first test asserts that the initial state of greeting is "Hello, World!".
6. Meanwhile, the second test assets that the changeGreeting() function actually changes the value of greeting.

Make sense?

In most cases, unit tests simply change the scope and assert that the results are what we expected.

In general, when testing controllers, you inject then register the controller with a beforeEach block, along with the $rootScope and then test that the functions within the controller act as expected. Run the tests again to ensure they still pass - gulp unit. What else could we test? How about if newText doesn’t change - e.g., if the user submits the button without entering any text in the input box - then the value of greeting should stay the same. Try writing this on your own, before you look at my answer: Try running this. It should fail. So, we’ve revealed a bug. We could fix this by adding validation to the input box to ensure the end user enters a value or we could update changeGreeting to only update greeting if newText is not undefined. Let’s go with the latter. Save the code, and then run the tests again: Nice! Since controllers are used to bind data to the template (via scope), unit tests are perfect for testing the controller logic - e.g., what happens to the scope as the controller runs - while E2E tests ensure that the template is updated accordingly. ### TestTwoController Start by analyzing the code: What should we test? Take out a pen and paper and write down everything that should be tested. Once done, write the code. Check your code against mine. Be sure to start with the following boilerplate: #### Test 1: The initial value of total #### Test 2: The initial value of items #### Test 3: The add function updates the total and items array when a value is added #### Test 4: The add function does not update the total and items array when an empty value is added #### Run Each test should be straightforward. Run the tests. There should be one failure: Update the code, adding a conditional again: Also update the partial, /app/partials/two.html: Run it again: Success! Did I miss anything? Comment below. ### TestThreeController Again, check out the code in app.js: What can we test here? Perhaps a better question is: What should we test here? Is the above test really necessary? Probably not. But we may need to test it out more in the future if we build out the functionality. Let’s go for it! #### Update app.js: Here we are defined a custom template, modal.tpl.html, to be used for the modal text and then we assigned $scope.modalNumber to 1 as well as function to iterate the number.

Add this template to the “app” folder.

#### Update three.html:

Finally, update the partial:

Run the app to make sure everything works, and then update the test…

#### Test redux

Notice how we’re no longer testing that a modal is present. We’ll test that via the E2E tests.

### TestFourController

Finally, let’s test the AJAX request:

Remember the discussion earlier on mocking HTTP requests? Well, here’s probably a good place to actually use a mocking library since this request hits an external API. To do this, we can use the $httpBackend directive from the angular-mocks library. First, let’s first add the mock.js file found in the repo into a new folder called “mock” within the “tests” folder. This module uses angular.module().value to set a JSON value to use as the fake data. Update the list of files in karma.conf.js so that the the mock file is loaded and served by Karma: Next, add the test: What’s happening? 1. Essentially, here we’re injecting defaultJSON so that when the app tries to make the HTTP request, it triggers $httpBackend, which, in turn, uses the defaultJSON value.
2. Did you notice the underscores surrounding the $httpBackend directive? This is a hack that allows us to use the dependency in multiple tests. You can find more information on this from the official documentation. 3. Finally, we’re using an afterEach block to check that we’re not missing any HTTP requests in our tests via the verifyNoOutstandingExpectation() and verifyNoOutstandingRequest() methods. Again, you can read more about these methods from the Angular docs. Test it out! ### Routes How about the routes, templates, and partials? 1. When the route is loaded, the current property is updated. We then test to ensure that the current controller and template are TestOneController and partials/one.html, respectively. 2. Did you notice that we wrapped the route change inside the $apply callback? Since unit tests don’t run the full Angular app, we had to simulate it by triggering the digest cycle.
3. Curious about WhenGET? Check out the Angular documentation. Take note of ExpectGET as well. Can you re-write the above test to use ExpectGET?

Make sure to run the tests one last time:

## Conclusion

That’s it for unit tests. In the next part, we’ll test the entire application, front to back, using end-to-end (E2E) tests via Protractor.

Checkout the third tag, v3, to view all the completed unit tests: