Gwy*_*ynn 54 javascript automation browser-automation cypress
目标: 我想使用 cypress 的辅助功能选择器单击页面上的特定元素
代码
cy.findAllByRole('rowheader').eq(2).click();
Run Code Online (Sandbox Code Playgroud)
错误
Timed out retrying: cy.click() failed because this element is detached from the DOM.
<th scope="row" data-automation-id="taskItem" aria-invalid="false" tabindex="-1" class="css-5xw9jq">...</th>
Cypress requires elements be attached in the DOM to interact with them.
The previous command that ran was:
> cy.eq()
This DOM element likely became detached somewhere between the previous and current command.
Run Code Online (Sandbox Code Playgroud)
问题: 我可以在 DOM 中看到该元素仍然存在 - 没有逻辑将该元素与 DOM 分离,并且 eq 方法当然不会这样做。此外,findAllByRow 方法显然正在工作,因为它找到了我想要单击的正确元素。怎么会说五行分离呢?对于这种情况有解决方法吗?
Ε Г*_*И О 33
这可能是个坏建议,但你能尝试以下方法吗?
cy.findAllByRole('rowheader').eq(2).click({force: true})
Run Code Online (Sandbox Code Playgroud)
Fod*_*ody 27
没有可重现的示例,这是推测性的,但请尝试使用Cypress.dom.isDetached在单击之前添加防护
cy.findAllByRole('rowheader').eq(2)
.should($el => {
expect(Cypress.dom.isDetached($el)).to.eq(false)
})
.click()
Run Code Online (Sandbox Code Playgroud)
如果期望失败,则先前的行导致分离并且cy.findAllByRole没有正确地重新查询元素。
如果是这样,你也许可以用普通的cy.get().
我也喜欢 @AntonyFuentesArtavia 使用别名的想法,因为别名机制保存原始查询,并在发现其主题分离时专门重新查询 DOM。
在这里查看我的答案
来自赛普拉斯源
const resolveAlias = () => {
// if this is a DOM element
if ($dom.isElement(subject)) {
let replayFrom = false
const replay = () => {
cy.replayCommandsFrom(command)
// its important to return undefined
// here else we trick cypress into thinking
// we have a promise violation
return undefined
}
// if we're missing any element
// within our subject then filter out
// anything not currently in the DOM
if ($dom.isDetached(subject)) {
subject = subject.filter((index, el) => $dom.isAttached(el))
// if we have nothing left
// just go replay the commands
if (!subject.length) {
return replay()
}
}
Run Code Online (Sandbox Code Playgroud)
Ant*_*via 13
不要尝试强制单击/操作,而是使用 Cypress 别名并充分利用内置的断言重试能力。
例子:
cy.get('some locator').first().find('another locator').eq(1).as('element');
cy.get('@element').should(***some assertion to be retried until met***);
Run Code Online (Sandbox Code Playgroud)
尽管我正在遍历很多元素(这可能会导致问题,因为其中一个父元素可能会分离),但最终当我在其上放置别名时,我添加了指向最终元素的直接链接在链末端产生的元素。然后,当我引用该别名时,Cypress 将重新查询最终元素,并根据添加在其顶部的任何断言根据需要重试。这确实对我防止这个独立问题有很大帮助。
小智 12
我正在运行同样的问题,运行时出现相同的错误:
cy.get('<elementId>').should('be.visible').click();
Run Code Online (Sandbox Code Playgroud)
我可以看到,当测试运行时,它找到了该元素(并突出显示了它),断言得到了验证,然后以某种方式无法.click()找到该元素,即使它是链接的。
我发现在此行之前添加静态等待几秒钟可以解决问题,但我不确定为什么我需要这样做,并且不想使用静态等待。
没有正在运行的异步任务,因此无法进行动态等待。
Ala*_*Das 11
您的问题的答案写在您收到的错误消息中:
超时重试:cy.click() 失败,因为该元素已与 DOM 分离。
...Cypress 需要将元素附加到 DOM 中才能与它们交互。
之前运行的命令是:
cy.eq()
该 DOM 元素可能在上一个命令和当前命令之间的某个位置分离。
收到此错误意味着您尝试与“死”DOM 元素进行交互 - 这意味着它已从 DOM 中分离或完全删除。因此,当 cypress 即将单击该元素时,该元素eq()要么已从 DOM 分离,要么已从 DOM 中删除。
在现代 JavaScript 框架中,DOM 元素会定期重新渲染 - 这意味着旧元素将被丢弃,并放置一个新元素。由于这种情况发生得如此之快,因此用户可能会觉得好像没有任何明显变化。但是,如果您正在执行测试命令,则您正在交互的元素可能已“死亡”。要处理这种情况,您必须:
当我们说守卫时,这通常意味着:
您可以从cypress 文档和官方 cypress 博客中阅读更多内容。
解决方案:首先确保您的元素已加载且可见,然后执行click()
cy.findAllByRole('rowheader').eq(2).should('be.visible').click();
Run Code Online (Sandbox Code Playgroud)
小智 5
发生这种情况是因为 React 重新渲染了整个页面。尝试使用一个命令查找元素:
// do this
cy.get('[role="rowheader"]:nth-ckild(2)').click();
// instead of this
cy.findAllByRole('rowheader').eq(2).should('be.visible').click();
Run Code Online (Sandbox Code Playgroud)
使用单个命令修复了 Cypress 仅重试该命令之前的最后一个命令的事实should。因此,以前仅.eq(2)会重试。然而,您cy.findAllByRole('rowheader')也需要重试。
Cypress 提出了另一种交替命令和断言的解决方案。它对我不起作用,但你可以尝试一下:
cy.findAllByRole('rowheader').should('be.visible').eq(2).should('be.visible').click();
Run Code Online (Sandbox Code Playgroud)