赛普拉斯点击 Angular link 太早了
Cypress clicks Angular link too early
我有一个 Angular 应用程序,我正在 运行 E2E-Tests 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 进度条,但它对于所有测试来说都不够可靠。
另见
- Cypress Angular When Can Test Start?
您可以使用 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
我有一个 Angular 应用程序,我正在 运行 E2E-Tests 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 进度条,但它对于所有测试来说都不够可靠。
另见
- Cypress Angular When Can Test Start?
您可以使用 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