Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing an AngularJS directive that watches an an attribute with isolate scope

I have a directive that uses an isolate scope to pass in data to a directive that changes over time. It watches for changes on that value and does some computation on each change. When I try to unit test the directive, I can not get the watch to trigger (trimmed for brevity, but the basic concept is shown below):

Directive:

angular.module('directives.file', [])
.directive('file', function() {
  return {
    restrict: 'E',
    scope: {
      data: '=',
      filename: '@',
    },
    link: function(scope, element, attrs) {
      console.log('in link');
      var convertToCSV = function(newItem) { ... };

      scope.$watch('data', function(newItem) {
        console.log('in watch');
        var csv_obj = convertToCSV(newItem);
        var blob = new Blob([csv_obj], {type:'text/plain'});
        var link = window.webkitURL.createObjectURL(blob);
        element.html('<a href=' + link + ' download=' + attrs.filename +'>Export to CSV</a>');
      }, true);
    }
  };
});

Test:

describe('Unit: File export', function() {
  var scope;

  beforeEach(module('directives.file'));
  beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();
  };

  it('should create a CSV', function() {
    scope.input = someData;
    var e = $compile('<file data="input" filename="filename.csv"></file>')(scope);
    //I've also tried below but that does not help
    scope.$apply(function() { scope.input = {}; });
  });

What can I do to trigger the watch so my "In watch" debugging statement is triggered? My "In link" gets triggered when I compile.

like image 876
nathasm Avatar asked Jul 31 '13 19:07

nathasm


People also ask

What is isolate scope in AngularJS?

Isolated scope directive is a scope that does not inherit from the parent and exist on its own. Scenario: Lets create a very simple directive which will show the object from the parent controller.

What are the directive scopes in AngularJS?

The directive scope uses prefixes to achieve that. Using prefixes helps establish a two-way or one-way binding between parent and directive scopes, and also make calls to parent scope methods. To access any data in the parent scope requires passing the data at two places – the directive scope and the directive tag.

What is unit testing in AngularJS?

Angularjs unit testing is the basic need for any application. It ensures the application's quality and demonstrates its capabilities to the users.

Which of the following can be used to run unit tests in angular?

Jasmine is the default test framework used with Angular.


1 Answers

For a $watch to get triggered, a digest cycle must occur on the scope it is defined or on its parent. Since your directive creates an isolate scope, it doesn't inherit from the parent scope and thus its watchers won't get processed until you call $apply on the proper scope.

You can access the directive scope by calling scope() on the element returned by the $compile service:

scope.input = someData;
var e = $compile('<file data="input" filename="filename.csv"></file>')(scope);
e.isolateScope().$apply();

This jsFiddler exemplifies that.

like image 180
Michael Benford Avatar answered Oct 04 '22 21:10

Michael Benford