What are unit testing strategies for D3JS?

I think I got the answer to my own question. Will try to explain it here.

It is not possible to validate whether the graph is plotted correctly by JS function written using D3JS. For this we may have to use Phantom.js or similar framework as mentioned by Chrisopher. I was not worried about making sure D3JS is plotting graph correctly, as any ways it is D3JS functionality and my code can safely assume D3JS is doing its work.

My worry is more of whether the data passed to D3JS is correct and as per my requirement. It is very much possible to make sure the properties of the graph are set correctly by creating Spy objects. I am providing a sample unit test covering test cases for a JS code plotting a Circle using D3JS.

CircleManager.js

function CircleManager() {};

CircleManager.prototype.draw = function(radius) {
    var svg = d3.select("body")
            .append("svg");

    svg.attr("width", 100)
            .attr("height", 100);    

    var circle = svg.append("circle");
    circle.style("stroke", "black")
        .style("fill", "white")
        .attr("r", radius)
        .attr("cx", 50)
        .attr("cy", 50);
};

CircleManagerSpec.js

describe("draw", function() {
    it("Constructs an svg", function() {
        var d3SpyObject = jasmine.createSpyObj(d3, ['append', 'attr']);

        // Returns d3SpyObject when d3.select method is called
        spyOn(d3, 'select').andReturn(d3SpyObject);

        var svgSpyObject = jasmine.createSpyObj('svg', ['append', 'attr', 'style']);

        // Returns svgSpyObject when d3.select.append is called.
        d3SpyObject.append.andReturn(svgSpyObject);


        d3SpyObject.attr.andCallFake(function(key, value) {
            return this;
        });

        svgSpyObject.append.andReturn(svgSpyObject);

        svgSpyObject.attr.andCallFake(function(key, value) {
            return this;
        });

        svgSpyObject.style.andCallFake(function(key, value) {
            return this;
        });

        var circleManager = new CircleManager();
        circleManager.draw(50);
        expect(d3.select).toHaveBeenCalledWith('body');
        expect(d3SpyObject.append).toHaveBeenCalledWith('svg');
        expect(svgSpyObject.attr).toHaveBeenCalledWith('r', 50);
        expect(svgSpyObject.attr).toHaveBeenCalledWith('width', 100);
        expect(svgSpyObject.attr).toHaveBeenCalledWith('height', 100);
        expect(svgSpyObject.style).toHaveBeenCalledWith('stroke', 'black');
        expect(svgSpyObject.style).toHaveBeenCalledWith('fill', 'white');
    });
});

Hope this helps.

Leave a Comment