使用Cypress.js测试D3.js拖动事件

时间:2019-01-03 18:30:55

标签: javascript d3.js svg cypress

我有一个SVG对象,该对象使用d3-zoom来实现缩放和平移功能。它可以正常工作,但是当我开始使用Cypress.js进行集成测试时,问题就出现了。

我尝试在svg元素上使用标准鼠标事件来模拟拖动行为:

cy.get('svg')
  .trigger('mousedown', { which: 1, force: true })
  .trigger('mousemove', { position: 'left' })
  .trigger('mouseup', { position: 'left', force: true });

上面的示例取自赛普拉斯drag and drop recipe,它在 nodrag.js 文件中产生以下错误:

  

无法读取未定义的属性文档

下面您可以看到错误发生的位置(视图undefined):

__webpack_exports__["default"] = (function(view) {
  var root = view.document.documentElement,
  ...

我花了很多时间试图以另一种方式触发事件,但是没有成功-就像使用svg容器尝试上面的代码段一样。

请记住,我无法从赛普拉斯测试中访问任何d3.js软件包,因为它已作为NPM软件包导入到React应用程序中。

在此先感谢您的帮助!

3 个答案:

答案 0 :(得分:3)

在不得不继续之前,我只能得到部分答案,但这也许可以帮助您或其他人找到最终的解决方案。

要纠正该错误,必须为view提供mousedown属性。像这样提供window,就可以正确触发D3方法:

cy.get('svg')
  .trigger('mousedown', { which: 1, force: true, view: window }) // <-- here
  .trigger('mousemove', { position: 'left', view: window })      // <-- here
  .trigger('mouseup', { position: 'left', force: true });

但是,在测试运行期间没有拖动或移动发生,其他问题也从那里出现。开始于...这是与事件一起发送的正确上下文吗?似乎是这样,因为window似乎是D3预期具有属性链的唯一上下文:

view.document.documentElement

或者这是一种反模式...一种代码气味?

追逐这些后续问题得出的结论似乎具有重要意义。

第一个问题涉及D3如何处理鼠标和拖动事件。 D3具有大量的事件监听器和回调,可以覆盖标准事件及其各自的处理程序。

第二个原因是iframes与赛普拉斯的测试跑步者一起玩。

可能是赛普拉斯的程序触发事件在赛普拉斯iframe中正确触发了,但是由于D3的激进事件处理,这些事件到应用程序iframe的转换丢失了吗?尤其是考虑到在测试视口中手动拖动圆圈效果很好。

再一次回到:

  • 是否没有在正确的上下文中调用以编程方式触发的事件?
  • 这些事件是否被D3的事件处理程序吞噬或与之碰撞?

我在一个简单的Ember应用程序中选择了Zoomable Force Directed Graph作为我的D3主题,以研究这个问题。它完美地再现了所提到的错误,因此,它肯定是D3 + Cypress的挑战,并且与前端框架无关。

我希望这项工作会有所帮助。


续...

经过进一步的阅读– Cypress's Trade-offs,尤其是他们的公开拉取请求Support for Native Browser Events –似乎赛普拉斯在D3中的事件处理优先级尚未完全协调。像drag and drop example中详细介绍的那样,更简单的实现不会带来由D3之类的第三方库引入的事件处理挑战。但是,赛普拉斯团队似乎确实正在开发这种支持。

答案 1 :(得分:0)

我使用的代码与您的代码有些不同,因此您可以尝试

cy.get('svg')
.trigger('mousedown', { which: 1 })
.trigger('dragstart', {})
.trigger('drag', {});

答案 2 :(得分:0)

尝试一下:

cy.window().then(win => {
  cy.get('svg')
    .trigger('mousedown', {
      which: 1,
      force: true,
      view: win,
    })
    .trigger('mousemove', {
      clientX: 300,
      clientY: 500,
      force: true,
    })
    .trigger('mouseup', {
      force: true,
      view: win,
    });
});

参考Jennifer Shehane's answer in this GitHub issue,对cannot read property document of undefined部分的答案是将窗口对象插入触发选项中的view中。在jacefarm的答案中提到的问题没有发生任何移动,似乎可以通过指定clientX / clientY来解决,而不是使用相对于所选元素的位置来解决。