Correctly chaining selectors in Cypress

Viewed 357

I've been working with Cypress for a few weeks and I'm starting to need to more complex selecting. Right now I am failing to understand how to chain selectors to get what I need.

Here is a simplified version of the HTML I am looking at:

<my-application-list-item test-hook="applicationListItem">
  <div>
    <!---->
    <div>
      <header>
        <a test-hook="name" href="/build/applications/iVANKl9Z">E2E Test Item</a>
        <my-build-application-menu>
          <!---->
          <my-dropdown testhook="actionsMenu">
            <my-icon-button-settings testhook="openActionsMenu">
              <button testhook="openActionsMenu">

The test hooks were placed when we were using Protractor, and there is inconsistency in the hyphenation. But anyway, I want to find and click the openActionsMenu that is inside the applicationListItem which contains the visible text "E2E Test Item".

I thought this would work, based on the docs for get, contains, and find:

cy.get('[test-hook="applicationListItem"]')
  .contains("E2E Test Item")
  .find('[testhook="openActionsMenu"]')

but this resulted in

Timed out retrying after 4000ms: Expected to find element: [testhook="openActionsMenu"], but never found it. Queried from element: <a.ellipsis.my-info-box__title-link.my-link>

even though running

cy.get('[testhook="openActionsMenu"]')

succeeds. What am I doing wrong?

2 Answers

Use the .contains(selector, content) form of contains().

The subject passed down is the one matching selector.

cy.contains('[test-hook="applicationListItem"]'), "E2E Test Item")
  .find('[testhook="openActionsMenu"]')

Experiment a bit, use .then(console.log) to check out the subject at that point

cy.contains('[test-hook="applicationListItem"]'), "E2E Test Item")
  .then(subject => console.log(subject)    // <my-application-list-item>
  .find('[testhook="openActionsMenu"]')
  .then(subject => console.log(subject)    // <my-icon-button-settings>

"contains" yields the element containing the text, in this case the <a> tag. If you use siblings(), you can force the runner to search in the next element:

cy.get('[test-hook="applicationListItem"]')
        .contains("E2E Test Item")
        .siblings()
        .find('[testhook="openActionsMenu"]')
Related