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

Test passes but log shows a failed assert #9155

Open
JessefSpecialisterren opened this issue Nov 10, 2020 · 9 comments
Open

Test passes but log shows a failed assert #9155

JessefSpecialisterren opened this issue Nov 10, 2020 · 9 comments
Labels
E2E Issue related to end-to-end testing pkg/driver This is due to an issue in the packages/driver directory topic: assertions ✔️ Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team. type: unexpected behavior User expected result, but got another

Comments

@JessefSpecialisterren
Copy link

JessefSpecialisterren commented Nov 10, 2020

Current behavior

Under certain circumstances, Cypress shows a test as passed even though the log contains a failed assert:
image

Desired behavior

In this particular case, the failed assert should not be shown. It was not executed in the invocation of the should callback that made the test succeed, because the third li element had been removed by that time.

Test code to reproduce

index.html

<body>
  <ul>
    <li>foo</li>
    <li>foo</li>
    <li>bar</li>
  </ul>
  <script>
    setTimeout(() => {
      document
        .querySelector('li:last-child')
        .remove()
    }, 1000)
  </script>
</body>

spec.cy.js

it('all li elements have text "foo"', () => {
  cy.visit('index.html')
  cy.get('li').should(($lis) => {
    $lis.each((_, element) => {
      expect(element.textContent).to.equal('foo')
    })
  })
})

Versions

Cypress: 12.12.0
Node: v16.16.0
Browser: Chrome 113
OS: Windows 10.0.19044.2965

@jennifer-shehane
Copy link
Member

Thanks for the simple example. I can see that the async nature of the app code will cause this situation where Cypress passes the test, and then updates the last assertion to fail.

Reproducible example

index.html

<body>
  <ul>
    <li>foo</li>
    <li>foo</li>
    <li>bar</li>
  </ul>
  <script>
    setTimeout(() => {
      document
        .querySelector('li:last-child')
        .remove()
    }, 1000)
  </script>
</body>

`spec.js

it('all li elements have text "foo"', () => {
  cy.visit('index.html')
  cy.get('li').should(($lis) => {
    $lis.each((_, element) => {
      expect(element.textContent).to.equal('foo')
    })
  })
})

Workaround

The ideal way to write this test would be to assert first that the removed element doesn't exist first:

it('all li elements have text "foo"', () => {
  cy.visit('index.html')
  cy.get('li').should('have.length', 2).and(($lis) => {
    $lis.each((_, element) => {
      expect(element.textContent).to.equal('foo')
    })
  })
})

@cypress-bot cypress-bot bot added the stage: needs investigating Someone from Cypress needs to look at this label Nov 10, 2020
@jennifer-shehane jennifer-shehane added type: unexpected behavior User expected result, but got another stage: needs investigating Someone from Cypress needs to look at this pkg/driver This is due to an issue in the packages/driver directory and removed stage: needs investigating Someone from Cypress needs to look at this labels Nov 10, 2020
@bahmutov
Copy link
Contributor

Yeah, this is unexpected. Once the test completes, the assertions should not change their state. In this particular case I would make sure the expected number of assertions has passed as described in https://www.cypress.io/blog/2020/01/16/when-can-the-test-stop/

@JessefSpecialisterren
Copy link
Author

Note that the real-world testcase that lead to this report types text into a filter field and checks if the filtered list only has elements containing the filter text. The number of results (and hence the number of assertions) is not known beforehand, so the proposed workarounds won't work

@bahmutov
Copy link
Contributor

Sure they will. It is just that the test has no idea when the application updates itself and when the test should finish. What if the app updates itself after 10 seconds? Or 15 seconds? So you have to observe something for the test to "know" when it can check the filtered results. Worst comes to worst, you can always add cy.wait(20000) before asserting the filtered results. I would do things a little differently - I would use cy.route2 to spy on the network request, once the network call returns I could look at the number of returns results and then check the DOM. Now you know how many results to expect and can verify it before checking each shown item.

@JessefSpecialisterren
Copy link
Author

I settled for this workaround:

it('all li elements have text "foo"', () => {
  cy.visit('index.html')
  cy.get('li').should(($lis) => {
    let nonFoo = []
    $lis.each((_, element) => {
      if (element.textContent !== 'foo') nonFoo.push(element)
    })
    expect(nonFoo, 'non-foo lis').to.be.empty
  })
})

Though I agree with @bahmutov that in general, it would be better to wait until the DOM is stable. My current project is effectively black box testing, however, so I prefer a solution that only looks at the html

@cypress-app-bot
Copy link
Collaborator

This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.

@cypress-app-bot cypress-app-bot added the stale no activity on this issue for a long period label May 17, 2023
@JessefSpecialisterren
Copy link
Author

Verified the behavior is still occuring and updated the test code

@nagash77
Copy link
Contributor

@JessefSpecialisterren thank you for confirming this issue is still happening. I will update the ticket.

@nagash77 nagash77 removed the stale no activity on this issue for a long period label May 19, 2023
@chrisbreiding
Copy link
Contributor

I replicated this issue in the latest version of Cypress and will forward this ticket to the appropriate team. They will evaluate the priority of this ticket and consider their capacity to pick it up. Please note that this does not guarantee that this issue will be resolved.

@chrisbreiding chrisbreiding removed their assignment May 22, 2023
@chrisbreiding chrisbreiding added E2E Issue related to end-to-end testing Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team. topic: assertions ✔️ and removed stage: needs investigating Someone from Cypress needs to look at this labels May 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E2E Issue related to end-to-end testing pkg/driver This is due to an issue in the packages/driver directory topic: assertions ✔️ Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team. type: unexpected behavior User expected result, but got another
Projects
None yet
Development

No branches or pull requests

6 participants