How to unit test an AngularJS Controller with $setPristine

angularjs, unit-testing

Solution

Yes, normally the `$scope.frmAddTask` object would be created by the `ngForm` directive. However, in this case, it is being created by you in your test:

scope.frmAddTask = {
  $valid: true
};

Since you're using this mock object anyway, I would suggest stubbing out the `$setPristine` method on it:

scope.frmAddTask = {
  $valid: true,
  $setPristine: function() {}
};

Problem

I have the following controller:- ``` appControllers.controller("TaskAddController", function ($scope, $timeout, taskService) { $scope.task = {}; $scope.messages = { error: false }; $scope.actions = { save : function() { if ($scope.frmAddTask.$valid) { taskService.insert($scope.task) .then( function() { $scope.messages.success = true; $scope.task = {}; $scope.frmAddTask.$setPristine(); $timeout(function() { $scope.messages.success = false; }, 3000); }, function() { $scope.messages.error = true; } ); } else { $scope.messages.error = true; } } }; }); ``` With this unit test:- ``` /// <reference path="../../../../src/tasks.web/scripts/angular-1.2.10.js" /> /// <reference path="../../../../src/tasks.web/scripts/angular-route-1.2.10.js" /> /// <reference path="../../../../src/tasks.web/scripts/app.js" /> /// <reference path="../../../../src/tasks.web/scripts/services.js" /> /// <reference path="../../../../src/tasks.web/scripts/controllers.js" /> /// <reference path="../lib/angular/angular-mocks.js" /> describe("TaskAddController", function() { var createController, scope, deferred, mockTaskService; beforeEach(function () { module('appControllers'); module('appServices'); inject(function ($rootScope, $q, taskService) { scope = $rootScope.$new(); scope.frmAddTask = { $valid: true }; deferred = $q.defer(); mockTaskService = taskService; spyOn(mockTaskService, "insert").andReturn(deferred.promise); }); inject(function ($controller) { createController = function () { return $controller("TaskAddController", { $scope: scope, taskService: mockTaskService }); }; }); }); it("when actions.save is called then messages.success should be true", function () { var task = { title: "Title", description: "Description" }; createController(); scope.task = task; scope.actions.save(); deferred.resolve("insert"); scope.$root.$digest(); expect(scope.messages.success).toEqual(true); }); }); ``` This errors with the message `TypeError: 'undefined' is not a function (evaluating '$scope.frmAddTask.$setPristine()')` I assume this is because the unit test only tests the controller and `$scope.frmAddTask` only exists when the view is present. So my question is how do I unit test this properly?

Original source