mindparse
mindparse

Reputation: 7235

d3.js - jasmine test to invoke a click on an svg element

I have a chart directive in my angular application that makes use of the d3.js library.

Part of the directive adds mouse event handlers to some svg elements like so

svg.selectAll('g rect')
    .on('click', function(d) {
        scope.clickHandler(d, scope.data);
    })
    .on('mouseover', function () {
        d3.select(this).classed('data-item-hover', true);
    })
    .on('mouseout', function () {
        d3.select(this).classed('data-item-hover', false);
    });

I want to cover these handlers in some unit tests, but am struggling with how to actually invoke these events dynamically.

I am attempting this in my test spec

describe('scope.clickHandler', function() {
    var rect;
    beforeEach(function(){
        spyOn(scope, 'clickHandler');
        rect = svg.select('g rect')[0][0];
        rect.on('click')();
    });
    it('should call scope.render after a window resize event occurs', function () {
        expect(scope.clickHandler).toHaveBeenCalled();
    });
});

However this throws an error

TypeError: undefined is not a constructor (evaluating 'rect.on('click')'

I came across this SO How to invoke "click" event programmatically in d3? and the second answer is what has led me to trying this technique.

How can I call a mouse event on the svg elements that I have registered events with in d3.js?

Thanks

Upvotes: 2

Views: 2433

Answers (1)

jarandaf
jarandaf

Reputation: 4427

The main issue is that svg.select('g rect')[0][0] is a DOM element and not a proper D3 selection, that's why you get undefined error. From the docs:

Selections are arrays of elements—literally (maybe not literally...). D3 binds additional methods to the array so that you can apply operators to the selected elements...

You can actually check that since a DOM element implements the Element interface:

(svg.select('g rect')[0][0] instanceof Element) // true

So in order to trigger some event on a certain element, you could do the following:

var rect = svg.select('g rect') // first rect element found is assumed
rect.on('click').call(rect.node(), rect.datum()); // as commented in above link

You can find a simple working fiddle here.

Upvotes: 4

Related Questions