I'm having trouble writing Cypress end-to-end tests for my Angular application due to the additional nested elements that Angular inserts. For example, if I have an Angular component with this HTML:
<a href="{{loginUrl}}" mat-raised-button>
Log In
</a>
Then I try to write a Cypress test like this:
it('has a login button with a login URL', () => {
cy.contains('Log In')
.should('have.attr', 'href');
});
But the test fails because Angular automatically inserts many elements, and the resulting HTML looks like this. cy.contains('Log In')
picks up the span
, which has no href
.
<a href="login-url">
<button >
<span>Log In</span>
</button>
</a>
Is there a generic way to tell Cypress to "put a virtual cursor over 'Log In' and then get the corresponding href"? Or, is there a better way to structure my HTML so that such tests can pass?
CodePudding user response:
There's a couple of ways to use .contains()
.
The way you have used it cy.contains('Log In')
gets the immediate "owner" of the text, which is the <span>
.
Since you know the HTML structure and you want to test the href
two levels above, you can use traversal commands to move up those two levels
cy.contains('Log In') // I want the element "owning" text "Log In"
.parents('a')
.should('have.attr', 'href', 'login-url');
The other way to use .contains()
is to specify a selector with it, and get the element you want to test directly. It works because .contains()
will search for specified text in descendent elements.
cy.contains('a', 'Log In') // I want <a> where this or descendent has "Log In"
.should('have.attr', 'href', 'login-url');