我正在尝试为我在 D3
中创建的一些自定义事件处理编写一些测试,但我无法找出触发这些事件的适当方法,但该方法仍然可以正常工作D3 的内部结构。
我不会介绍自定义事件的确切实现详细信息,但会简要介绍我所拥有的。因此,首先有一个函数将一系列事件连接到称为 g
的SVG元素。为简单起见,我将使用 Mousedown
事件来解释我的问题:
var events = function(g) {
container = g;
// Register the raw events required
g.on("mousedown", mousedown)
.on("mouseenter", mouseenter)
.on("mouseleave", mouseleave)
.on("click", clicked)
.on("contextmenu", contextMenu)
.on("dblclick", doubleClicked);
return events;
};
Mousedown
事件启动时,这将调用以下功能:
function mousedown(d, i) {
// Record the initial position of the mouse down
windowStartPosition = getWindowPosition();
position = getPosition();
// Do more stuff
// Trigger a mouse down event
dispatch.mousedown.call(this, d, i);
}
function getWindowPosition() {
var point = {
x: d3.event.clientX,
y: d3.event.clientY,
dx: 0,
dy: 0
};
if (position) {
point.dx = windowPosition.x -point.x;
point.dy = windowPosition.y - point.y;
}
return point;
};
所以我希望使用 Jasmine
测试此代码,我已经在 SVG circle
上设置了自定义事件,现在我想触发它们来测试我的代码。请注意, myFunc
是 jasmine
spy。
it("triggers mouse down", function () {
events.on("mousedown", myfunc);
// Trigger mouse down
expect(myfunc).toHaveBeenCalled();
})
因此,我目前使用 d3
来获取事件并手动触发它:
circle.on("mousedown")();
并使用jQuery选择和触发事件:
$("circle").trigger("mousedown");
不幸的是,我发现我的 getWindowPosition()
调用失败,这是因为 d3.event
是null。
因此,我试图找出一种触发事件的方法,该事件的行为尽可能类似于真实的点击,以便 D3
正确设置 d3.event 信息。谁能就我如何触发此事件提出任何其他建议?
最佳答案
这听起来很像几周前我必须努力解决的类似问题。你的方法是我当时第一个想到的。经过一些研究后,我得出结论,由于以下原因,它不会起作用:
jQuery
规范告诉我们 jQuery.trigger()
方法:
Although
.trigger()
simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.
这种行为有两个缺点:
正如您已经提到的,
d3.event
不会填充触发的事件,使其null
。即使您尝试以编程方式将
d3.event
设置为 jQuery 创建的合成事件,您也会偶然发现下一个问题,因为您会发现它很漂亮很空白。由于该事件不是由真正的鼠标单击引起的,因此其中不会有任何坐标(如.clientX
、.clientY
)。因此,您的代码将因这个缺点而崩溃。
最终,我创建了自己的 MouseEvent
:
// Initialize the event as needed.
var mouseEventInit = {
"button": 0,
"clientX": 0, // maybe something like circle.getBoundingClientRect().left + 1
"clientY": 0 // maybe something like circle.getBoundingClientRect().top + 1
// ... fill any properties you need.
};
// create new event and...
var event = new MouseEvent("click", mouseEventInit);
如果您需要支持 Internet Explorer,则必须使用已弃用的方法 MouseEvent.initMouseEvent()
,因为 IE 尚不支持使用通过构造函数创建的新事件对象:
var event = document.createEvent("MouseEvents");
event.initMouseEvent( /* params */ );
我使用了浏览器检测并切换到设置事件对象的正确方法。
创建新的事件对象后,您可以使用方法dispatchEvent()
将其分派(dispatch)到所需的目标。由 DOM 的 Element
实现的接口(interface) EventTarget
的:
// dispatch it to the target
circle.dispatchEvent(event);
这样您最终会得到一个成熟的事件,d3 也会识别该事件,并将其相应地放入 d3.event
中。
关于javascript - 触发浏览器事件进行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29413119/