Reputation: 303
I try to make and E2E test with Cypress. I have to visit multiple links from a table and make an assertion after visiting the page.
In the Cypress UI I see the page is loaded, also if I check I can see the elements in the DOM. But my Cypress assertion not working, it says:
Timed out retrying after 4000ms: cy.should() failed because this element is detached from the DOM.
<div id="content" class="css-1ddoub">...</div>
Cypress requires elements be attached in the DOM to interact with them.
The previous command that ran was:
> cy.wait()
This DOM element likely became detached somewhere between the previous and current command.
My test code:
cy.get('[id="content"').parent().within(()=>{
cy.get('[data-cy="list-item"]').each(item => {
const link = item.find('a').first();
cy.visit(link.attr('href')!)
cy.wait(5000)
cy.findByText(/report herunterladen/i)
})
})
Interesting because If I hardcode the url and not use .each, then all assertions works fine after .visit().
cy.visit('/de/banks/compare/?a=calculations.average&b=ins.PL.PKO') // Hardcoded url
cy.wait(1000)
cy.findByText(/report herunterladen/i)
I tried to use cy.wait() even with a large number like 30000 but it didn't work.
For me it looks like Cypress has a bug with .each() method. It doesn't want to load pages DOM elements within the each function.
Cypress: 10.7.0
Upvotes: 4
Views: 3030
Reputation: 171
It looks like the cy.visit()
command is over-writing the links on the page.
You should issue a go-back to restore them, but also re-query the link elements inside the loop.
cy.get('[id="content"').parent().within(() => {
cy.get('[data-cy="list-item"]')
.each((_, index) => {
cy.get('[data-cy="list-item"]').eq(index) // re-query after page changes
.find('a').first().then(link => {
cy.visit(link.attr('href')!)
cy.wait(5000)
cy.findByText(/report herunterladen/i)
cy.go('back')
})
})
})
Upvotes: 3
Reputation: 569
Detached error happens when you successfully saved(e.g. using cy.get()) a DOM element into memory, and tried to access it but the page has unfortunately removed that element meanwhile. To be precise, the page has probably re-rendered(re-created the same elements).
It is OK to put cy.wait()
, but before you actually try to access the elements.
// Change this number depending on your needs
cy.wait(2000) // Let the page do it's thing
// Now try to access
cy.get('[id="content"').parent().within(()=>{
cy.get('[data-cy="list-item"]').each(item => {
const link = item.find('a').first();
cy.visit(link.attr('href')!)
cy.wait(5000)
cy.findByText(/report herunterladen/i)
})
})
The above should work, but you should review this issue on the Front-end and look deeper into the re-rendering cause.
Detached DOM element error is actually a JS error.
Upvotes: 0
Reputation: 10535
Please see this answer Traverse through a list....
To avoid detached error, use .each()
on list of urls not list of elements
cy.get('[id="content"')
.parent()
.within(() => {
cy.get('[data-cy="list-item"] a')
.then($els => [...$els].map((a) => a.href))
.each(link => {
cy.visit(link)
cy.wait(5000)
cy.findByText(/report herunterladen/i)
})
})
Upvotes: 10
Reputation: 1
Please try this!
cy.get('[id="content"').parent().within(()=>{
cy.get('[data-cy="list-item"]').each(item => {
cy.wrap(item).find('a').first().invoke('attr','href').then((href)=>{
cy.visit(href)
cy.wait(2000)
cy.findByText(/report herunterladen/i)
})
})
})
Upvotes: -1