102

say I have the HTML:

<select name="subject" data-testid="contact-us-subject-field">
  <option value="What is this regarding?">What is this regarding?</option>
  <option value="Partnerships">Partnerships</option>
  <option value="Careers">Careers</option>
  <option value="Press">Press</option>
  <option value="Other">Other</option>
</select>

Selecting an option with a known value, such as 'Careers' is as easy as:

cy.get('[data-testid="contact-us-subject-field"]').select('Careers');

How do I select the nth option in this field, regardless of its value?

Paolo
  • 3,530
  • 7
  • 21
JD.
  • 2,361
  • 6
  • 25
  • 38

12 Answers12

135

Update

As pointed out by @dpstree in the comments, this doesn't answer the original question. Please see more recent answers for a complete solution.

Original

By using eq

cy.get('tbody>tr').eq(0)    // Yield first 'tr' in 'tbody'
cy.get('ul>li').eq(4)       // Yield fifth 'li' in 'ul'
Arnaud P
  • 12,022
  • 7
  • 56
  • 67
  • 2
    Is `eq` an abbreviation? What does it mean? – nitzel Jun 26 '19 at 15:10
  • 2
    As mentioned by the documentation page I linked, the term comes from jQuery. So you may be interested in [this post](https://stackoverflow.com/questions/15059207/what-does-eq-in-the-jquery-eq-method-stand-for) – Arnaud P Jun 27 '19 at 13:13
  • 4
    This doesn't select anything. It does demonstrate the .eq() syntax that is needed as part of the solution, but misses the important context of needing to manipulate the select. See Robert or Miguel's solution below. – dpsthree Aug 26 '20 at 15:15
  • My word, you're right, I must have read the question too quickly. Will edit to point this out. – Arnaud P Aug 27 '20 at 08:13
  • Also, the eq()in Cypress simply doesn't work. I've tried it just about anywhere in my angular 8 application, where there are rows of elements with some element or other having the same ID in each row. If there are two buttons with the same ID, Cypress will ALLWAYS click the first one, whether I use eq(0) or eq(1). At the same time, it DOES try to honor the index, since it won't accept eq(2) when there are only two. But it doesn't work. At all. –  Feb 11 '21 at 14:45
  • 1
    Just remember that if you save this selection to a variable, it won't work. const mySelection = cy.get('tbody>tr') ; mySelection.eq(0); mySelection.eq(1) --> the will be no second element. You need to call a selection function again – Rantiev May 06 '21 at 21:35
  • why do i feel like there should an `nth()` command!? – Craig Wayne Apr 07 '22 at 19:41
51

In the particular context of selecting the nth option, this may be appropriate:

cy.get('select[name=subject] > option')
  .eq(3)
  .then(element => cy.get('select[name=subject]').select(element.val()))
Robert K. Bell
  • 9,350
  • 2
  • 35
  • 50
  • big thumbs up on this clever solution – nullsteph May 13 '20 at 18:28
  • 1
    Exactly what I was looking for, please note that soon there might be an easier solution https://github.com/cypress-io/cypress/issues/757. Small suggestion for @Robert to use cy.wrap() + parents() to not duplicate the selector: `.eq(2).then(($el) => cy.wrap($el).parent('select').select($el.val()))`. – TimNode Jun 02 '20 at 13:08
28

Based on solution from Miguel Rueda, but using prevSubject option:

Cypress.Commands.add(
  'selectNth',
  { prevSubject: 'element' },
  (subject, pos) => {
    cy.wrap(subject)
      .children('option')
      .eq(pos)
      .then(e => {
        cy.wrap(subject).select(e.val())
      })
  }
)

Usage:

cy.get('[name=assignedTo]').selectNth(2)

Explanation:

  • Using children('option') and .eq(pos) traverse children of select to specific element.
  • Call select method with value of selected element.
Tomáš Ehrlich
  • 6,546
  • 3
  • 25
  • 31
23

You can now select an option by index within the .select(index) command:

cy.get('select').select(0)        // selects by index (yields first option) ie "What is this regarding?"
cy.get('select').select([0, 1])   // select an array of indexes

This should be easy now with the release of cypress v8.5.0. See documentation for more.

t_dom93
  • 10,226
  • 1
  • 52
  • 38
10

I had the same problem and solved it by creating a custom cypress command. No as pretty as I would like, but it did the job.

Cypress.Commands.add("selectNth", (select, pos) => {
  cy.get(`${select} option +option`)
    .eq(pos)
    .then( e => {
       cy.get(select)
         .select(e.val())
    })
})

then I used in the test as such

    cy.viewport(375, 667)
      .selectNth("customSelector", 3)

The option +option part was the only way I could find to get the full list of options inside a select and it's currently the bit of code i'm trying to work arround although it works fine.

Miguel Rueda
  • 109
  • 1
  • 2
7

since the working answers are using then anyways, eq or something fancier is redundant with array indexing...

// to click on the 1st button
cy.get('button').then($elements => {cy.wrap($elements[0]).click();});
// to click on the 4th tr
cy.get('tr').then($elements => {cy.wrap($elements[3]).click();}); 
// to click on the last div:
cy.get('div').then($elements => {cy.wrap($elements[$elements.length - 1]).click();});
Joelle Boulet
  • 360
  • 4
  • 11
  • 1
    finally, one that works. in my case: `cy.wrap($recordings[0]).findByRole('button', { name: 'Remove' }).click({ force: true })` – Jason G Jan 04 '21 at 19:43
3

Let's assume you wanna select 2nd option, you can do that simply by this

cy.get("select option").eq(2)

just keep in mind that cy.get() works like jquery's $().

Ajay Rawat
  • 307
  • 3
  • 10
2

Find dropdown using ID or Class -

cy.get('#ID').contains("dowpdown placeholder or name").click();

After Click dropdown result dropdown element will popup, find that result ID or Class using inspect element, Then -

cy.get('#result-ID').children().first().click();

This will click on the first element of the dropdown.

roapp
  • 530
  • 6
  • 17
Pradnyesh patil
  • 271
  • 3
  • 3
1

You can also rely on the :nth-child css pseudo-class:

cy.get("[data-testid="contact-us-subject-field"] option:nth-child(2)").click();

It's probably less flexible than using the cypress constructs but it is nice and clean. (And doesn't make me crawl through the cypress docs)

Tim Van Laer
  • 2,434
  • 26
  • 30
0

Capture all the elements in the drop-down using a selector. Get the length. Use math.random() to randomly get a number. Select the option at the index.

cy.get("ul > li").as("options")
cy
.get("@options")
.its('length')
.then(len => Math.floor(Math.random() * Math.floor(len)))
.then((index) => {
cy.get("@options").eq(index).click()
})
iknow
  • 8,358
  • 12
  • 41
  • 68
GHULAM NABI
  • 498
  • 5
  • 15
0

if you are looking a value to select then you cannot use .eq(), you need to use .contains() .eq() is only for numbers(indexes)

Example: cy.get(dropdownOptions).contains(some_value).click()

Eggcellentos
  • 1,570
  • 1
  • 18
  • 25
0

If you look for the nth option in the select dropdown, for example, in case the data is dynamically changed and you want to select the nth one, whatever the content may be, you can use this syntax:

App

<select name="mySelect">
  <option value="option_1">option 1</option>
  <option value="option_2">option 2</option>
  ...
  <option value="option_n">option n</option>
  ...
</select>

Spec

cy.get("[name='mySelect'] option:nth-of-type(n)")
.invoke("text")
.then((text) => {
  cy.get("[name='mySelect']").select(text);
});

And note that n is the order of the option that you want to select. The count start from 1.