AngularJS and unit testing: Jasmine, Karma and mocks

I spent some time a while back getting up to speed with unit test approaches with AngularJS, but it’s been a while and I need to retrace my steps to pick it up again.

For (my) future reference, here’s a list of the notes I had before:

To pick this up again, here’s my reading list of some useful articles to review:

AngularJS console errors are links to further details (?!)

I don’t know why I didn’t notice or try this before, but I noticed in the Udemy ‘AngularJS Zero to Hero’ course that the instructor was clicking the links in the console errors. Previously I thought those rather oddly looking random character messages in the console were just not particularly friendly, but now they make more sense.

Maybe this is completely obvious to others, but this is a very neat feature that I had completely not picked up on.  The links are parameterized with details of your specific error, and the error message page in the AngularJS docs gives you more specifics about the error.

For example, if I have a typo in my ng-app:

Clicking on the link in the error message takes you to a detailed page with further details:

Getting Started with AngularJS (pt 4): Form submits and two-way data binding

The trouble with learning something new and then not using it for a while is you tend to forget everything you learned a few weeks back.

So picking up again on learning AngularJS (see my previous posts here), I had completely forgot how to handle form submits using AngularJS.

The key is to use the directive ng-submit=”functionname()” on your form, where functionname() is some function defined in $scope in your controller for this form.

The values in your form are automagically bound to your model in your controller, and you can handle the user action of pressing a submit button to do whatever processing you need.

There’s a great explanation in this article here.

Converting a ngRoute based AngularJS app to Angular ui-router

My AngularJS app I’ve been developing for a while was using ngRoute for it’s routing between views (I put together a simple example for reference on GitHub here). I got to the point where I need more that just single URL based routes to views, I needed to have at least one of the views incorporate other nested views that are part of a wizard set of pages. This is something that’s not supported by default in ngRoute, so I’m taking a look at AngularJS ui-router as an alternative.

AngularUI Router is state based, rather than that URL based.

Here’s my starting point for my app before adding the nested views and converting to ui-router:

[code]
var myApp = angular.module(‘MyApp’, [ "ngRoute", "ngAnimate",
"MyControllers" ]);

myApp.config([ ‘$routeProvider’, function($routeProvider{
$routeProvider.when(‘/’, {
templateUrl : ‘home.html’
}).when(‘/page1’, {
templateUrl : ‘page1/page1.html’,
controller : ‘Page1Controller’
}).when(‘/page2’, {
templateUrl : ‘page2.html’
}).when(‘/page3’, {
templateUrl : ‘page3.html’
}).otherwise({
redirectTo : ‘/’
});
}]);
[/code]

Converted to the state based approach, my routing config now looks like:

[code]
var myApp = angular.module(‘MyApp’, [ "ui.router", "ngAnimate", "MyControllers" ]);

myApp.config(function($stateProvider, $urlRouterProvider) {

$stateProvider
// show home page
.state(‘home’, {
url: ‘/home’,
templateUrl: ‘home.html’
})

//show page2
.state(‘page2’, {
url: ‘/page2’,
templateUrl: ‘page2/page2.html’,
controller: ‘Page2Controller’
})

//show page3
.state(‘page3’, {
url: ‘/page3’,
templateUrl: ‘page3.html’
})

// catch all route
// send users to the home page
$urlRouterProvider.otherwise(‘/home’);
});[/code]

The ng-view from ngRoute is now replaced with the ui-view directive from ui-router:

[code]
<div ng-view></div>
[/code]

becomes:

[code]
<div ui-view></div>
[/code]

My menu links looked like this previously:

[code]
<li><a href="index.html#/home">Home</a></li>
<li><a href="index.html#/page1">Page 1</a></li>
<li><a href="index.html#/page2">Page 2</a></li>
[/code]

 

Instead of using URLs that map to view templates, ui-router uses states and state changes to move between page templates – here’s what the replacement for the above menu links looked like:

[code]
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="page1">Page 1</a></li>
<li><a ui-sref="page2">Page 2</a></li>
[/code]

Right now the routing configuration is really not that much different than before: the ui-router config is slightly different and ui-sref states replaced the links. Where the interesting part is that now you can also support nested views, that look like this in the configuration:

[code]
$stateProvider
// show page2
.state(‘page2’, {
url: ‘/page2’,
templateUrl: ‘page2/page2.html’
})

//show page2 – sub page1
.state(‘page2.subsection1’, {
url: ‘/page2/sub1’,
templateUrl: ‘page2/page2sub1.html’
})

//show page2 – sub page2
.state(‘page2.subsection2’, {
url: ‘/page2/sub2’,
templateUrl: ‘page2/page2sub2.html’
})
[/code]

This is the routing for page2 and two nested views that are nested within the main ui-view (ui-view is the ui-router replacement for ng-view ) with a states of page2.subsection1 and page2.subsection2.

The nested views have corresponding nested states in the routing, identified with a dot notation. Assuming page 2 has a submenu and it’s own ui-view nested view, the submenu would like like this:

[code]
<li><a ui-sref="page2.subsection1">Subsection 1</a></li>
<li><a ui-sref="page2.subsection2">Subsection 2</a></li>
[/code]

With a following ui-view nested view in the page following the Page 2’s submenu:

[code]
<div ui-view></div>
[/code]

… clicking on the submenu items will load the nested view fragments into this nested view.

Full docs for ui-router are here.

I have two working sample apps showing an approach using ngRouter and then the examples above updates to use ng-router:

  • Using ng-route here
  • Using ui-router here