Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cy command chain not repeating until assertion fulfilled #1210

Closed
shcallaway opened this issue Jan 19, 2018 · 6 comments
Closed

Cy command chain not repeating until assertion fulfilled #1210

shcallaway opened this issue Jan 19, 2018 · 6 comments

Comments

@shcallaway
Copy link

shcallaway commented Jan 19, 2018

  • Operating System: macOS High Sierra 10.13.2
  • Cypress Version: 1.0.3
  • Browser Version: Chrome 63

Is this a Feature or Bug?

Bug

Current behavior:

My cy command chain is not repeating until the chained assertion is fulfilled, as the documentation suggested it would.

I have a page where users can view their credit cards and change default payment method. My test involves changing the default payment card and asserting that the credit cards swap places (putting the default first).

But here's the thing: It takes a moment for the credit cards to re-render. So cy.get("credit-card") is grabbing the old credit card DOM elements (which are in the wrong order) and then passing them to the first chainer.

The first chainer gets repeated, as one would expect, but not the whole command chain.

Desired behavior:

The whole cy command chain should be repeated until the chained assertion is fulfilled.

How to reproduce:

N/A

Test code:

This code works...

cy.get("credit-card:first")
    .should("contain", "4242");

This code does not...

cy.get("credit-card")
    .first()
    .should("contain", "4242");

Additional Info (images, stack traces, etc)

@jennifer-shehane jennifer-shehane added type: unexpected behavior User expected result, but got another pkg/driver This is due to an issue in the packages/driver directory stage: ready for work The issue is reproducible and in scope labels Jan 19, 2018
@bahmutov
Copy link
Contributor

@shcallaway you are describing what @brian-mann and I have argued at length many times already. Currently Cypress retries the last query method before an assertion, not the entire query chain.

In the first situation you have 1 query .get('credit-card:first') that is retried until assertion contain 4242 passes. In the second situation you get a list of card elements, then get the first item and retry getting first element until it contains "4242". But React and other frameworks will blow away the entire list when putting new cards there. But we never "re-get" the list - we already got it! We are only retrying getting the first element of the same old list ... which goes nowhere.

So there are two solutions that we see. First, the bad news - implementing retrying of the entire query chain is going to be hard. Second, the good news. If you use single query before assertion it works. So a rule of thumb - alternate query with assertions. For example, in your test you might have no cards initially, then 2 cards and then number "4242". I would write this as

cy.get('credit-card') // query
    .should('have.length', 2) // assertion
    .first() // query
    .should('contain', '4242') // assertion

If you are swapping order of cards, you might expect some intermediate view, right? So in this case I would do the following

// view two cards
cy.get('credit-card')
    .should('have.length', 2) 
    .eq(1) // second card
    .click() // make default
// all cards are removed by the UI
cy.get('credit-card')
    .should('have.length', 0)
// now make sure the 4242 card is shown first
cy.get('credit-card') // query
    .should('have.length', 2) // assertion
    .first() // query
    .should('contain', '4242') // assertion

@jennifer-shehane jennifer-shehane removed stage: ready for work The issue is reproducible and in scope pkg/driver This is due to an issue in the packages/driver directory labels Jan 22, 2018
@vjau
Copy link

vjau commented Jul 14, 2018

This should be in the FAQ.

@jennifer-shehane
Copy link
Member

I created a new issue in our docs to document add this behavior to the FAQ here: cypress-io/cypress-documentation#809. Our documentation is open source and contributions are welcome. 😄

@johnnysprinkles
Copy link

I'm running into this issue as well... seems like we need a general way to group multiple commands into a single "retry group."

@tnrich
Copy link
Contributor

tnrich commented Apr 8, 2020

@jennifer-shehane @bahmutov why not add a way to rerun chains of cy commands back up the stack? This is far and away the largest source of flake in our tests: elements being rerendered and detached from the dom and the commands not being smart enough to rerun.

Here is a very simplified version of what I'm suggesting:

Say you want to click a button that is next to a label with text:

<div>I'm a label</div>
<button>Ok</button>

And I want to get the button based on the label text:

cy.contains("div", "I'm a label").siblings().find("button").click({retryChain: true}) //retryChain=true would cause the commands linked in this chain to be retried!

Maybe the button hasn't rendered by the time the label shows up, or maybe it has been re-rendered and detached from the dom. Why not add an option to retry the whole chain leading up to the click? Can you explain to me why that is technically impossible? Because if it is possible I think we should do it!

Thank you!

@jennifer-shehane jennifer-shehane removed the type: unexpected behavior User expected result, but got another label Apr 14, 2020
@jennifer-shehane
Copy link
Member

There's an existing thread about retrying chains here: #3561

@cypress-io cypress-io locked and limited conversation to collaborators Apr 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants