赛普拉斯点击 Angular link 太早了

Cypress clicks Angular link too early

我有一个 Angular 应用程序,我正在 运行 E2E-Tes​​ts with Cypress。 正常的测试将使用 cy.visit('/') 打开站点,加载后它开始使用侧边栏上的按钮在站点上导航。菜单使用的主题是 PrimeNG Ultima。

测试在我的本地开发机器上运行良好,但在 CI 中失败。 似乎赛普拉斯在 Angular 注册了处理 link 元素上的点击所需的逻辑之前触发了点击事件。

有没有办法让 cypress 知道 Angular 何时完成引导? 我更喜欢在主应用程序中没有额外代码的解决方案,但我可以在 Angular 部分中进行更改。

我已经尝试了以下代码段但没有成功:

cy.window().its('getAllAngularRootElements' as any).should('exist');
cy.window().then(win => new Cypress.Promise((resolve) => win.requestIdleCallback(resolve)));

另一种部分起作用的解决方法是监听 PrimeNG 主题中包含的 pace.js 进度条,但它对于所有测试来说都不够可靠。

另见

您可以使用 Chrome 调试器协议,如本文所述 When Can The Test Click

给出的例子是

it('clicks on the button when there is an event handler', () => {
  cy.visit('public/index.html')

  const selector = 'button#one'
  cy.CDP('Runtime.evaluate', {
    expression: 'frames[0].document.querySelector("' + selector + '")',
  })
    .should((v) => {
      expect(v.result).to.have.property('objectId')
    })
    .its('result.objectId')
    .then(cy.log)
    .then((objectId) => {
      cy.CDP('DOMDebugger.getEventListeners', {
        objectId,
        depth: -1,
        pierce: true,
      }).should((v) => {
        expect(v.listeners).to.have.length.greaterThan(0)
      })
    })
  // now we can click that button
  cy.get(selector).click()
})

其中 cy.CDP 是从此包安装的 cypress-cdp


正在重试点击

另一种方法可能是重试点击直到它生效。

确切的代码将取决于应用程序,但模式将是

const clickUntilChanged = (linkSelector, changeSelector, attempt = 0) => {

  if (attempt > 10) throw 'Something went wrong'

  cy.get(changeSelector).invoke('text')
    .then(initial => {

      cy.get(linkSelector).click()            // attempt a click  
      cy.get(changeSelector).invoke('text')
        .then(next => {
          if (initial === next) {             // no change
            cy.wait(50)                       // wait a bit then try again
            clickUntilChanged(linkSelector, changeSelector, ++attempt)
          }
          // else click was effective, just exit
        })
    })
})

clickUntilChanged('menu-item', 'page-header')

测试重试

另一种方法是使用带有重试设置的小型初始测试

it('tests the link click', {retries: {runMode: 10, openMode: 0}}, () => {
    cy.get('menu-item').click()
    cy.get('page-header')
      .should('have.text', 'new-page-header')  // fails and retries 
                                               // if click had no effect
})

稍等

查看 Gleb 的最新文章 Solve The First Click,他只是在中间添加了一个硬等待以允许事件侦听器连接。

考虑到简单性,这可能是我的首选方法,谁会注意到 CI 运行.

中多了 1 秒
cy.visit(...)
if (!Cypress.config('isInteractive')) {   // run mode
  cy.wait(1000)
}
cy.get('menu-item').click()               // should now be functioning