I need to assert that a <table> element contains both a nested <thead> and a <tbody> element.
Sure, an obvious solution would be sth. like this:
cy.get('table')
.find('thead')
cy.get('table')
.find('tbody')
but isn't there a simple way to to that all in one chain? Like this:
cy.get('table')
.should('contain.element','thead')
.should('contain.element','tbody')
Unfortunatelly there is no such contain.element.
I know, there is .should('contain.html','...') but it doesn't work for me because this would require me to specify the full html string including nested content (with tr, td). I only want to assert that both child elements thead and tbody are existing.
Another way would be to create an array of elements and using a forEach() loop assert that they are visible, something like this:
const elements = ['table thead', 'table tbody']
elements.forEach((ele) => {
cy.get(ele).should('be.visible')
})
Update: Okay, I missed your note, related .should('contain.html'..). Usually, contain.html returns true if a node is a descendant of a target node, no matter if it has a deep three child nodes.
You can use should in combination with and. .and() yields the same subject it was given from the previous command:
cy.get('table')
.should('contain.html','thead')
.and('contain.html','tbody')
Try jQuery .has()
cy.get('table')
.should($table => {
expect($table.has('thead')).to.eq(true)
expect($table.has('tbody')).to.eq(true)
})
Or same thing in one line
cy.get('table:has(thead):has(tbody)') // pseudo selector :has()
Or same thing in one selector
cy.get('table thead, table tbody') // jQuery Multiple Elements Selector
.should('have.length', 2) // passes if both exist