Reputation: 385
I am attempting to trigger a d3 event using Jasmine. In particular, I want to check that my event listener is being called using a Jasmine spy.
For example, if I attach the d3 zoom behavior to an svg element (I am using Backbone.js for my front end):
Code (a):
class MyView extends Backbone.View
initialize: ->
zoom = d3.behavior.zoom().on("zoom", this.zoom_listener)
d3.select(this.el).append("svg").attr("class", "viewport").call(zoom)
zoom_listener: ->
console.log("zoom called")
The following test in Jasmine fails:
Code (b):
it "calls zoom listener on dblclick", ->
zoom_spy = spyOn(MyView.prototype, "zoom_listener").andCallThrough()
view = new MyView()
view.$(".viewport").trigger("dblclick")
waitsFor((-> zoom_spy.callCount == 1), "Call zoom", 1000)
On the other hand, (just as a sanity check) if I binded a 'dblclick' event to my view as shown below, the above test i.e. Code (b) will pass:
Code (c):
class MyView extends Backbone.View
events:
"dblclick" : "zoom_listener"
initialize: ->
zoom = d3.behavior.zoom().on("zoom", this.zoom_listener)
d3.select(this.el).append("svg").attr("class", "viewport")
# .call(zoom) # commented off this line for the sanity check
zoom_listener: ->
console.log("zoom called")
Can anyone give me some insight as to why I can't seem to get the D3 zoom event triggered within the Jasmine test i.e. Code (b) using my original view above i.e. Code (a)?
Upvotes: 3
Views: 2583
Reputation: 1
A variation on the example by @Biovisualize:
fixture.datum(dataset).call(barChart);
var callback = jasmine.createSpy("filterCallback");
barChart.on('customHover', callback);
//to trigger all elements
fixture.selectAll('.bar').each(function() {
this.__onmouseover();
});
expect(callback).toHaveBeenCalled();
Upvotes: 0
Reputation: 385
As stated by M. Bostock in https://github.com/mbostock/d3/issues/906: "jQuery trigger doesn't dispatch real events; it only calls its own listeners."
One way to dispatch a real event using vanilla JS is (based on the reply from user "handler" in How to invoke "click" event programmatically in d3?):
Code (b-modified)
it "calls zoom listener on dblclick", ->
zoom_spy = spyOn(MyView.prototype, "zoom_listener").andCallThrough()
view = new MyView()
jQuery.fn.custom_mouse_dblclick = (->
this.each(((i, element) ->
evt = document.createEvent("MouseEvent")
evt.initMouseEvent(
"dblclick",
true,
true,
window,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null)
element.dispatchEvent(evt)
))
)
view.$(".viewport").custom_mouse_dblclick()
waitsFor((-> zoom_spy.callCount == 1), "Call zoom", 1000)
So the Jasmine test in Code (b-modified) passes when performed on Code (a) in the original question i.e. svg element with d3.zoom() behavior.
Upvotes: 0
Reputation: 2475
Backbone triggers jQuery events, which doesn't seem to register outside of the jQuery world. Some workarounds are explained here. But here is a general way to test D3 events with Jasmine.
it('should trigger a callback on custom events', function() {
fixture.datum(dataset)
.call(barChart);
var callback = jasmine.createSpy("filterCallback");
barChart.on('customHover', callback);
var bars = fixture.selectAll('.bar');
bars[0][0].__onmouseover();
var callBackArguments = callback.argsForCall[0][0];
expect(callback).toHaveBeenCalled();
expect(callBackArguments).toBe(dataset[0]);
});
D3 exposes events on the DOM object. So you can attach a spy and trigger it.
Upvotes: 5