cypress: cy.get().contains() does not accept new DOM elements
Current behavior:
- When
cy.get().contains()
is called,.contains()
will only wait for the DOM elements that existed duringcy.get()
. Newly created DOM elements will not be checked against.contains()
. .get().contains()
works fine in when there is only one result for the.get()
. But as soon as there is a list of generated items,.get().contains()
is no longer working as previously and race conditions start to occur. The reason is not obvious but this is a reason for tests to become flaky over time.
Desired behavior:
-
cy.get()
should accept new DOM elements while.contains()
has not finished. I expect it to work likecy.get().should('contain', '...');
. -
Also the documentation misses the hint of this significant behavior difference.
Steps to reproduce:
HTML
<div class="myDiv">Div1</div>
<div class="myDiv">Div2</div>
<div class="replaceMe">Div3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
setTimeout(() => {
$("div.replaceMe").replaceWith('<div class="myDiv">Expectation</div>');
}, 4000);
</script>
Cypress Test
describe('test', () => {
it('should work', () => {
cy.visit('http://localhost:8080/cy.html');
cy.get('.myDiv').contains('Expectation');
});
});
Result:
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 20
- Comments: 19 (5 by maintainers)
cy.contains('.myDiv','Expectation')
works as expected and succeeds.I still see the current behavior as an issue, especially because
.get().contains()
works fine in most cases where there is only one result for the.get()
As soon as there is a list of generated items,
.get().contains()
is no longer working as expected and race conditions occur. Also the reason is not obvious.Just for the record - this behavior is documented here: https://docs.cypress.io/guides/core-concepts/retry-ability.html
This should be improved or resolved completely in Cypress 12 with the introduction of queries and major changes in the way Cypress retries commands.
I’m going to close this as resolved; if you’re still experiencing similar issues in Cy 12+, please open a new issue or leave a comment here telling me what I’ve missed!
This is a major reason for flaky tests as not every developer is fully aware of this behavior. Is there an update on this issue? @jennifer-shehane
for me it is quiet confusing that it works with
.should
but not with.contains
…think the cypress docu is not right… if u take a look at the
.should
command, it is described as it works “will continue to retry its specified assertions until it times out” ( https://docs.cypress.io/api/commands/should.html#Timeouts ) …also
.contains
is described simular “.contains() can time out waiting for the element(s) to exist in the DOM.” (https://docs.cypress.io/api/commands/contains.html#Timeouts) which works as expected, when it is NOT chained to other commands… which is imo very critical…I read some time ago a post concerning this, and the author encouraged the use of
cy.contains('element', 'text')
for cases like yours.Can you try with
cy.contains('.myDiv','Expectation')
?@BlueWinds can you elaborate on how this should be fixed in cypress 12+? the changelog does not mention any related changes to the existing selector handling and it does not mention any new query api. https://docs.cypress.io/guides/core-concepts/retry-ability has been reworked but misses the problem that I mentioned
In our experience, using the
cy.contains('.my-element', 'My Text')
form is best:This struck me today. Took 2h’s of reading docs, then finding this thread, to get it working. I consider this a weak spot of cypress, not being clear in documented behaviour being the most severe issue, the actual behaviour too being non-intuitive.
Expected behaviour (unless very clearly documented): .get should re-query the DOM on every retry, regardless of how many chained calls are postpended to the get call.
I ran into similar situation and my solution is to set a buffer to check the amount of the element first and then use
cy.get().contains()
to get the element that I actually need.cy.get(selector).should("have.length", 5) cy.get(selector).contains("target").click()
cy.get(selector).should("have.length", 5)
will make sure that I got the correct amount of elements that I’m expecting and then I can get the element that contains “target” string.@haveaguess Cypress retries the last command with its assertions, not the entire chain. The Retry-ability guide talks a lot about how to merge commands or add an assertion in between to ensure each step finishes when you want it to.
I’m coming across this problem a lot in a SPA when the data isn’t ready yet. It means we can’t use
.eq
reliably and have to resort to using:nth-child
selectors.