【问题标题】:Testing onclick events on SVG with Cypress使用 Cypress 在 SVG 上测试 onclick 事件
【发布时间】:2018-09-16 01:00:04
【问题描述】:

我正在使用 Cypress 测试一个 d3 应用程序。在测试中,我想确保在单击 SVG 元素中的圆圈时调用特定的函数。当我手动单击时调用该函数,但我编写的测试失败了,所以我假设我在测试的某个地方犯了错误。 这是我现在的测试代码:

import * as app from "../../app";

describe("Scatter plot", () => {
  before(() => {
    cy.visit("http://localhost:1234");
  });
  it("Triggers the displayMovieInfo on click", () => {
    const displayMovieInfo = cy.spy(app, "displayMovieInfo");
    cy.get("#scatterPlot")
      .get("circle")
      .eq(0)
      .click({ force: true });

    expect(displayMovieInfo).to.be.called;
  });
});

我从赛普拉斯得到的输出:

预计 displayMovieInfo 至少被调用过一次,但它 从未被调用过

任何帮助将不胜感激!

更新: 我相信点击之前可能没有起作用,因为当柏树试图点击它时圆圈不存在。通过添加“等待 cy.wait(1000);”在单击操作之前,调用该函数(我可以看到结果和从其中记录的消息)。可悲的是,测试仍然失败。

更新 2: 我将测试改为使用 window 对象(见下文),但断言仍然失败(测试本身成功,这也不是一件好事)。

 cy.window()
      .then(window => {
        displayMovieInfoSpy = cy.spy(window, "displayMovieInfo");
        cy.get("#scatterPlot")
          .get("circle")
          .eq(2)
          .click({ force: true })
          .as("clicking");
        expect(displayMovieInfoSpy).to.be.called;
      });

更新 3: 似乎d3和parcel.js的结合导致测试失败。当单独使用 d3 或 parcel.js 时,测试工作得很好。 另外,expect 语句应该在 click 动作之后的 then 块中。

【问题讨论】:

    标签: javascript testing d3.js ui-testing cypress


    【解决方案1】:

    您似乎是直接在测试中导入 app 变量。此对象与浏览器上的对象不同。您应该创建一个全局变量(或方法)来直接从浏览器获取您的应用变量

    cy.window().its('app').then((app) => { 
       // your test with app var
    })
    

    您可能还想使用 then() 条件来确保它在之后检查它。但这可能不是必需的。

    .click({ force: true }).then(() => {
       expect(displayMovieInfo).to.be.called;
    });
    

    【讨论】:

    • 感谢保罗的回复!不幸的是,我的 window 对象上没有 displayMovieInfo 属性,可能是因为我正在使用 parcel 为我的应用程序提供服务。这种情况有解决办法吗?
    • 我手动将 displayMovieInfo 绑定到窗口对象,现在它是窗口对象的一个​​属性。 app 属性不存在,所以我稍微修改了您的代码(请参阅原始帖子更新中的结果),但没有运气 =(
    • 我认为“expect”方法在cypress“get”方法之前执行。你应该试试这个: .click({ force: true }).then(() => { expect(displayMovieInfo).to.be.call; }); (查看我第一次回复的第二个代码)
    • 即使期望失败,它也只是使测试通过 =(
    【解决方案2】:

    我认为您对 cypress 的工作原理主要有几个概念问题。

    第一次点击只能在一个元素上,第二次是关于如何使用别名。

    我放的这段代码就像一个魅力,希望它能帮助你了解别名、应该、点击和间谍的概念。

    d3test.spec.js

    describe("Scatter plot", () => {
    before(() => {
      cy.visit("http://localhost/d3test");
    });
    it("Triggers the displayMovieInfo on click", () => {
        cy.window()
        .then(window => {
          let displayMovieInfoSpy = cy.spy(window, "displayMovieInfo");
    
          cy.get("#scatterPlot").get("circle").as('circles')
    
          cy.get('@circles').should('have.length', 1)
    
          cy.get('@circles').click({ force: true })
            .then(() => {
                expect(displayMovieInfoSpy).to.be.called;
            })
        });
    });
    });
    

    index.html

    <svg id="scatterPlot">
        <circle cx="50%" cy="50%" r="100" fill="blue" onclick="displayMovieInfo()"></circle>
    </svg>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script>
        window.displayMovieInfo = function(){
            console.log(1);
        }
    </script>
    

    如果您遇到更多麻烦,我建议您使用 cy.log() 和调试器控制台一一尝试。

    【讨论】:

    • 谢谢保罗!我想我弄清楚了问题所在(请参阅原始帖子的更新)。 .eq(2) 正在从数组中挑选第三个圆圈,所以那部分很好。我确实需要将断言移到 .then 块中,你在那个部分是对的。非常感谢您的帮助!
    猜你喜欢
    • 2016-07-12
    • 2012-09-08
    • 2021-11-09
    • 2022-12-15
    • 2020-01-13
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 2019-08-18
    相关资源
    最近更新 更多