cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.72k stars 3.16k forks source link

.should('not.exist') is not detecting that element is no longer there #25363

Open extracker-ppetrov opened 1 year ago

extracker-ppetrov commented 1 year ago

Current behavior

In 10.7.0 the code below is working fine. Once the element disappears from the page, the assertion passes.

Cypress.Commands.add('WaitForObjectWithTextToDisappear', (pageObject: string, text: string): any => {
  cy.log('Wait for the object [' + pageObject + 'with text' + text + ' to show up.')
  cy.get(pageObject).contains(text).should('exist')
  cy.log('Wait for the object [' + pageObject + '] to close.')
  cy.get(pageObject).contains(text).should('not.exist')
})

In 12.3.0 the code above is no longer working as expected. Even thou the element is no longer on the page, the assertion fails and reports that it is still there.

Desired behavior

.should('not.exist') works in 12.3.0 the same way as it was in 10.7.0

Test code to reproduce

Cypress.Commands.add('WaitForObjectWithTextToDisappear', (pageObject: string, text: string): any => {
  cy.log('Wait for the object [' + pageObject + 'with text' + text + ' to show up.')
  cy.get(pageObject).contains(text).should('exist')
  cy.log('Wait for the object [' + pageObject + '] to close.')
  cy.get(pageObject).contains(text).should('not.exist')
})

Cypress Version

10.3.0

Node version

18.12.1

Operating System

Windows 10

Debug Logs

No elements in the current DOM matched your query:

  > cy.get(div[role="dialog"] h5)
      at isElement (https://staging.extracker.co/__cypress/runner/cypress_runner.js:151854:70)
      at validateType (https://staging.extracker.co/__cypress/runner/cypress_runner.js:151712:14)
      at Object.isType (https://staging.extracker.co/__cypress/runner/cypress_runner.js:151743:7)
      at <unknown> (https://staging.extracker.co/__cypress/runner/cypress_runner.js:139050:22)
      at Object.subjectFn (https://staging.extracker.co/__cypress/runner/cypress_runner.js:149750:16)
      at $Cy.verifyUpcomingAssertions (https://staging.extracker.co/__cypress/runner/cypress_runner.js:131027:31)
      at onRetry (https://staging.extracker.co/__cypress/runner/cypress_runner.js:149741:15)
      at tryCatcher (https://staging.extracker.co/__cypress/runner/cypress_runner.js:8914:23)
      at Promise.attempt.Promise.try (https://staging.extracker.co/__cypress/runner/cypress_runner.js:6188:29)
      at whenStable (https://staging.extracker.co/__cypress/runner/cypress_runner.js:146641:65)
      at <unknown> (https://staging.extracker.co/__cypress/runner/cypress_runner.js:146082:14)
      at tryCatcher (https://staging.extracker.co/__cypress/runner/cypress_runner.js:8914:23)
      at Promise._settlePromiseFromHandler (https://staging.extracker.co/__cypress/runner/cypress_runner.js:6849:31)
      at Promise._settlePromise (https://staging.extracker.co/__cypress/runner/cypress_runner.js:6906:18)
      at Promise._settlePromise0 (https://staging.extracker.co/__cypress/runner/cypress_runner.js:6951:10)
      at Promise._settlePromises (https://staging.extracker.co/__cypress/runner/cypress_runner.js:7031:18)
      at Promise._fulfill (https://staging.extracker.co/__cypress/runner/cypress_runner.js:6975:18)
      at <unknown> (https://staging.extracker.co/__cypress/runner/cypress_runner.js:8589:46)
  From Your Spec Code:
      at Context.eval (webpack:///./cypress/support/commands-object-actions.ts:256:36)

Other

https://www.loom.com/share/042330356ebb48f19998456ddff4c7aa

kpratik0912 commented 1 year ago

Facing same issue randomly. For me should("not.exist) fails its in afterEach hook when main test fails.

nagash77 commented 1 year ago

Hi @extracker-ppetrov ! I'm sorry to hear you are having difficulties running Cypress. This seems potentially related to Detached DOM changes we made in Cy12. Have you already read our Guide on Retry-ability? There are some changes to the way we suggest folks chain their commands in tests.

If you still feel this is a problem with Cypress we will need a reproducible example from which our devs can replicate the problem internally to be able to properly diagnose the issue. Here are some tips for providing a Short, Self Contained, Correct, Example and our own Troubleshooting Cypress guide.

extracker-ppetrov commented 1 year ago

Hi @nagash77 , I did some more testing between 10.7.0 and 12.3.0

The problem seems to be only with the last part of my command, where I am trying to check if an object with text does not exist in the DOM.

cy.get(pageObject).contains(text).should('not.exist')

Again, this is working in the 10.7.0 version. But in 12.3.0 it fails. My scenario is that a message appears on the screen for about 5 seconds. I would like to check when the message is no longer in the DOM, so I can do my next action. If I break it down like this: cy.get(pageObject) cy.get(pageObject).contains(text) cy.get(pageObject).contains(text).should('not.exist')

The first two rows pass because the message is still on the page. But the last row is the one that fails to detect that the message is no longer in the DOM. It is executed while the message is still on the screen. My defaultwaitoncommand is 10 seconds and the message is on the screen 5 sec. So once the message is closed, the assertion should pass.

If I do the check without the contains() part, then cypress successfully detects that the message is no longer in the DOM. So this code works:

cy.get(pageObject).should('not.exist')

this code works too:

cy.contains(pageObject, text).should('not.exist')

but this does not:

cy.get(pageObject).contains(text).should('not.exist')

This is what does not make sense to me. Why is the contains() breaking the assertion, when used between get() and should()?

MaksimYaginov commented 1 year ago

Hi @ extracker-ppetrov! Faced the same problem

BlueWinds commented 1 year ago

There must be something extra going on here, which is why we're asking for a reproducible example. Consider the following test:

it('works?', () => {
  cy.visit('http://example.cypress.io')

  setTimeout(() => {
    cy.$$('h1').remove()
  }, 1000)

  cy.get('div').contains('Kitchen Sink').should('not.exist')
})

Here we have a .get().contains().should('not.exist') which fails for the first second, then passes once the element matching .contains() is removed from the page.

There has been some changes in behavior from 10.x -> 12.x - namely, we always re-query from the start of the query chain. So this test will pass in 10.x and fail in 12.x:

it.only('changed in Cy12', () => {
  cy.visit('http://example.cypress.io')

  setTimeout(() => {
    cy.$$('.dropdown a').remove()
  }, 1000)

  cy.get('div').contains('Commands').should('not.exist')
})

At first, it locates the <a>Commands</a> in the navigation bar - then after a second this element disappears, but .get().contains() then matches the <h2>Commands</h2>. This could be the change you're running into - the solution would be to use a more precise selector to locate the element you want to not exist.

extracker-ppetrov commented 1 year ago

@BlueWinds @nagash77 You can create a free account at Extracker.com and use the following test, setting your user and pass:

  describe("Create New Project." + Date().toLocaleString(), () => {

    it("EX-3332 - Create a projct in General Contractor Company as Project Manageer." + Date().toLocaleString(), function () {

      cy.visit("/auth/login?redirect=/");
        cy.log("Logging in General Contractor Company as PM.") 

        cy.get("#username").last().should("exist").last().clear({force: true}).last().type("<user>");
        cy.get("button[name=action]").first().should("exist").click();

        cy.get("#password").last().should("exist").last().clear({force: true}).last().type("<password>");
        cy.get("button[name=action]").first().should("exist").click();

        cy.log("Logged in GC Company as PM.")
        cy.log("Creating project.")

        cy.get("button[data-cy='add-new-button']").first().should("exist").click();
        cy.get("li:nth-child(1) div:nth-child(1)").first().should("exist").click();
        cy.get("#title").should("exist").first().clear({force: true}).first().type("12.03.0");
        cy.get("#address").should("exist").first().clear({force: true}).first().type("123 Test Street");
        cy.get("#city").should("exist").first().clear({force: true}).first().type("Test City");
        cy.get(".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth").first().should("exist").click({ force: true,  multiple: true });

        cy.log('Wait for the object [' + "div[role='alert']" + 'with text' + "Succesfully created project!" + ' to show up.');
        cy.get("div[role='alert']").contains("Succesfully created project!").should('exist');
        //cy.get("div[role='alert']").should('have.text', "Succesfully created project!")
        cy.log('Wait for the object [' + "div[role='alert']" + '] to close.');
        cy.get("div[role='alert']").contains("Succesfully created project!").should('not.exist');

        // cy.get("div[role='alert']")
        // cy.contains("div[role='alert']","Succesfully created project!").should('not.exist')
    });
  });
BlueWinds commented 1 year ago

Test is failing for me for an unrelated reason.

image

Occurs after clicking 'Continue' on the login page. Possible I signed up as the wrong account type? I know nothing about the application or what I should be doing here. :woman_shrugging:

extracker-ppetrov commented 1 year ago

You can use this in exceptions.ts file in your ./cypress/support folder. And import it in e2e.ts:

/cypress/support/exceptions.ts

Cypress.on('uncaught:exception', (err, runnable) => { console.warn(err); if (err.message && err.message.startsWith("Uncaught Error: [OneDriveSDK Error]")) { cy.log('Cypress detected uncaught exception: ', err); cy.pause() return false; } return false })

/cypress/support/e2e.ts

import './exceptions'

nagash77 commented 1 year ago

Hi @extracker-ppetrov , it would be helpful to have a simpler example of the behavior you are seeing that is not reflective of intended changes in behavior as @BlueWinds mentioned in this comment. Is the behavior you are seeing not consistent with our documentation?

extracker-ppetrov commented 1 year ago

@nagash77 Unfortunately, I cannot provide you with a simpler example. As you can see I am not the only one facing the issue. LINK

The behavior is not consistent with Cypress's documentation.

Expected Behavior: If an element that contains text, exists in the DOM and the following command is executed: cy.get("objectLocator]").contains("TEXT").should('not.exist'); If the element disappears from the DOM within the set command timeout in cypress.config.ts the assertion should(not.exist) should pass.

Actual Behavior: If an element that contains text, exists in the DOM and the following command is executed: cy.get("objectLocator]").contains("TEXT").should('not.exist'); If the element disappears from the DOM within the set command timeout in cypress.config.ts the assertion should(not.exist) fails.

aram-bigid commented 1 year ago

Hi, Experiencing almost the same issue. In my tests i'm trying to assert than an element does not exist on page cy.get('wahtever').should('no.exist') fails for all tests once upgrading to 12.x When downgraded to 11.3.0 same tests passed

AtofStryker commented 1 year ago

@extracker-ppetrov I created a reproduction repository here with the steps you've described and have been able to reproduce this issue, though I would like to see if we can have a simpler reproduction.

@aram-bigid are you able to provide a reproduction repository to help us narrow down this issue?

jlozanog commented 1 year ago

@AtofStryker Has there been any update about this issue?

AtofStryker commented 1 year ago

@jlozanog no updates as of yet. I don't believe this is prioritized at the moment. One thing that I think could help a lot is a simple reproduction since getting the current one set up is somewhat involved, which might help speed up a fix.

manny1206 commented 1 year ago

Hi. We have this same issue. cy.get("some selector").should("not.exist") fails even if it is not in the document at all. Is there some assertion for if the element never exists from the start? I'm wondering if that would be needed for this case

mikoca commented 8 months ago

Same here, I have latest version.

faebeee commented 2 weeks ago

Any updates here? I've also the same issue currently