unit-testing angularJS controllers in a non-trivial environment

I just released a new patch version of my angularJS sekeleton project ngStart. It now contains a sample unit test for a controller.

There are many examples out there how to unit test an angularJS controller. Basically you have to create a new controller scope yourself and tell angularJS to create a new scope instance for a given controller. This looks usually like this (as a jasmine test):

describe("the controller", function () {
	var contactController, scope;
	beforeEach(function () {
		inject(function ($rootScope, $controller) {
			scope = $rootScope.$new();
			contactController = $controller("contactController", {$scope: scope});

	it("should be something", function () {

Note: this code assumes that the controller was registered in the production code via a call to angular.controller like this: angular.controller(“contactController”, function($scope){…}

The catches in my ngStart project are, that

  • its a requireJS environment and
  • that the controller is not registered by name as its usually done in simple projects, but the controller is defined inside a route definition without an explicit name. The controller is only valid for the given route. As far as I know, you can’t access it via a name anywhere outside.

The route definition looks like this:

define(['angular', 'ContactController'], function (angular, ContactController) {

	var contact = angular.module("contact", []);

	contact.config(["$routeProvider", function($routeProvider) {
		$routeProvider.when('/contact/', {
			templateUrl: 'contact.html',
			controller: ContactController

	return contact;


How do you test the controller now in a unit test if you can’t access it via name?


As we can load the controller definition with requireJS (aka its function representation) you can give the $controller function this controller function directly. You don’t have to provide a string which angularJS uses to look for a registered function like its done with a call to angular.controller(“name”, controllerFunction).

The rest is the standard behaviour like above:

define(["contact/ContactController"], function(ContactController) {
	describe("the controller", function () {
		var contactController, scope;

		beforeEach(function () {
			inject(function ($rootScope, $controller) {
				scope = $rootScope.$new();
				contactController = $controller(ContactController, {$scope: scope});

		it("should be something", function () {

Frontend optimizations for HTML5 web apps

I did a presentation in front of some colleagues some time ago and it was then when I realized how successful our frontend optimizations really are.

Our mobile web app which is running with angularJS and jQuery Mobile is loading over 1.6MB in more than 50 HTTP requests in local development mode. Only the laziest developers would give THAT to their customers.

After all optimizations done during grunt build, customers need to load only 250kB in 13 HTTP requests on their first visit. Although the number of HTTP seems a bit high, this is a appcache app and it contains all ressources ever needed for the app, including HTML files and all images, fonts and styles.

Because of appcache caching a returning visitor needs to only load 3kB for the whole app in 1 HTTP request. Thats, right. 3 kB! Thats the initial payload for the JSON data that the app loads from a REST service.

3kB instead of 1.6MB. How is that possible?

Here is a list of most optimzations that is done during grunt build:

  • all javascript files are concatenated and optimized with requireJS optimizer into one single javscript file. This single steps is gaining by far the most in size and HTP requests as we structure our code in small and meaningful modules/files. Side effect: optimizer creates javascript source maps so debugging is possible even in minized code on production.
  • all css files are concatenated and optimized into one single css file
  • all images (icons) are written as base64 into the css file as data URIs. Though the images are around 20% bigger, the browser saves heavily on fewer HTTP request which outweighs the bigger data by far!
  • an appcache manifest file is created during build and referenced inside the HTML files. The browser can then load the whole app during first visit and needs only to load dynamic data on subsequent visits.

That is only a part of the build process. What I learned during developing this build system, was the foundation what I did later in my angularJS skeleton project: ngStart

Grunt is a fabulous build tool and there is already a plugin for most, if not all frontend optimizations. You only have to configure them.

AddToHomescreen: pin web apps to the homescreen

add2home-screen1Apples iOS supports since ages a meta tag called “apple-mobile-web-app-capable”, with which a developer can tell iOS that web site doesn’t need navigation and url bars and is handling that itself. So, if this meta tag is set and a web site is called from the iOS homescreen it looks like a normal app for the normal visitor.

The problem is to tell its visitors that this behaviour is supported as most users don’t know that there is even the possibility to add websites to their homescreens.

But like they say – there is an app for that – there is a library for that: Matteo Spinelli has developed the wonderful tool AddToHomescreen. If you embed the code inside your web app, a small tooltip will be visible after page load which asks the user to add the site to their homescreen. The library checks itself that its only visible on compatible iOS devices and changes the little icon what the user should tap on automatically (its different on iPads and iPhones). Additionally you can configure some options like if and how long the tooltip stays or how long the tooltip remembers that the user has closed the tooltip and will not see it again.

After optimizing and deleting not-needed languages its payload is only 6 kB.

Attention if you are using requireJS

AddToHomeScreen uses the onload event to init itself by default, but that event is already gone when loading it via requireJS … at least when using it together with r.js optimizer (which you should!). But there is a (advanced) config option for this:

window.addToHomeConfig = {hookOnload: false}

If this option is set, the library inits itself as soon as its loaded and doesn’t wait for the (already gone) load event.

jQuery Mobile: display listviews in a grid

Recently we had the requirement in our mobile web app which is using jQuery mobile to use a two-column grid view. Inside the columns a listview should display some data (data-role=listview). Out of the box that doesn’t look good with jQuery Mobile 1.2 as margins and paddings of the containers outside the listviews are messed up.

2 Listviews - falsches Margins und Paddings

But its surpringly easy to alter the paddings and margins so that it looks as expcted when displaying two listviews next to each other:

		<div data-role="content" style="padding: 0;">

			<div class="ui-grid-a" style="padding: 15px;" >
				<div class="ui-block-a">
					<ul data-role="listview" data-theme="e">
						<li data-role="fieldcontain"><a>Eins</a></li>
						<li data-role="fieldcontain"><a>Zwei</a></li>
						<li data-role="fieldcontain"><a>Drei</a></li>

				<div class="ui-block-b">
					<ul data-role="listview" data-filter="true">
						<li data-role="fieldcontain"><a>Eins</a></li>
						<li data-role="fieldcontain"><a>Zwei</a></li>
						<li data-role="fieldcontain"><a>Drei</a></li>

All you need to do is to set the padding of the content div to 0 and add the now missing padding to the first grid container (“ui-block-a”.

2 Listviews - korrekte Margins und Paddings

And done.

Appcache Manifest erstellen und in einer angularJS App integrieren

Wer eine ausgewachsene App entwickelt, die aus rein statischen Dateien (*js, *.css, *.html) besteht und die dynamischen Daten ausschließlich über einen REST-Server nachlädt, sollte sich in jedem Fall mal mit dem HTML5 Appcache beschäftigen. In so einem Fall kann man die (z.B. bei alistapart etwas übertriebenen beschriebenen) Nachteile nämlich ruhig ignorieren.

Der Vorteil für den Nutzer die kompletten statischen Daten immer sofort auf dem Gerät parat zu haben und außer dem REST-Request überhaupt keine HTTP-Requests zum Laden der App zu benötigen, ist speziell für mobile Anwendungen ein ungeheurer Performancegewinn.

Wie ein Appcache-Manifest aufgebaut ist, wird z.B. auf HTML5 Rocks beschrieben.

Nun will man die Datei aber natürlich möglichst automatisch erstellen. Wir haben uns – da wir grunt als Buildtool verwenden – für grunt-contrib-manifest entschieden. Für mich ein weiterer Grund sehr zufrieden mit unserer Entscheidung zu sein, grunt zu verwenden. Es gibt für praktisch alle Anforderungen im Bereich Webentwicklung bzw. Frontend-Entwicklung bereits ein Plugin. [highlight1]”Da gibts ein Plugin für”[/highlight1] statt “Da gibt’s eine App für” sozusagen 🙂

Die Konfiguration ist simpel und selbsterklärend, da muss ich nicht weiter drauf eingehen. Und funktioniert bisher problemlos.

Was etwas mehr nachdenken erfordert hat, war, wie man auf das Event “updateready” reagieren soll, das der Browser erzeugt, wenn er die Dateien im Appcache vollständig aktualisiert hat und die neue Version der App geladen werden muss. Dass eine nicht wegklickbare Info-Box erscheinen sollte, die der Nutzer nur mit einem Klick auf “Neu laden” schließen können sollte, war recht schnell klar. Das eigentliche “Problem” war, das solche DOM-Manipulationen nicht in einen angularJS Controller gehören. Schließlich sollen die auf jeden Fall auch ohne DOM unittest-bar bleiben.

Also war eine Direktive notwendig.

Wir haben es momentan mit dieser Direktive gelöst. Das Popup benutzt jQuery Mobile.

function AppcacheUpdated() {
	var elementScope;

	window.applicationCache.addEventListener('updateready', function() {
		if (window.applicationCache.status === window.applicationCache.UPDATEREADY) {
			elementScope.show = true;
			if (!elementScope.$$phase) {

	return {
		template:" <div data-role='popup' class='appcachePopup ui-content' data-theme='e'>" +
			" <p><translate>Neue Version</translate></p><br />" +
			"<a ng-click='reload()' data-role='button'>Neu laden</a> </div>",
		controller: function ($scope){
			$scope.$watch("show", function(value) {
				if (value) {
					$(".appcachePopup").popup("open", {dismissible:false});

			$scope.reload = function() {

			$scope.show = false;
		link: function (scope) {
			elementScope = scope;

angularModule.directive("appcacheUpdated", AppcacheUpdated);

Die Direktive zu verwenden ist simpel, einfach in jede HTML-Seite, auf der sie verwendet werden soll, irgendwo einbauen:


Das ist so ziemlich meine erste Direktive. Mal schauen ob sie auch weiterhin so funktionieren wird, wie sie es momentan tut. Oder ob es dort noch Fallen gibt, über die ich bisher nicht gestolpert bin. Vor allem bin ich mir momentan noch etwas unsicher, ob es günstig ist, sich den “element.$scope” in einer Closure zu merken.

Die Komplexität um angularJS-Direktiven zu schreiben, ist aber in jedem Fall deutlich geringer als JSF-Komponenten zu schreiben. Ich bin immer mehr der Überzeugung, dass JSF für mich keine Zukunft mehr hat, wenn es um Frontend-Entwicklung geht. Der Ansatz auf dem Server das HTML zu rendern und den Client darstellen zu lassen, hat sich in den letzten Jahren einfach überlebt.

Die Entwicklung mit angularJS ist erstens deutlich einfacher und zweitens … macht es einfach Spass. 🙂

Javascript in der IDE debuggen mit Webstorm

Gleich vorweg, das Video ist nicht von mir und hat auch keinen Ton.

Nichtsdestotrotz sieht man dort sehr schön wie man mit der aktuellen Testacular Version in der aktuellen Webstorm Version Javacscript direkt in der besten Javascript IDE debuggen kann, die es momentan gibt: Webstorm.

Das ist nicht übertrieben. Die Jungs von Jetbrains sind momentan absolut führend in der Integration von Javascript in einer IDE. Wer keinen reinen Editor wie Sublime verwenden möchte sondern eine ausgewachsene sinnvoll vorkonfigurierte IDE, dem bleibt nur Webstorm.

Trotz des Videos hier nochmal die wichtigsten Konfigurationsfenster zusammengefasst. Es wird eine laufende Testacular Installation vorausgesetzt, wie das z.B. geht habe ich z.B. in meinem Artikel erklärt.

Die gesamte Konfiguration ist in 2-3 Schritten erledigt und baut auf die “Run/Debug Configurations” auf. Die sind über die Icon-Leiste erreichbar (siehe Bild).

Dort kann man zwei oder drei Konfigurationen anlegen. Drei benötigt man, wenn die Tests nicht automatisch nach jedem Speichern laufen sollen, sondern auf Knopfdruck.

Die erste Konfiguration ist der Server (siehe Bild). In dem Menü muss man über das + eine neue node.js Konfiguration anlegen. Die dort einzutragenden Werte seht ihr auf dem Bild. Die Pfade sind entsprechend anzupassen, auf dem Bild sind die Pfade für einen Mac zu sehen.

Die zweite (optional) anzulegende Konfiguration, ist die manuelle Ausführung der Tests, wenn der Server nicht automatisch loslegen soll (abhängig von der Konfiguration in der testacular.conf.js). Auch hier muss wieder eine node.js Konfiguration angelegt werden und als Startparameter für Testacular gibt man diesmal nur “run” an. Das wars schon.

Jetzt kann man bereits die Tests ausführen und man sieht die Ergebnisse in der Konsole. Wenn Fehler aufgetreten sind, sieht man dort die Dateien, die alle anklickbar sind sodass man direkt an der betreffenden Codestelle landet.

Wenn man nun noch debuggen möchte, fügt man wieder über das + und “Javascript Debug” eine “Remote” Konfiguration hinzu. Die genaue Konfiguration ist wieder auf dem Bild sichtbar. Spannend ist hier nur die Wahl des Browsers (aktuell Chrome oder Firefox) und die Remote URL. Im Fall von Testacular und dem Standardport ist das [highlight1]http://localhost:9876/base[/highlight1]

Das wars. Man kann den vorher angelegten Server nun nicht mehr nur starten, sondern über das Debug-Icon auch debuggen. Das startet den gewählten Browser und stellt eine Verbindung her. Das debugging sollte direkt funktionieren, das genaue Vorgehen sieht man in obigem Video.

[image title=”Run/Debug Configurations” caption=”Run/Debug Configurations”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/editconfigurations.png[/image]
[image title=”Testacular Server starten” caption=”Testacular Server starten”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/server.png[/image]
[image title=”Testacular Tests starten” caption=”Testacular Tests starten”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/run.png[/image]
[image title=”Testacular Debug Konfiguration” caption=”Testacular Debug Konfiguration”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/debug.png[/image]
[image title=”Testacular Server gestartet” caption=”Testacular Server gestartet”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/serverstarted.png[/image]

angularJS App mit requireJS und Testacular testen

Wie schon ein paar mal geschrieben, bin ich schwer begeistert wie einfach es mit angularJS ist, Web Apps mit Javascript zu entwickeln. Vielleicht merkt man das auch an der ein oder anderen Stelle 🙂

Aber egal, wie einfach das Entwickeln ist, wir machen alle Fehler. Deshalb muss auch angularJS-Code getestet werden, mindestens Unit-Tests besser noch mit End-2-End-Tests.

[highlight1]Aber moment mal, Javascript-Code und Unit-Tests? Geht das überhaupt? [/highlight1]

Aber klar! Schon lang gibt es diverse Test-Frameworks für Javascript. jQuery benutzt z.B. qunit, die AngularJS-Entwickler bevorzugen Jasmine.

Als Skriptsprache, die beim Kunden im Browser ausgeführt wird, ist es bei Javascript-Tests natürlich wichtig, sie dort auszuführen wo sie laufen: im Browser. Und das ist ohne spezialisierte Tools äußerst aufwändig.

Als sogenannter Test Runner, gibt es seit einigen Jahren jsTestDriver (von Google), das Unit-Tests entgegennimmt und dafür sorgt, sie auf angeschlossenen Browsern auszuführen. Leider habe ich keine gute Erfahrung damit gemacht, da es allgemein recht instabil läuft, mehrfach täglich neugestartet werden muss und nach Neustart das automatische Wiederverbinden mit den Browsern eher hakelig ist. Außerdem scheint die Weiterentwicklung auch eher eingeschlafen zu sein.

Die AngularJS-Entwickler haben sich deshalb entschlossen, einen eigenen Test Runner zu entwickeln. [highlight1]Testacular[/highlight1].

Testacular ist kein Testframework, sondern wirklich nur der Test Runner. Man schreibt die Unit-Tests also z.B. als Jasmine-Tests und führt sie mit Testacular in Chrome oder Firefox oder Safari oder auch in PhantomJS (Headless Browser) aus.

Da wir AngularJS u.a. auch mit requireJS benutzen, ist es allerdings nicht ganz einfach, als Anfänger zu verstehen, wie man Testacular konfigurieren muss, damit requireJS den Produktions- und Testcode asynchron nachladen kann und erst danach Testacular loslegt um die Tests auszuführen.

Standardmässig liefert Testacular nämlich eine Webseite an den Browser aus, in der alle referenzierten *.js-Dateien automatisch als <script>-Tag referenziert werden, damit der Browser sie lädt. Nach Laden der Seite fängt dann Testacular an, die Tests auszuführen. Mit requireJS darf Testacular allerdings die Skripte eben gerade nicht mittels <script>-Tag laden, sondern dies übernimmt require.js. Nur die main.js um requireJS zu laden und zu konfigurieren, darf so eingebunden werden.

Als Startpunkt für meine Konfiguration mit requireJS habe ich einen Artikel bei Jake Trent gefunden, der sich genau diesem Problem widmet. Im Gegensatz zu diesem Artikel kann ich aber sagen, dass die komplette requireJS-Konfiguration wie man sie im Produktionsbetrieb gewohnt ist, auch für Testacular funktioniert. Testacular bindet mit meiner Konfiguration nur noch Jasmine, requireJS und die main-test.js ein. Alles andere lädt requireJS nach.

Dies erreicht man mit folgender Konfiguration der Dateien:

files = [
	{pattern:'src/main/external-libs/angular-1.0.3.js', included:false},
	{pattern:'src/test/external-libs/angular-mocks-1.0.3.js', included:false},
	{pattern:'src/main/js/**/*', included:false}, //Produktionscode
	{pattern:'src/test/unit/**/*.js', included:false}, //Testcode
	'src/test/main-test.js' //requireJS-Konfiguration

Entscheidend ist hier das [hightlight1]included:false[/highlight], was dafür sorgt, dass die Dateien zwar verfügbar sind, aber nicht per <script> automatisch ausgeliefert werden. Der Rest der Konfiguration kann so aus dem verlinkten Artikel übernommen werden.

In der main-test.js Datei muss man nun dafür sorgen, dass die eigene Anwendung geladen wird (die ja sowieso schon aus require-Module bestehen sollte), die Testklassen geladen werden (das müssen nun auch alles require-Module sein, siehe Artikel) und wenn das alles geladen ist, muss Testacular mitgeteilt werden, dass es nun loslegen kann. Meine main-test.js sieht wie folgt aus:

(function (window, require) {
	"use strict";
	var file, requireModules;
	requireModules = [];

	//aus den von Testaular bereitgestellten Dateien alle *Test-Dateien raussuchen und Pfad anpassen, damit requireJS
	//was damit anfangen kann
	for (file in window.__testacular__.files) {
		if (window.__testacular__.files.hasOwnProperty(file)) {
			if (file.substring(file.length - 7, file.length) === 'Test.js') {
				requireModules.push("../.." + file.substring(9, file.length - 3));

	// unsere eigene Anwendung inkl. Abhängigkeiten laden

	//angular Mocks laden

		// "/base" ist die URL von der Testacular alle Dateien ausliefert,
		// "src/main/js" ist due Base-URL aller Module die nicht Test sind
			'angular':{ exports:'angular' },
			'mocks':{ deps:['angular'], exports:'mocks' }
	}, requireModules, function () {
		//erst hier wird Testacular tatsächlich (manuell) gestartet
	}, function (err) {
		//hier kommt die Fehlerbehandlung hin
}(window, require));

Über den Zugriff auf [highlight1]window.__testacular__.files[/highlight1] hole ich mir alle Testdateien und bastele daraus die korrekt benamten require-Module. Dann wird noch die eigentliche Anwendung und Angular hinzugefügt. Wenn requireJS alles geladen hat, wird dann über [highlight1]window.__testacular__.start();[/highlight1] Testacular gestartet.

Wenn man das einmal begriffen hat, ist es eigentlich recht einfach. Aber das ist ja häufig so 🙂 Testacular ohne requireJS zu konfigurieren, ist auch deutlich einfacher.

Wenn es dann einmal läuft, hat man aber einen hervorragenden Testrunner, den man dann auch in Webstorm (Javascript IDE) integrieren kann, um direkt in der IDE, die Unit Tests starten zu können und – besonders beeindruckend – auch direkt in der IDE debuggen kann.

Aber dazu ein anderes mal mehr Details.

iOS 6 cached POST-Requests … und wie man das verhindert

Letzte Woche haben wir uns ziemlich gewundert als uns aufgefallen ist, dass unsere iPhones mit iOS 6 nicht mehr mit unserer Web App funktioniert haben. Da sind wir wohl über ein “Feature” von iOS 6 gestolpert, das ziemlich viel Aufsehen in der Entwicklergemeinde verursacht hat, als es veröffentlicht wurde.

Um dem Benutzer noch das letzte bisschen Performance vorzugaukeln, hat sich Apple nämlich entschieden, POST-Requests (z.B. per Ajax) im Browser zu cachen, wenn dies nicht explizit vom Server deaktiviert wird.

Apple steht damit ziemlich alleine … alle HTTP-Clients machen das aus gutem Grund nicht. In der “Restful HTTP”-Philosophie sind POST-Requests per Definition nicht idempotent, d.h. das Ergebnis mehrerer identischer POST-Requests an dieselbe URL selbst mit derselben Payload haben NICHT immer dasselbe Ergebnis. In SQL entspricht ein POST-Requests einem INSERT. Es werden also im Regelfall für jeden Request neue Datensätze angelegt.

POST-Requests zu cachen verbietet sich also, ausser der Serverbetreiber aktiviert es explizit mittels der üblichen HTTP-Header zum Caching.

Zwar kann ich verstehen, wenn Apple so viele HTTP-Requests sparen möchte wie es geht, damit der Benutzer möglichst performante Webseiten präsentiert bekommt, aber hier übertreiben sie ganz eindeutig.

Wenn man das Problem einmal gefunden und identifiziert hat, lässt es sich zum Glück sehr schnell deaktivieren. Wir haben im Server nun einen ServletFilter (Java) implementiert, der in alle Responses von POST-Requests zur REST-Schnittstelle den HTTP-Header [highlight1]Cache-Control: no-cache[/highlight1] einbaut.

Wenn man über den Server keine Kontrolle hat und das nicht einbauen kann, kann man als Client-Entwickler auch eine zufällige Komponente in die URL einbauen, sodass die URL immer unterschiedlich ist und iOS6 die Requests zwar cached, aber durch die wechselnde URL der Cache ins Leere läuft. Am besten geht das mit einem Timestamp:

url = url + "?" + (new Date()).getTime();

Der URL wird dann die Anzahl der Millisekunden seit 1970 angehangen.