Unit test controllers with modal


#1

Hi there,

I am trying to write unit tests with Karma + Jasmine on a controller that uses a modal.

Controller code looks like this:

.controller('TodoCtrl', function($scope, $ionicModal) {
	
	// The list of tasks
	$scope.tasks = [];

	// Creat and load the New Task modal
	$ionicModal.fromTemplateUrl('templates/new-task.html', function(modal) {
		$scope.taskModal = modal;
	}, {
		scope: $scope,
		animation: 'slide-in-up'
	});

	$scope.addTask = function(task) {
		$scope.tasks.push({
			title: task.title
		});
		$scope.taskModal.hide();
		task.title = '';
	};

My test code is:

describe(‘Controller: TodoCtrl’, function() {

// Load the controller's module
beforeEach(module('doobiedoo'));

var TodoCtrl, scope;

// Initialise the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
	scope = $rootScope.$new();
	TodoCtrl = $controller('TodoCtrl', {
		$scope: scope
	});
}));

it('should add tasks to the list', function() {
	scope.task = { title: 'Task 1' };
	scope.addTask(scope.task);
	expect(scope.tasks.length).toBe(1);
});

The code fails with this exception:

PhantomJS 1.9.7 (Mac OS X) Controller: TodoCtrl should remove tasks from the list FAILED
TypeError: ‘undefined’ is not an object (evaluating ‘$scope.taskModal.hide’)

How is this done in general?

Thanks a lot.


#2

Maybe your modal is not added to your scope?

But all in all it is difficult to write good unit tests for controllers, because $scope-functions are called from user interface interactions and communicate with other controllers and so on.

For those parts it is easier to write an ui-test with protractor and chrome or phantomJS.
There you can simulate the userbehavior (clicking, typing and so on) and validate the results with css selectors (how the dom changes and so on).

Unit tests are really good for services / factories / providers, because they are almost ordinary functions with parameters and a return value. So you can call the function easy in your unit test and you can check the result.

Hope that helps a bit.

If you are using angularjs right, everything you do not need in a controller (mostly everthing, which is not set on $scope. …) you can move in a service and write a function for that. So your UI-tests will cover all controller stuff (maybe also directive stuff). and unit tests the rest of your code.

Greets, bengtler