Is there any way to assert that an element is never visible at any point when routing within Cypress?
I have a server-rendered web app that is sometimes showing a "loading" state when it shouldn't. So when I navigate between pages, a "loading" indicator is showing for a few seconds and then disappearing.
I know that Cypress's assertions will sometimes "wait" -- in this case Cypress waits until loading indicator goes away and that makes the test think that it has passed. But I want the test to fail because the loading indicator was visible at some point.
I'm using these two assertions:
cy.get('[data-test="loading"]').should('not.exist');
cy.get('[data-test="loading"]').should('not.be.visible');
But both of them are passing because the loading indicator goes away.
I've checked through all the documentation but there doesn't seem to be some kind of method for checking that an element is never visible. Is there some method I'm missing or some hack to test this a different way?
Is there any way to assert that an element is never visible at any point when routing within Cypress?
I have a server-rendered web app that is sometimes showing a "loading" state when it shouldn't. So when I navigate between pages, a "loading" indicator is showing for a few seconds and then disappearing.
I know that Cypress's assertions will sometimes "wait" -- in this case Cypress waits until loading indicator goes away and that makes the test think that it has passed. But I want the test to fail because the loading indicator was visible at some point.
I'm using these two assertions:
cy.get('[data-test="loading"]').should('not.exist');
cy.get('[data-test="loading"]').should('not.be.visible');
But both of them are passing because the loading indicator goes away.
I've checked through all the documentation but there doesn't seem to be some kind of method for checking that an element is never visible. Is there some method I'm missing or some hack to test this a different way?
Share Improve this question edited Dec 12, 2021 at 17:29 Nate Anderson 21.1k20 gold badges111 silver badges152 bronze badges asked Dec 12, 2018 at 15:03 greatbearsharkgreatbearshark 1651 gold badge3 silver badges8 bronze badges 1- can you add a wait of some sort of 0, so i does not wait? – Maccurt Commented Dec 12, 2018 at 15:45
2 Answers
Reset to default 13I might be crazy, and i have not tested this yet, but I wanted to throw this out there
I assume you are testing that there should NEVER be a loading indicator and it is waiting the default 4 seconds and the indicator goes away, and thus your test pass. So below I set the wait to zero, so it does not wait. I am also confused as to why you don't fix the actual code so you don't see the indicator if you are not supposed to. Perhaps you don't have access to the code..
cy.get('[data-test="loading"]',{ timeout: 0 }).should('not.exist');
cy.get('[data-test="loading"]',{ timeout: 0 }).should('not.be.visible');
Cypress has a lite version of jQuery, so we can watch for changes to the parent of the element that should not exist.
@Maccurt's tests are applied whenever a change occurs.
You want to keep watch firing to a minimum, so find the immediate (or nearest) parent of tested element.
Note this covers exists
tests, but should not be necessary for visible
tests if the element is present all the time but is just not visible.
In this example a button is added to body
.
The first test watches for a span
(which is never added so the test succeeds).
The 2nd test watches for the button
and fails.
describe('watching for an element to not appear', () => {
const watchAndTest = function(parentSelector, assert) {
Cypress.$(parentSelector).bind('DOMNodeInserted', function(event) {
assert()
});
}
it('should succeed because "span" does not exist', () => {
const parentSelector = 'body'
const watchForSelector = 'span'
watchAndTest(parentSelector,
() => {
// Place your 'assert' code here
cy.get(`${parentSelector} ${watchForSelector}`,{ timeout: 0 })
.should('not.exist');
}
)
// Place your 'act' code here
cy.get(parentSelector).then(parent => {
var newElement = document.createElement('button');
parent[0].appendChild(newElement)
})
Cypress.$(parentSelector).unbind('DOMNodeInserted')
})
it('should fail because "button" exists', () => {
const parentSelector = 'body'
const watchForSelector = 'button'
watchAndTest(parentSelector,
() => {
// Place your 'assert' code here
cy.get(`${parentSelector} ${watchForSelector}`,{ timeout: 0 })
.should('not.exist');
}
)
// Place your 'act' code here
cy.get(parentSelector).then(parent => {
var newElement = document.createElement('button');
parent[0].appendChild(newElement)
})
Cypress.$(parentSelector).unbind('DOMNodeInserted')
})
})