javascript - 触发浏览器事件进行测试

标签 javascript d3.js jasmine

我正在尝试为我在 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.

这种行为有两个缺点:

  1. 正如您已经提到的,d3.event 不会填充触发的事件,使其 null

  2. 即使您尝试以编程方式将 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/

相关文章:

javascript - 语法错误: missing ) after formal parameters when adding if/else

javascript - 在 javascript/jquery 中排序 xml

node.js - Jasmine Node 找不到规范模块

javascript - 为什么 rxjs 6 弹珠文档说 "--(abc)-|"在第 8 帧完成?

unit-testing - 如何进行同步测试或不共享 stub 服务?

javascript - 如何将javascript变量传递给xsl变量?

javascript - 使用时是否需要使用 "="? : javascript shortcut?

javascript - 调整 D3 图表栏高度

d3.js - NVD3.js (d3.js) 尺度中断

javascript - D3 曲线反转