Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cypress: How to scroll a dropdown to find item

I need to click a dropdown list and scroll to find an item by text.

enter image description here

At the moment I know that the item is at the bottom of the list so I can do:

cy.get('.ng-dropdown-panel-items').scrollTo("bottom").contains(/test/i).click()

and this works, but if the item moves and is no longer at the bottom, this will break.

I tried scrollIntoView but with no luck:

cy.get('.ng-dropdown-panel-items').contains(/test/i).scrollIntoView().click()

and

cy.get('.ng-dropdown-panel-items').scrollIntoView().contains(/test/i).click()

Does anyone know how I can do this?

Update: the list of options is dynamically generated (not all options are in the DOM initially) so scrolling to the bottom is required to get all options. Once all options are available .contains() can be used to find the element.

like image 712
SamHeyman Avatar asked Oct 19 '25 23:10

SamHeyman


2 Answers

The Angular ng-select in virtual mode is quite tricky to handle.

It's list is virtual, which means it only has some of the items in the DOM at one time, so you can't select them all and iterate over them.

You can recursively scan the options list and use .type({downarrow}) to move new options into the DOM (which is one way a user would interact with it).

it('selects an option in a virtual-scroll ng-select', () => {

  cy.visit('https://ng-select.github.io/ng-select#/virtual-scroll')

  cy.get('ng-select').click();                    // open the dropdown panel

  cy.get('.ng-option')
    .should('have.length.gt', 1);                 // wait for the option list to populate

  function searchForOption(searchFor, level = 0) {

    if (level > 100) {                                         // max options to scan
      throw 'Exceeded recursion level'                         // only useful for 100's
    }                                                          // not 1000's of options 

    return cy.get('ng-select input')
      .then($input => {
        const activeOptionId = $input.attr('aria-activedescendant') // highlighted option
        const text = Cypress.$(`#${activeOptionId}`).text()         // get it's text
        if (!text.includes(searchFor)) {                            // not the one?
          cy.wrap($input).type('{downarrow}')                       // move the list
          return searchForOption(searchFor, level + 1)              // try the next
        }
        return cy.wrap(Cypress.$(`#${activeOptionId}`))
      })
  }

  searchForOption('ad et natus qui').click();             // select the matching option

  cy.get('.ng-value')
    .should('contain', 'ad et natus qui');                // confirm the value 

})

Note that recursion can be hard on memory usage, and this code could be optimized a bit.

like image 61
Richard Matsen Avatar answered Oct 22 '25 04:10

Richard Matsen


For most cases you would need cy.get().select like for example:

cy.get('.ng-dropdown-panel-items').select(/test/i)

like image 43
Rosen Mihaylov Avatar answered Oct 22 '25 03:10

Rosen Mihaylov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!