【问题标题】:Testing D3.js drag events with Cypress.js使用 Cypress.js 测试 D3.js 拖动事件
【发布时间】:2019-01-03 18:30:55
【问题描述】:

我有一个 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 });

上面的例子取自 Cypress drag and drop recipe,它在 nodrag.js 文件中产生以下错误:

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

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

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

我花了很多时间尝试以另一种方式触发事件,但没有成功 - 比如尝试使用上面的 sn-p 和 svg 容器。

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

提前感谢您的帮助!

【问题讨论】:

  • 您能否提供一些示例——甚至是指向使用相同 API 的网页的链接,我们可以在其中对其进行测试?

标签: javascript d3.js svg cypress


【解决方案1】:

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

要纠正错误,必须为mousedown 提供view 属性。像这样提供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 正在与 Cypress 测试运行器一起玩。

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

这又导致:

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

我在一个简单的 Ember 应用程序中选择了 Zoomable Force Directed Graph 作为我的 D3 主题,用于研究这个问题。它完美地重现了上面提到的错误,所以它绝对看起来是一个 D3 + Cypress 的挑战,与前端框架无关。

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


继续...

经过进一步阅读——Cypress's Trade-offs,尤其是他们的开放拉取请求Support for Native Browser Events——似乎 D3 中的事件处理覆盖在赛普拉斯中尚未完全协调。更简单的实现,如drag and drop example 中详述的那些,不会出现由像 D3 这样的第三方库引入的事件处理挑战。但是,赛普拉斯团队似乎正在开发这种支持。

【讨论】:

    【解决方案2】:

    试试这个:

    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 issuecannot read property document of undefined部分的答案是在触发选项中将窗口对象插入view。 jacefarm 的答案中提到的没有发生移动的问题似乎可以通过指定 clientX/clientY 而不是使用相对于所选元素的位置来解决。

    【讨论】:

    • 仅针对遇到我问题的其他人:各种实现可能需要额外的事件。我必须在拖放的目标上添加“鼠标悬停”。
    【解决方案3】:

    我使用的代码和你的代码有点不同,你可以试试

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      相关资源
      最近更新 更多