Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing AngularJS directive, postLink D3 not changing DOM

I'm trying to unit test an AngularJS directive using Jasmine. The directive is meant to add SVG elements to the template in the postLink phase using D3js. This works fine in the actual application.

In the unit test it appears that the D3 code is never executed.

This is a simplified version of the code that still reproduces the error:

angular.module('app', []);

angular.module('app').directive('d3Test', function () {
  return {
    template: '<div id="map"></div>',
    restrict:'E',
    scope: {
      someAttr: '@',
    },
    link: function postLink(scope, element, attrs) {

      d3.select('#map').append('svg');
    }
  };
});

This is the unit test:

describe('directive test', function () {

  var element, scope;

  beforeEach(module('app'));

  beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();
    element = '<d3-test></d3-test>';
    element = $compile(element)(scope);
    scope.$apply();
  }));

  it('should have an SVG child element', function () {
     expect(element.html()).toEqual('<div id="map"><svg></svg></div>');
   });

});

The error I receive is:

PhantomJS 1.9.8 (Mac OS X) directive test should have an SVG child element FAILED
    Expected '<div id="map"></div>' to equal '<div id="map"><svg></svg></div>'.

Is my expectation wrong on how I can test for the DOM changes D3 will make? How can I best test this?

like image 730
Joe Dreimann Avatar asked Feb 09 '15 18:02

Joe Dreimann


1 Answers

the problem is very simple. The d3.select method is searching for the element in the window.document. In your test case your element is in a detached dom element and not part of the window.document.

To fix this you can get the node directly via the directive's element instead of using a global selector.

d3.select(element.find('div#map')[0]).append('svg');

Note: This code works with angular+jQuery. If you don't use jQuery inside of your project you may need to adapt the selector because then your are limited to lookups by tag name. https://docs.angularjs.org/api/ng/function/angular.element

like image 89
Robin Böhm Avatar answered Nov 15 '22 04:11

Robin Böhm