Angular directive testing with Jasmine and waiting for event to be triggered

Using the $timeout and the mocked $timeout the test becomes a lot more clear and concise.

by Danny Michaelis

HTML

<script src="http://jasmine.github.io/1.3/lib/jasmine.js"></script>
<script src="http://jasmine.github.io/1.3/lib/jasmine-html.js"></script>
<link rel="stylesheet" href="http://jasmine.github.io/1.3/lib/jasmine.css">
<script src="http://code.angularjs.org/1.2.9/angular.js"></script>
<script src="http://code.angularjs.org/1.2.9/angular-mocks.js"></script>
Example of using jasmine and angular using the $timeout.  It will allow you to upgrade your jasmine to version 2.0 without problems unlike running with the runs(){} and waits(){} that will have to be rewritten as they are not longer supported.

JavaScript

//--- CODE --------------------------

// Create module
var myApp = angular.module('myApp', []);

myApp.directive('delayedModel', function($timeout) {
  return {
    scope: {
      model: '=delayedModel'
    },
    link: function(scope, element, attrs) {
      element.val(scope.model);
      scope.$watch('model', function(newVal, oldVal) {
        if (newVal !== oldVal) {
          element.val(scope.model);
        }
      });

      var timeout;
      element.on('paste', function() {
        $timeout(function() {
          scope.model = element[0].value;
          element.val(scope.model);
          scope.$apply();
        }, attrs.delay || 500);
      });
    }
  };
});

// ---SPECS-------------------------

describe('Test directive with a timeout', function() {
  
	var $scope, $compile, html, element, $timeout;

	beforeEach(module('myApp'));

	beforeEach( inject( function ( $rootScope , _$compile_, _$timeout_) {
		this.$scope = $rootScope.$new();
		this.$compile = _$compile_;
        this.$timeout = _$timeout_;
	}));
    
    afterEach ( function() {
        this.$timeout.verifyNoPendingTasks();
    });
    
	describe('using the $timeout functionality', function() {
		var html;

		beforeEach(function (){
            //setup to have a delay of 10 miliseconds.
			this.html = '<input delayed-model="query" delay="10" name="Search"></input>';
			this.element = this.$compile(this.html)(this.$scope);
            //as we have our own scope in the directive we should use our element's scope
			this.element.scope().$apply();
		});

		describe('when we check the delayed search', function () {
			//starts off as nothing
			it('scope and element value should start off unset and empty', function() {
				expect(this.$scope.query).toBeUndefined();
				expect(this.element.val()).toEqual('');
				expect(this.element.scope().query).toBeUndefined();
			});

			it('it will trigger only change the value on the scope after the timeout has elapsed',...