Home > OS >  How to use Cypress to test Angular Material app, with elements automatically inserted by Angular?
How to use Cypress to test Angular Material app, with elements automatically inserted by Angular?

Time:05-02

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');
  • Related