Let's develop hybrid mobile apps with Ionic framework II.

I wrote about Ionic Framework in the previous post, concentrated on basic requirements of development, such as how to install ionic and cordova, how to create a blank template and how to build your app. In the current post we start developing a note manager app, focusing on unit tests, developing in a test driven way. Most precisely we will walk round how to set up your framework if you want to use task automation for easing test driven development.

Project management method

In this project we will use Trello. It is free, flexible and really useful tool for managing your projects.

We create 5 tables in the simpleNote board:

  • Backlog: these cards contains features in user stories and acceptance criteria form
  • Sprint backlog: backlog cards being in the given sprint
  • Todo: the tasks that we can hammer out the features with
  • In progress: tasks in progress
  • Done: done tasks

For now we created the following cards in Backlog:

  • Setting up developing environment
  • Create a list of notes (show title)
  • Show details of notes (title, text, tags)
  • Add note
  • Remove note
  • Edit note
  • Filter note by search term
  • Synchronize note data with database

In the project we'll walk through the cards above and realize them.

1. Setting up the developing environment for an ionic app

1.1. Using Ionic Framework

As I mentioned before we will develop this app in Ionic framework. I wrote a blogpost on setting up your environment for an ionic project. I recommend checking out that post if you haven't installed ionic and cordova yet.

1.2. Using Yeoman

We generate the template using Yeoman, especially the Yeoman Ionic Generator:

$ npm install -g generator-ionic

Then scaffold the project:

$ yo ionic simpleNote
  • didn't use Sass with Compass now
  • no additional Cordova plugins than defaults
  • Blank starter template

In Windows you need to install Python 2.7.~, and Visual Studio Express to get the build.

1.3 Project Structure

├── Gruntfile.js            - Configuration of all Grunt tasks  
├── package.json            - Dev dependencies and required Cordova plugins
├── bower.json              - Lists front-end dependencies
├── config.xml              - Global Cordova configuration
├── .gitignore              - Best practices for checking in Cordova apps
├── resources/              - Scaffolded placeholder Icons and Splashscreens
│   ├── ios/
│   ├── android/
├── app/
│   ├── index.html          - Main Ionic app entry point
│   ├── lib/                - Libraries managed by Bower
│   ├── scripts/            - Custom AngularJS Scripts
│   ├── styles/             - Stylesheets
│   ├── templates/          - HTML views
├── platforms/              - Targeted operating systems
├── plugins/                - Native plugins
├── hooks/                  - Cordova lifecycle hooks
├── merges/                 - Platform specific overrides
├── coverage/               - Istanbul reports
├── test/                   - Unit tests
│   ├── spec/
├── www/                    - Copied from app/ to be used by Cordova

Source: ionic-genereator: https://github.com/diegonetto/generator-ionic

1.4. Workflow commands

For all commands check out the Ionic Generator page (but first your Gruntfile.js)

grunt serve

Run a local development server with built in file system watching support integrated with LiveReload so you can develop your Ionic app in a browser. It also does linting your code.

grunt test

Watch for changes and run your tests, using karma, mocha, chai.

1.5. Cleaning up the template

  • app/scripts/app.js: changing the main module name (simpleNote), removing unwanted comments and adding 'use strict'
  • app/index.html: adding title (simpleNote), updating the module name and the header title
  • update the config.xml description and author elements

1.6. Editorconfig

EditorConfig is used to maintain consistent coding styles. There is an .editorconfig file in the project root directory, that defines the main styles.

You have EditorConfig plugins for lots of editors.

As opening a file, EditorConfig plugins look for a file named .editorconfig in the directory of the opened file and in every parent directory. A search for .editorconfig files will stop if the root file path is reached or an .editorconfig file with root=true is found.

The content of .editorconfig file:

# http://editorconfig.org  
root = true

indent_style = space  
indent_size = 2  
end_of_line = lf  
charset = utf-8  
trim_trailing_whitespace = true  
insert_final_newline = true

trim_trailing_whitespace = false

1.7. Setting up test environment

