Cypress:如何使用点击处理程序处理等待元素

Duk*_*ver 7 event-handling e2e-testing cypress

代码 I\xe2\x80\x99m 测试有很多<a>使用 href 标签呈现的标签元素,但在页面加载后不久,就会给出一些执行不同操作的点击事件(例如打开模式)。href 是一个后备,预期的行为是在单击事件中。

\n

Cypress 对于 page\xe2\x80\x99s javascript 来说通常太快,并且在事件添加到元素之前单击该元素。这会导致页面导航到默认的 href,而不是触发我想要测试的行为。这里\xe2\x80\x99s是一个例子,我使用超时来模拟慢加载的JS:

\n
<a id="reveal_cats" href="https://http.cat" >\n  Show me cats!\n</a>\n\n<div id="cats_div" style="display: none;">\n  Cats!\n</div>\n\n<script>\n  // Using a timeout to simulate a slow-loading JS file\n  // that adds a click handler\n  setTimeout(\n    () => {\n      console.log("Handler is added")\n      $("#reveal_cats").on("click", function(e) {\n        e.preventDefault();\n        $("#cats_div").show()\n      })\n    }, 3000\n  )\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n
it("fails because the click handler isn\'t loaded yet", () => {\n  cy.contains("a", "Show me cats!").click()\n  // This fails because the event handler isn\'t loaded yet\n  // so instead we\'ve navigated to http.cat\n  cy.get("#cats_div").should("be.visible")\n})\nit("passes, but uses an undesirably long hardcoded wait", () => {\n  cy.contains("a", "Show me cats!").click()\n  cy.wait(5000)\n  cy.get("#cats_div").should("be.visible")\n})\n
Run Code Online (Sandbox Code Playgroud)\n

如何让 Cypress 等待处理程序加载?

\n

我的第一个猜测是使用拦截来等待添加处理程序的JS文件,但文件名是随机生成的,因此它们\xe2\x80\x99不可靠。

\n

我的第二个猜测是尝试对元素上的事件处理程序进行断言,但我没有看到\xe2\x80\x99t 的标准断言。我想也许我可以使用 jQuery 实用程序在块中查找侦听器then(),但我不相信如果第一次尝试时发现事件不是 xe2x80x99t 就会正确重试。

\n

到目前为止,我发现的唯一可行的解​​决方案是硬编码 waits\xe2\x80\xa6

\n

Ala*_*paz 8

等待点击处理程序的最简单方法是使用cypress-cdp插件。

这是对您的示例页面的测试:

import 'cypress-cdp'

it('waiting for click event handler on link element', () => {
  cy.visit('cats.html')

  cy.get('#cats_div').should('not.be.visible')    // evaluates immediately

  cy.hasEventListeners('#reveal_cats', { type: 'click' })
  cy.get('#reveal_cats').click()

  cy.get('#cats_div', {timeout: 100})  // setting really short timeout for demo 
    .should('be.visible')
    .and('contain', 'Cats!')
})
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


编写链接版本

cy.hasEventListeners()是一个父命令,因此它不是设计为使用像cy.get().find().hasEventListeners().

在内部它使用cy.get()

// plugin source

Cypress.Commands.add('hasEventListeners', (selector, options = {}) => {
  ...
  cy.get(selector, { log: false })
Run Code Online (Sandbox Code Playgroud)

因此,您可以应用链接.within(),并且内部cy.get()将仅限于先前链接的主题。

cy.get('x').find('y')   // "root" is now 'y'
  .within(() => {
    cy.hasEventListeners('#reveal_cats', { type: 'click' })
  })
Run Code Online (Sandbox Code Playgroud)

或者你可以编写自己的命令

Cypress.Commands.add('hasEventListeners2', {prevSubject: true}, (subject, options) => {
  const selector = subject.selector
  cy.hasEventListeners(selector, options)
})

cy.get('div').find('#reveal_cats').hasEventListeners2({ type: 'click' })
Run Code Online (Sandbox Code Playgroud)

  • 我添加了几种解决该问题的方法。 (2认同)