简体   繁体   中英

Unit testing AngularJS directive wrapping Snap.svg

I'm trying to create an Angular directive to wrap Snap.svg functionality, but I'm having trouble with unit testing it. So far I have a directive that looks like this:

'use strict';

angular.module('rpApp')
  .directive('rpSvgMap', function () {
    return {
      template: '<svg id="" width="" height=""></svg>',
      restrict: 'E',
      replace: true,
      // Don't isolate scope because we want to attach rpMap to parent scope
      link: function postLink(scope, element, attrs) {
        // Set up Snap.svg wrapper
        scope.rpMap = Snap('#' + attrs.id);
      }
    };
  });

And my Karma/Jasmine tests look like this:

'use strict';

describe('Directive: rpSvgMap', function () {

  // load the directive's module
  beforeEach(module('rpApp'));

  var element,
    scope;

    beforeEach(inject(function($rootScope,$compile) {
        scope = $rootScope.$new();
        element =
      '<rp-svg-map id="anyOldID" width="800" height="400" src="../../assets/testmap.svg"></rp-svg-map>';

        element = $compile(element)(scope);
        scope.$digest();
  }));

  describe('on initialization', function() {
    it('should create an SVG element with the provided dimensions and id', function() {
      expect(element.attr('id')).toBe('anyOldID');
      expect(element.attr('height')).toBe('400');
      expect(element.attr('width')).toBe('800');
    });
    it('should provide a working Snap.svg drawing surface', function() {
      var testCircle = scope.rpMap.circle(100,150,200);
      expect(testCircle.attr(cx)).toBe(100);
    });

});

The first test passes, and the second one fails as scope.rpMap always comes back as "null".

In the browser, this works just fine -- if I attach $scope to the window in my controller, rpMap is correctly wrapped by Snap.svg and rpMap.circle() correctly draws a circle.

So far as I can tell, the testing environment is properly loading snap.svg as a dependency and I'm reading scope properly out of the directive. For instance, if I add:

scope.hasSnap = angular.isFunction(Snap);

to the directive's link function, then this test passes:

it('should tell us when Snap.svg is available', function() {
      expect(scope.hasSnap).toBe(true);
    });

Snap() is not async and changing the beforeAll/it to asynchronous mode does not help.

Any ideas what I'm doing wrong here?

This jsfiddle I found (sorry, can't remember the source) contains the solution http://jsfiddle.net/hRy4A/2/

Specifically, we can pass the element directly to Snap like so:

scope.rpMap = Snap(element[0]);

When rpMap is created this way, the following test passes:

it('should provide a working Snap.svg drawing surface', function() {
        var testCircle = scope.rpMap.circle(100,150,200);
        expect(testCircle.attr('cx')).toBe('100');
        expect(testCircle.attr('cy')).toBe('150');
        expect(testCircle.attr('r')).toBe('200');
    });

I guess one potential issue with this approach is that I don't necessarily need or want to have all the Snap.svg methods exposed in $scope -- I suppose ideally the graphical stuff would all be self-contained inside the directive.

Note that there was also a minor typo in my original test, it should be

expect(testCircle.attr('cx')).toBe('100');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM