374

I want to be able to click on a check box and test that an element is no longer in the DOM in Cypress. Can someone suggest how you do it?

// This is the Test when the checkbox is clicked and the element is there

cy.get('[type="checkbox"]').click();
cy.get('.check-box-sub-text').contains('Some text in this div.')

I want to do the opposite of the test above.

So when I click it again the div with the class check-box-sub-text should not be in the DOM.

SSpall
  • 139
  • 1
  • 8
Maccurt
  • 12,655
  • 7
  • 32
  • 43
  • 1
    I like cypress because for the most part it is easy and it just works. I get the issue with it only being used in Chrome, but for me I can live with that. – Maccurt Nov 11 '18 at 20:12
  • `cy.get('.check-box-sub-text').contains('Some text in this div.')` in some cases might not work (on some devices). You can replace it with `cy.contains('.check-box-sub-text', 'Some text in this div.')` it will work in same way. – ulou Jan 03 '19 at 10:15
  • 2
    I think you should clarify the question to "test if element is removed". Otherwise it's confusing with another question, "test if element was never there". The technical implications, and answers, are different depending on the case. – Eric Burel Jun 10 '20 at 12:36
  • @alexrogers sometimes you don't need cross browser testing, but just spin up some quick end to end tests. This is specially helpful for small teams that cannot afford testing all the browsers, but barely can support e2e. – chesscov77 Jul 30 '20 at 08:03
  • @alexrogers: If you develop Android apps, Chrome is all you need ;-) Adaption to different targets brings more complexity and potential bugs... Also: there should be no need to test if your target is implemented correctly (that's the duty of the developers of said target). You should only need to test your own code ... That's the theory at least ... – Fred Dec 07 '21 at 10:20

17 Answers17

509

Well this seems to work, so it tells me I have some more to learn about .should()

cy.get('.check-box-sub-text').should('not.exist');
Maccurt
  • 12,655
  • 7
  • 32
  • 43
  • 13
    HI! I am using pretty much the same code: `cy.get(data-e2e="create-entity-field-relation-contact-name").should('not.exists')` but it fails on `get` and then tries to invoke `should` several times, each of which fails... any idea what am I doing wrong? Thanks in advance – volk Nov 08 '18 at 10:30
  • Sorry I just saw your comment, is your selector working on a data attribute? Can you paste your html in the comments? That selector looks odd to me! – Maccurt Nov 08 '18 at 21:32
  • @volk I think `cy.get('[data-e2e="create-entity-field-relation-contact-name"]').should('not.exists')` should work. – YingYang Nov 13 '18 at 07:08
  • 12
    @Maccurt, @YingYang : actually I found the mistake, and it was kind of silly: there is redundant `s` in should: `.should('not.exists')` -> `.should('not.exist')` – volk Nov 14 '18 at 12:39
  • Instead of should() is it possible to wrap above condition in if loop? Thanks – user2451016 May 22 '19 at 11:54
  • 7
    This works for the case that it is being removed. but in the case that you want it to never exist... https://docs.cypress.io/guides/references/assertions.html#Existence It will retry until it goes away. This doesn't really work for the title problem which is what most people will be looking for. – Urasquirrel May 22 '20 at 13:36
  • You can also `cy.get('.check-box-sub-text').contains('Some text in this div.').should('not.exist');` ... so basically just add `.should('not.exist');` to make it the opposite – nawlbergs Nov 23 '21 at 00:46
107

You can also search for a text which is not supposed to exist:

cy.contains('test_invite_member@gmail.com').should('not.exist')

Here you have the result in Cypress: 0 matched elements

enter image description here

Reference: Docs - Assertions, Existence

Mads Brugger
  • 242
  • 9
Alan
  • 9,167
  • 4
  • 52
  • 70
  • 13
    this didn't work for me, the `contains` timed out and caused the test to fail `CypressError: Timed out retrying: Expected to find content: 'Im not supposed to be here' but never did.` – Tim Abell Nov 04 '19 at 18:01
  • I added more explanations with an example in my answer. After deleting the user `test_invite_member@gmail.com`, Im checking if the email exists somewhere. the result is `0 element`. What version of Cypress are you using? – Alan Nov 04 '19 at 19:32
  • cheers for the update. `npx cypress --version` - `Cypress package version: 3.5.0 Cypress binary version: 3.5.0` – Tim Abell Nov 05 '19 at 08:14
  • 1
    That's working for me now, I'm actually not sure what I missed. Thanks for your help – Tim Abell Nov 05 '19 at 08:18
  • 5
    Doesn't work for me in Cypress 4. It seems to work for removed element, not element that should not exist at all (eg when testing server side rendering) – Eric Burel Jun 10 '20 at 10:06
  • `should('not.exist')` is the other way round to `should('exist')` where `contains` is at the end: `cy.getByData('success_msg').should('exist').contains(address)` – Timo Aug 23 '22 at 15:28
77

Use .should('not.exist') to assert that an element does not exist in the DOM.


Do not use not.visible assertion. It would falsely pass in < 6.0, but properly fail now:

// for element that was removed from the DOM
// assertions below pass in < 6.0, but properly fail in 6.0+
.should('not.be.visible')
.should('not.contain', 'Text')

Migration Docs here: Migrating-to-Cypress-6-0

t_dom93
  • 10,226
  • 1
  • 52
  • 38
37

Cypress 6.x+ Migration

According to cypress docs on Existence

The very popular attempt which is a bit naive will work until it doesn't and then you'll have to rewrite it again... and again...

// retry until loading spinner no longer exists
cy.get('#loading').should('not.exist')

This doesn't really work for the title problem which is what most people will be looking for.

This works for the case that it is being removed. but in the case that you want it to never exist... It will retry until it goes away.

However, if you want to test that the element never exists in our case.

Yes lol. This is what you really want unless you want to just have your headache again another day.

// Goes through all the like elements, and says this object doesn't exist ever
cy.get(`img[src]`)
  .then(($imageSection) => {
    $imageSection.map((x, i) => { expect($imageSection[x].getAttribute('src')).to.not.equal(`${Cypress.config().baseUrl}/assets/images/imageName.jpg`) });
})
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Urasquirrel
  • 1,461
  • 1
  • 18
  • 34
23
cy.get('[data-e2e="create-entity-field-relation-contact-name"]').should('not.exist');

might lead to some false results, as some error messages get hidden. It might be better to use

.should('not.visible');

in that case.

RiZKiT
  • 2,107
  • 28
  • 23
MrSmiley
  • 347
  • 2
  • 7
  • 2
    if it did not exist in the DOM would not.visible work? I will try it out. Thanks!!!! – Maccurt Apr 11 '19 at 15:37
  • 5
    For me it was quite the opposite! (`should('not.exist')` fixed a wrong `should('not.be.visible')`) – Paul Melero Oct 23 '19 at 07:46
  • if it does not exist in the dom then not.be.visible will work. If you check the cypress logs you will get something like expected undefined to not be visible and the assertion will pass. So in a way not be visible actually covers not exist and not visible in one assertion – Shiva Srinivasan Mar 10 '20 at 15:33
  • 2
    Do not use `should('not.visible')` assertion. It would falsely pass in Cypress < 6.0, but properly fail now for the element that was removed from the DOM. Use `should('not.exist')`. See my answer below: https://stackoverflow.com/questions/48915773/cypress-test-if-element-does-not-exist/64983253#64983253 – t_dom93 Jan 05 '21 at 17:01
7

Here's what worked for me:

cy.get('[data-cy=parent]').should('not.have.descendants', 'img')

I check that some <div data-cy="parent"> has no images inside. Regarding original question, you can set data-cy="something, i.e. child" attribute on inner nodes and use this assertion:

cy.get('[data-cy=parent]').should('not.have.descendants', '[data-cy=child]')
Mikhail Vasin
  • 2,421
  • 1
  • 24
  • 31
5

You can use get and contains together to differentiate HTML elements as well.

<button type='button'>Text 1</button>
<button type='button'>Text 2</button>

Let's say you have 2 buttons with different texts and you want to check if the first button doesn't exist then you can use;

cy.get('button').contains('Text 1').should('not.exist')
  • 5
    It works on your case but if button never exist the "get" fails as cypress never found a button into ths DOM – chadyred Sep 05 '21 at 13:31
1

I closed an element and checked should('not.exist') but the assertion failed as it existed in the DOM. It just that it is not visible anymore.

In such cases, should('not.visible') worked for me. I have just started using cypress. A lot to learn.

sakibdroho
  • 11
  • 2
1

Could be done also using jQuery mode in cypress:

assert(Cypress.$('.check-box-sub-text').length==0)
Fseee
  • 2,476
  • 9
  • 40
  • 63
1

No try-catch flow in cypress

In java-selenium, we usually add the NoSuchElementException and do our cases. if UI is not displaying element for some Role based access cases.

Jayanth Bala
  • 758
  • 1
  • 5
  • 11
1

You can also query for the matched elements inside the body or inside the element's parent container, and then do some assertions on its length:

cy.get("body").find(".check-box-sub-text").should("have.length", 0);
1

In case anyone comes across this, I was having the issue that neither .should('not.exist') nor .should('have.length', 0) worked - even worse: If the element I was querying was actually there right from the get-go, both asserts still returned true.

In my case this lead to the very strange situation that these three assertions, executed right after each other, were true, even though asserts 1+2 and 3 contradict each other:

cy.get('[data-cy="foobar"]').should('not.exist')
cy.get('[data-cy="foobar"]').should('have.length', 0)
cy.get('[data-cy="foobar"]').should('have.text', 'Foobar')

After extensive testing, I found out that this was simply a race condition problem. I was waiting on a backend call to finish before running the above 3 lines. Like so:

cy.wait('@someBackendCall')
cy.get('[data-cy="foobar"]').should('not.exist')

However once the backend called finished Cypress immediately ran the first two assertions and both were still true, because the DOM hadn't yet caught up rerendering based on the backend-data.

I added an explicit wait on an element that I knew was gonna be there in any case, so my code now looks something like this:

cy.wait('@someBackendCall')
cy.get('[data-cy="some-element"]').should('contain', 'I am always here after loading')
cy.get('[data-cy="foobar"]').should('not.exist')
Dominik Ehrenberg
  • 1,533
  • 1
  • 15
  • 12
0

You can also use below code

expect(opportunitynametext.include("Addon")).to.be.false

or

should('be.not.be.visible')

or

should('have.attr','minlength','2')
Chetan Gawai
  • 2,361
  • 1
  • 25
  • 36
Rajan Domala
  • 133
  • 1
  • 8
0

Voted element is correct but I highly recommend not to using anti-pattern saving you from a lot of headaches. Why? Yes, because;

  1. Your application may use dynamic classes or ID's that change
  2. Your selectors break from development changes to CSS styles or JS behavior Luckily, it is possible to avoid both of these problems.
  3. Don't target elements based on CSS attributes such as: id, class, tag
  4. Don't target elements that may change their textContent
  5. Add data-* attributes to make it easier to target elements

Example:

<button id="main" name="submission" role="button" data-cy="submit">Submit</button>

And if you want to be more specific and want to indentify more than one selector, it is always good to use .shouldchainer.

Example:

cy.get("ul").should(($li) => {
    expect($li).to.be.visible
    expect($li).to.contain("[data-cy=attribute-name]")
    expect($li).to.not.contain("text or another selector")
  })
0

If there is no element, we can use simple line like:

cy.get('[type="checkbox"]').should('not.exist')

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 15 '22 at 07:15
-1

In my case, Cypress was so fast, that simple .should('not.be.visible') was passing the test and after that, loader appears and test failed.

I've manage to success with this:

cy.get('.loader__wrapper')
  .should('be.visible')
cy.get('.loader__wrapper', { timeout: 10000 })
  .should('not.be.visible')

Also nice to set the timeout on 10 seconds when your application loads more than 4s.

-2

I would use :

cy.get('.check-box-sub-text').should('not.be.visible');

This is safer than

cy.get('.check-box-sub-text').should('not.exist');

( The element can be present in the DOM but not visible with display: none or opacity: 0 )