使用Sinon在D3中测试Mouseover事件

时间:2014-06-05 10:28:05

标签: javascript jquery d3.js bdd sinon

我在试图通过测试时遇到了麻烦。我希望能够使用间谍来检查鼠标悬停事件是否被正确调用。目前我收到以下错误,“错误:预计至少被调用一次,但从未被调用”。我的部分困惑与d3和jQuery选择器之间的差异有关,我非常乐意使用后者,但我不确定如何在测试中正确使用前者来获得我想要的结果。

我的依赖是d3,jQuery,mocha,chai,sinon和sinon-chai。

我的index.html文件中的相关代码,

<script src="fixtures.js"></script>
<div id="mocha"></div>
<script src="mocha.js"></script>
<script src="chai.js"></script>
<script src="sinon-chai.js"></script>
<script src="sinon-1.10.2.js"></script>
<script>
    mocha.ui('bdd');
    mocha.reporter('html');
    var expect = chai.expect;
 </script>
 <script src="tests.js"></script>
 <script>
    mocha.run();
</script>

fixtures.js,

var path = svg.selectAll("path")
          .data(pie(data))
          .enter().append("path").attr("class", "path")
          .style("fill", function(d, i) { return color(i); })
          .attr("d", arc)
          .on("mouseover", function() { d3.select(this).style("fill", "#ff0000"); })
          .on("mouseout" , function() { d3.selectAll("path").style("fill", function(d, i) { return color(i); }); });

//  I wanted to test my understanding of d3 selectors
var path_one = d3.select('.path').attr("id", "path_one"); 

tests.js,

describe('Donut Chart', function() {
    describe("Mouseover events", function() {
        it("should call on('mouseover')", function () {
            var spy = sinon.spy(path, "on");
            $('path').mouseenter();
            sinon.assert.called(spy);
        });
    });
});

1 个答案:

答案 0 :(得分:8)

这里有一些问题;我们可以理清你的语法,但我们也必须弄清楚这个意图。

错误消息&#34;错误:预期on至少被调用一次,但从未被调用过#34;是准确的。在测试期间 on未被调用。它只在您的灯具中调用,以设置事件处理程序。您还会触发mouseenter个活动,但您的听众适用于mouseovermouseout。在现实世界中,您在mouseover事件发生后很快就会获得mouseenter,但是当您使用不会发生的jQuery伪造它时。无论如何,jQuery是一个非首发;见下文。


您可以尝试通过将它们从匿名函数更改为命名的内容来解决此问题,如下所示:

var mouseOverHandler = function() { 
    d3.select(this).style('fill', '#ff0000');
};

然后使用path将其绑定到path.on('mouseover', mouseOverHandler)。您认为现在可以监视mouseOverHandler,但不能继续监视。当你打电话给on时,你的功能会受到约束,所以将它换成一个罪人间谍后来不会有任何影响。

jQuery触发无法使用D3

另一个问题是you can't use jQuery to trigger D3 events because jQuery events aren't DOM events。因此,您应该将对$('path').mouseenter()的调用替换为类似document.getElementById('path_one').dispatchEvent(new MouseEvent('mouseover'));的内容(注意这是在更改代码来自&#34;在所有路径上触发mouseenter&#34;到&#34;在ID为mouseover&#34;)的元素上触发path_one

测试错误的东西

你可以通过重构来实现这一点,这样你可以用你可以窥探的东西来换掉你的回调,但从根本上你是在测试错误的东西。从本质上讲,你正在尝试为D3编写测试; &#34;当我添加一个事件监听器时,请确保调用事件监听器。&#34;相反,你应该测试你的实际代码的行为:&#34;当有人鼠标悬停在图表上时,它的颜色应该改变&#34;。

如果您确实想断言您的事件处理程序已绑定,您可以这样做:

expect(path.on('mouseover')).to.be.a('function')

但是如果你想确保改变你的颜色,你希望你的测试如下:

describe("Mouseover events", function() {
    it("should update the colours when a user mouses over the paths", function () {
        var oldColor = path.style('fill');
        document.getElementById('path_one').dispatchEvent(new MouseEvent('mouseover'));
        expect(path.style('fill')).to.not.equal(oldColor);
    });
});