使用Sinon在D3中测试Mouseover事件

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

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

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

 
mocha.ui('bdd'); mocha.reporter('html'); var expect = chai.expect; mocha.run();

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); }); }); }); 

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

错误消息“错误:预期至少被调用一次但从未被调用过”是准确的。 on测试期间不会调用on 。 它只在你的灯具中调用,用于设置事件处理程序。 您还触发了mouseenter事件,但您的侦听器是用于mouseovermouseover mouseout 。 在现实世界中,你会在mouseenter事件发生后很快得到一个mouseover ,但是当你用jQuery伪造它时就不会发生。 无论如何,jQuery是一个非首发; 见下文。


您可以尝试通过将它们从匿名函数更改为名称来修复此问题,如下所示:

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

然后使用path.on('mouseover', mouseOverHandler)将其绑定到您的path 。 你认为你现在可以监视mouseOverHandler ,但这也不会起作用 。 当你打电话on ,你的function将受到限制,因此以后将其交换为Sinon间谍将不会产生任何影响。

jQuery触发不适用于D3

另一个问题是你不能使用jQuery来触发D3事件,因为jQuery事件不是DOM事件 。 因此,您应该document.getElementById('path_one').dispatchEvent(new MouseEvent('mouseover')); $('path').mouseenter()的调用替换为document.getElementById('path_one').dispatchEvent(new MouseEvent('mouseover')); (注意这是将代码从“在所有路径上触发mouseover ”更改为“在具有id path_one的元素上触发mouseover ”)。

测试错误的东西

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

如果你真的想断言你的事件处理程序是绑定的,你可以这样做:

 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); }); });