触发浏览器事件进行测试
Triggering browser events for testing
我正在尝试为我在 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
间谍。
it("triggers mouse down", function () {
events.on("mousedown", myfunc);
// Trigger mouse down
expect(myfunc).toHaveBeenCalled();
})
所以我目前尝试了 2 种不同的方法来在圆圈上触发此事件,使用 D3
获取事件并手动触发它:
circle.on("mousedown")();
并使用jQuery到select并触发事件:
$("circle").trigger("mousedown");
不幸的是,我发现我的 getWindowPosition()
调用失败了,这是因为 d3.event
为空。
因此,我试图找到一种方法来触发一个事件,该事件的行为将尽可能像真正的点击,这样 D3
可以正确设置 d3.event 信息。谁能就我如何触发此事件提出任何其他建议?
这可能是一个范围界定问题。尝试在 mousedown 处理程序中调用 d3.event 并查看该值是否仍然为空。如果是这样,只需将 getWindowPosition 函数声明移动到 mousedown 处理程序范围内。
这听起来很像几周前我不得不努力解决的类似问题。你的方法是我当时第一个想到的。在做了一些研究后,我得出结论,由于以下原因,它不会起作用:
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 */ );
我使用浏览器检测并切换到设置事件对象的正确方法。
创建新事件对象后,您就可以使用接口 EventTarget
的方法 dispatchEvent()
将其分派到所需的目标,接口 EventTarget
由 DOM 的 [=25] 实现=]:
// dispatch it to the target
circle.dispatchEvent(event);
这样你就得到了一个完全成熟的事件,它也将被 d3 识别并相应地把它放到 d3.event
。
我正在尝试为我在 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
间谍。
it("triggers mouse down", function () {
events.on("mousedown", myfunc);
// Trigger mouse down
expect(myfunc).toHaveBeenCalled();
})
所以我目前尝试了 2 种不同的方法来在圆圈上触发此事件,使用 D3
获取事件并手动触发它:
circle.on("mousedown")();
并使用jQuery到select并触发事件:
$("circle").trigger("mousedown");
不幸的是,我发现我的 getWindowPosition()
调用失败了,这是因为 d3.event
为空。
因此,我试图找到一种方法来触发一个事件,该事件的行为将尽可能像真正的点击,这样 D3
可以正确设置 d3.event 信息。谁能就我如何触发此事件提出任何其他建议?
这可能是一个范围界定问题。尝试在 mousedown 处理程序中调用 d3.event 并查看该值是否仍然为空。如果是这样,只需将 getWindowPosition 函数声明移动到 mousedown 处理程序范围内。
这听起来很像几周前我不得不努力解决的类似问题。你的方法是我当时第一个想到的。在做了一些研究后,我得出结论,由于以下原因,它不会起作用:
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 */ );
我使用浏览器检测并切换到设置事件对象的正确方法。
创建新事件对象后,您就可以使用接口 EventTarget
的方法 dispatchEvent()
将其分派到所需的目标,接口 EventTarget
由 DOM 的 [=25] 实现=]:
// dispatch it to the target
circle.dispatchEvent(event);
这样你就得到了一个完全成熟的事件,它也将被 d3 识别并相应地把它放到 d3.event
。