Software Development Blogs

How to Write Unit Test Cases in AngularJS

When it comes to JavaScript development, the definition of unit testing fully complies with that of Roy Osherove. However, many front-end developers believe it makes no sense as most of logic behind unit testing is a reaction of Document Objective Model (DOM) to both JavaScript code manipulations and the way styles affect it.

Good news is that unit testing in JavaScript does make a lot of sense, as our primary goal is to make sure all abstractions function properly.

Introduction

A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward. If the assumptions turn out to be wrong, the unit test has failed. A “unit” is a method or function.

“The Art of Unit Testing” by Roy Osherove 

Check out a related article:

When it comes to JavaScript, the definition of unit testing fully complies with that of Roy Osherove. However, many front-end developers believe it makes no sense as most of logic behind unit testing is a reaction of Document Objective Model (DOM) to both JavaScript code manipulations and the way styles affect it.

Good news is that unit testing in JavaScript does make a lot of sense, as our primary goal is to make sure all abstractions function properly.

So, once again, unit testing implies checking the working efficiency of a separate piece of code against the anticipated result.

As ES6 update took center stage back in 2015, it became a breakthrough for all developers familiar with OOP, as it brought some OOP functionality to JavaScript. Those who still code in ES5 (what a shame!) should get familiar with JavaScript prototyping and module pattern basics in a functional style. If you still prefer procedural programming (what a shame!), don’t get upset, you’ll make use of JavaScript unit testing as well, as you can basically test whatever you want in JS.

Tooling

Sometimes when I write in Javascript, I think I'm going crazy, I want to scream and turn this table to hell, but i will never know what “this” means...

Anonymous Developer

At the very beginning of unit testing, many developers including myself are faced with a how-to-do-it dilemma, which is reasonable enough. Having gained extensive experience with PHP and C#, I expected to get everything on a platter when it comes to JavaScript testing. Yet, JavaScript isn’t that simple! It requires special approach and treatment. Here are some tools that will help us a great deal! So, setup and configure your NodeJs environment and have some patience. Let’s go!

  1. Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.
  2. Webpack is a project module bundler.
  3. Karma is a runner that helps bring a productive testing environment to developers. The environment being one where you don't have to set up loads of configurations, but rather a place where you can just write the code and get instant feedback from your tests.
  4. Istanbul is yet another JS code coverage tool that computes statement, line, function and branch coverage with module loader hooks to transparently add coverage when running tests.

These will suffice at the initial stage.

So what do I do with this awesome toolset? You use it to configure the environment!

Setting up your test environment

You’re building your own maze, in a way, and you might just get lost in it....

Marijn Haverbeke

Now you can either copy the entire repository that I’ve prepared specifically for this article or follow me step by step. Going forward, I’ll add links to repository files with their explanation.

As I am a big fan of Microsoft’s Typescript, we’ll work with it. Read these guidelines about how to build files and compile code in Typescript.

Package.json is an important part of work with npm, so you can either copy it from my repository or create it with npm init command. Good old NodeJS will show you what lines to fill out and how.

Now you have an empty folder with a versions control file. Copy all of the required dependencies and scripts from here. Run in console npm install (npm i). Now you have the following magic modules in your folder:

  • @types - our analyzer needs it to read and understand Typescript code
  • html-loader for webpack
  • html-webpack-plugin - our webpack needs it to launch html file, connect all builds and use html file for webpack-dev-server
  • istanbul-instrumenter-loader - allows us to use instanbul along with webpack
  • jasmine - our test framework
  • karma - test launcher
  • ts-loader - typescript files loader for webpack
  • typescript
  • webpack
  • webpack-dev-server - plugin that allows for building a server within node environment that tracks any changes in project files.
  • webpack-merge - plugin allowing for unification of webpack setting (since Object.assign isn’t covered in ES5)
  • angular and angular-ui-router
  • Angular-mocks - we need this module to catch modules and use DI in test mode.

Now you’re all set as far as required packages. In order to configure webpack, read the documentation and repeat the path of the sources presented here. Do the same with Karma (documentation, config).

Also pay attention to webpack test configuration where we register istanbul-instrumenter post loader that was described above. You exclude node_modules, spec.ts and test.ts files to prevent application from attempting to determine test coverage at the source file where we’ll actually initialize it as well as test coverage of uploaded modules and unit tests themselves. In Karma configuration you only enter test.ts file.

Now you’re ready to move to the final step. Thanks to awesome webpack polyfills, we have the opportunity to find and connect all of the required application source files and our unit tests. In this particular configuration vendor.ts, test.vendor.ts, and app.ts will be your source files. You can definitely change them in your configuration. Also note that typescript will conflict if your Require is missing Context. To avoid this conflict, copy these custom typings. Once again, we need html.d.ts file to be able to upload html files dynamically within the application in Typescript.

It’s up to you how you setup the application. Just open app.ts file and here you go!

Unit test example

JavaScript’s global scope is like a public toilet. You can’t avoid going in there, but try to limit your contact with surfaces when you do.

Dmitry Baranovsky 

I’ve created this small unit test to test an app’s service quality.

A describe block is located at the beginning of each set of unit tests. Once you launch a unit test, you’ll see that describe names all tests with a phrase from the first argument, while second argument is the entire tests body where each test is wrapped with it block that, just like in describe case, gets its name and body.

beforeEach is one of the most important global functions of jasmin for Angular, as it lets you launch modules falsely before each unit test. For this purpose, locate mock in it as was done in index.spec.ts.

Speaking about DI and Angular mocks, I meant receipt of app’s services. In this case, it’s _AppService_ that’s recorded in AppService variable for access to tests.

Launch

If you’ve done everything described above, you’ll see a beautiful tree-like list comprised of one unit test and a green message “TOTAL: 1 SUCCESS” right after the launch of npm test in console and configuration. A coverage folder will also be created in the project’s root directory. Having opened index.html file, you’ll see a test coverage visualization. Congrats, you’ve just reached the final point of running a unit test in AngularJS.

Are you looking to hire seasoned front-end developers and/or testers for your in-house / offshore software project?
Send us your request!
Denis is our front-end developer. He has 3+ years of hands-on experience in web development (Angular, React) as well as extensive PHP and NodeJS experience.
Intersog does not engage with external agencies for recruitment purposes. Learn more about this here.