Running grunt test launches Karma testing tool. This grunt task watches *.js files changing in the following libraries (and in their sub-libraries)

  • app/scripts
  • test/mock
  • test/spec

The latter two libraries doesn't exist, so we have to create them. After creating the folders you need rerun grunt test for correct watching.

1.7.1. Create a sample test

Let's create a sample test to see if our testing tool works:

// test/spec/sample.spec.js

'use strict';

describe('Sample test for setting up development framework', function () {  
  it('should be ok', function () {

Let's test a sample angular directive. I recommend installing karma-ng-html2js-preprocessor. As its documentation says

This preprocessor converts HTML files into JS strings and generates Angular modules. These modules, when loaded, puts these HTML files into the $templateCache and therefore Angular won't try to fetch them from the server.

$ npm install karma-ng-html2js-preprocessor --save-dev

We need update our Gruntfile.js's karma task. Add the correct path to files array:

files: [  
  '<%= yeoman.app %>/<%= yeoman.scripts %>/**/*.html': ['ng-html2js']

Add preprocessor to karma task's options:

preprocessors: {  
  '<%= yeoman.app %>/<%= yeoman.scripts %>/**/*.html': ['ng-html2js']
ngHtml2JsPreprocessor: {  
  // strip this from the file path
  stripPrefix: 'app/', // to get the correct path regards building
  // this meand that our temlpates urls will start with 'scripts/'

  // setting this option will create only a single module that contains templates
  // from all the files, so you can load them all with module('templates')
  moduleName: 'templates'

Now we can create our second test in sample.spec.js:

describe('Directive: sample-directive', function () {  
  var $compile;
  var scope;



  inject(function ($injector) {
      $compile = $injector.get('$compile');
      scope = $injector.get('$rootScope').$new();

  it('should get the appropriate content', function () {
    var element = $compile('')(scope);


'); }); });

You may want to check out this repo about testing angularJs directives.

After our test we can write the sample directive:

  • create a sample folder in app/scripts
  • create a file in app/scripts/sample/sample.drv.js
// sample.drv.js

'use strict';

angular.module('simpleNote').directive('sampleDirective', function () {  
  return {
    restrict: 'E',
    templateUrl: 'sample/sample.drv.html'

Finally, create the test template app/scripts/sample/sample.drv.html:


Now we can run grunt test and when we save our .js files the test will run.

1.7.2. Extending test framework with karma-jquery and chai-jquery

If you want to write tests for Angular directives, you need tools for testing DOM elements. This is where karma-jquery and karma-chai-jquery come into play. Let's install them:

$ npm install karma-jquery karma-chai-jquery --save-dev

We need to update the karma task in Gruntfile.js:

options: {  
  frameworks: ['chai-jquery', 'chai', 'jquery-2.1.0', 'mocha'],

Check out the order of frameworks. As of this writing you need to keep this order (from the most specified to the less specified), otherwise you'll get an error.

Let's write a test that uses these frameworks. We'd like to develop a button element with a sample-class css class, and an inner <h1> element:

describe('Directive: sample-directive', function () {  
  var $compile;
  var scope;
  var element;



  beforeEach(inject(function (_$compile_, _$rootScope_) {
    $compile = _$compile_;
    scope = _$rootScope_.$new();
    element = $compile('')(scope);

  it('gets the appropriate content', function () {

  it('should get button element and check its css class', function () {
    var buttons = element.find('button');

And let's update the template:

<button class="sample-class">  

1.7.3. Testing css

If we want to test css we have to instantiate our test element. We need to amend the test file with this line after compiling the element and digesting it:

angular.element(document).find('body').append(element); // for rendering css

Now you can write a test like this:

expect(noteTitle).to.have.css('color','rgb(255, 0, 0)');


In this post we set up a testing framework for developing in ionic framework in test driven way. We used Yeoman and Ionic Generator for scaffolding the project. We cleand up the Ionic blank template and wired up the testing framework, created a sample test for testing an angular directive. We used karma-jquery and karma-chai-jquery for testing classes and css. In a follwing post we will go on developing our ionic app. You can check out the app's repo here.

comments powered by Disqus