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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With