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

Retry mechanism of 'should' can erroneously cause the arguments to .should() to be null when cy.log() in fn #8346

Closed
GCHQDeveloper911 opened this issue Aug 19, 2020 · 4 comments
Labels
existing workaround stage: ready for work The issue is reproducible and in scope type: bug

Comments

@GCHQDeveloper911
Copy link
Contributor

GCHQDeveloper911 commented Aug 19, 2020

Current behaviour:

If I want to assert an element doesn't exist in the DOM, I have the option of simply doing something like:

cy.get('#notFound').should('not exist');

However, in the logging, this simply returns a rather crude Expected null not to exist. In my view, a better way of doing the assertion is:

cy.get('#notFound').should((elem) => {expect(elem).to.not.exist})

Which produces a log of Expected #notFound to not exist - which is far more informative.

However, I've discovered that if I then try and do more within the 'should' block, Cypress fails, reporting that it DID expect to find the element:

cy.get('#notFound').should((elem) => {expect(elem).to.not.exist; cy.log('As we thought, it is not there')})

This produces 'Timed out retrying: Expected to find element: #notFound , but never found it.'

Similarly, the following works:

cy.get('#thisElemIsFound').should((elem) => {expect(elem).to.exist})

Yet the following returns 'expected null to exist'

cy.get('#thisElemIsFound').should((elem) => {expect(elem).to.exist; cy.log('As we thought, it is there')})

Desired behavior:

All the following statements should pass - the only difference being, the last two should produce the cy.log statements. In summary, it should be possible to do more than just a simple expect statement within the should block.

cy.get('#notFound').should((elem) => {expect(elem).to.not.exist;})
cy.get('#thisElemIsFound').should((elem) => {expect(elem).to.exist;})
cy.get('#notFound').should((elem) => {expect(elem).to.not.exist; cy.log('As we thought, it is not there')})
cy.get('#thisElemIsFound').should((elem) => {expect(elem).to.exist; cy.log('As we thought, it is there')})

Test code to reproduce

Please see above - obviously you'll need to substitute the selectors as appropriate!

Versions

Cypress 12.1, CentOS 8, Chrome 83.

@jennifer-shehane
Copy link
Member

Yeah, this is definitely incorrect behavior. Just to remove the concept of negating the assertions, the code below demonstrates the problem with just checking existence alone.

This seems to have always been the behavior, went back to Cypress 3.4.1.

Repro

<html>
<body>
  <div id="thisElIsFound">El</div>
</body>
</html>
it('test', () => {
  cy.visit('index.html')

  cy.get('#thisElIsFound').should((el) => { 
    expect(el).to.exist // passes, element exists
  })

  cy.get('#thisElIsFound').should((el) => {
    expect(el).to.exist // fails, expected null to exist
    cy.log('As we thought, it is there')
  })
})

Screen Shot 2020-08-20 at 3 40 18 PM

The el is initially defined, but then on the next retry, the el is null.

Screen Shot 2020-08-20 at 3 45 56 PM

@cypress-bot cypress-bot bot added the stage: ready for work The issue is reproducible and in scope label Aug 20, 2020
@jennifer-shehane jennifer-shehane changed the title Retry mechanism of 'should' can erroneously break the test on when asserting element does (not) exist Retry mechanism of 'should' can erroneously cause the arguments to .should() to be null Aug 20, 2020
@jennifer-shehane jennifer-shehane changed the title Retry mechanism of 'should' can erroneously cause the arguments to .should() to be null Retry mechanism of 'should' can erroneously cause the arguments to .should() to be null when cy.log() in fn Dec 3, 2020
@jennifer-shehane
Copy link
Member

Another example of this bug found in #9435

The cy.log() runs twice.

it('test', () => {
  cy.get('div').should(($element) => {
    cy.log($element)
  })
})

Screen Shot 2020-12-03 at 3 23 53 PM

@sainthkh
Copy link
Contributor

sainthkh commented Dec 23, 2020

The command is run twice because the should callback function uses Promise internally. It returns Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise. error.

The workaround is to use Cypress.log() function directly like below:

it('test', () => {
  cy.visit('fixtures/a.html')

  cy.get('#thisElIsFound').should((el) => {
    expect(el).to.exist
    Cypress.log({
      displayName: 'log',
      message: 'As we thought, it is there',
    })
  })
})

If you don't want to use Cypress.log, then you can change should with then:

it('test', () => {
  cy.visit('fixtures/a.html')

  cy.get('#thisElIsFound').then((el) => {
    expect(el).to.exist
    cy.log('As we thought, it is there')
  })
})

@BlueWinds
Copy link
Contributor

Closing this as duplicate of #22587, which now has an associated PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
existing workaround stage: ready for work The issue is reproducible and in scope type: bug
Projects
None yet
Development

No branches or pull requests

4 participants