Pregunta

I have d3 visualization inside of my directive. The problem with that is that there is a lot of boilerplate code that can be reused across many other visualizations, like setting the element[0] to the container of the d3 visualization. So I decided to create a service to do all the work that was being done in the directive and try to keep myself DRY. I'm stuck with testing at the moment and this is where I was hoping to get some help. My code is as follows

Directive


angular.module('app')
  .directive('barchart', function (Barchartservice) {
    return {
      restrict: 'E',
      link: function postLink(scope, element, attrs) {

        scope.$on('drawCharts',function(ev,attrs){
          draw();
        });

        function draw(){
          if(!scope.dataset) return;

          var svg = Barchartservice.setContainer(svg, element);
          .
          .
          .
          .

        }
      }
    };
  });


Service


angular.module('app')
  .service('Barchartservice', function Barchartservice() {
    var margin = {top: 50, right: 20, bottom: 50, left: 40},
              container,
              width = (1120 || container.width() - 20) - margin.left - margin.right,
              height = 400 - margin.top - margin.bottom;
    return{
        setContainer: function(svg, element){
            container  = angular.element(element);
            svg = d3.select(element[0]).append('svg')
                    .attr('width', width + margin.left + margin.right)
                    .attr('height', height + margin.top + margin.bottom)
                    .append('g')
                    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
        return svg;
        }
    }
  });

Test


'use strict';

describe('Service: Barchartservice', function () {

  // load the service's module
  beforeEach(module('clientApp'));

  // instantiate service
  var Barchartservice;
  beforeEach(inject(function (_Barchartservice_) {
    Barchartservice = _Barchartservice_;
  }));

  it('should insert an svg element into the barchart directive', function () {
    var svg = undefined;
    var element = [];
    element[0] = '<barchart></barchart>';
    expect(Barchartservice.setContainer()).toEqual('<barchart><svg></svg></barchart>');
  });

});

Error


PhantomJS 1.9.2 (Mac OS X) Service: Barchartservice should do something FAILED
    TypeError: 'undefined' is not an object (evaluating 'element[0]')

Any help is much appreciated. Thanks!

¿Fue útil?

Solución

You need to compile the element. When testing AngularJS you have to control compiling and linking the directives to the dom tree. You also need to call scope.$apply() once this is completed as well.

So first you need to inject the $compile service and the $rootScope service in the beforeEach DI block.

Set scope = $rootScope in the beforeEach as well so you can reference a clean scope for you tests.

var element = $compile('<barchart></barchart>')(scope);
scope.$apply();
expect(Barchartservice.setContainer()).toEqual('<barchart><svg></svg></barchart>');

This should get you further, but it may not pass the test completely. It seems from your source, that you need to broadcast a drawCharts event as well to actually run the setContainer function. So this could be an issue as well.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top