148

I'm trying to select an item from a drop down menu using Capybara (2.1.0).

I want to select by number (meaning select the second, third, etc option).

I've Googled like crazy trying all sorts of things but no luck.

I was able to select it by using the value:

 find("option[value='4c430d62-f1ba-474f-8e8a-4452c55ea0a8']").click

But I don't want to use that method b/c the value is something that will change and that will make my test brittle.

The HTML for the drop down is:

<td class="value">
    <select name="organizationSelect" id="organizationSelect" class="required">
     <option value="NULL">Choose...</option>
     <option value="4c430d62-f1ba-474f-8e8a-4452c55ea0a8">&nbsp;Institution1</option>
     <option value="e1a4efa7-352d-410a-957e-35c8a3b92944">&nbsp;Institution / test</option>
    </select>
</td>

I also tried this:

  option = find(:xpath, "//*[@id='organizationSelect']/option[2]").text  
  select(option, :from => organizationSelect)

But it results in this error:

Ambiguous match, found 2 elements matching option "Institution" (Capybara::Ambiguous)

So how can I select the first, second, third, etc option from the drop down (using Capybara) ?

carols10cents
  • 6,943
  • 7
  • 39
  • 56
Farooq
  • 1,925
  • 3
  • 15
  • 36

11 Answers11

210

For some reason it didn't work for me. So I had to use something else.

select "option_name_here", :from => "organizationSelect"

worked for me.

Yohann
  • 800
  • 10
  • 15
RVM
  • 2,237
  • 1
  • 13
  • 13
  • 1
    Weird, that doesn't work for me as the method seems to take at least 3 options. Although the code you suggested matches the example code from the capybara guide. – Linus Feb 16 '14 at 21:38
  • 2
    it's not `form`, it is `from`. Here is the [documentation on select](http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions#select-instance_method) – fontno Dec 26 '14 at 01:21
  • 5
    Perhaps worth noting the from value is the name, id, or label text. i.e. "#organizationSelect" is incorrect, but "organizationSelect" should work. – MZB Mar 12 '15 at 04:57
  • This didn't work for me, but carols10cents's solution did. This is not a critic of your answer. I just find it really strange that even on the latest version of capybara, some calls work and some calls don't even when intution would lead you to believe that multiple solutions look valid. It's driving me insane. Is this related to firefox (or whatever browser capybara ends up using)? – chaostheory Dec 13 '15 at 18:26
  • I think this will only work when the option name and option value are the same. – pixelearth Mar 17 '17 at 16:40
144

If you take a look at the source of the select method, you can see that what it does when you pass a from key is essentially:

find(:select, from, options).find(:option, value, options).select_option

In other words, it finds the <select> you're interested in, then finds the <option> within that, then calls select_option on the <option> node.

You've already pretty much done the first two things, I'd just rearrange them. Then you can tack the select_option method on the end:

find('#organizationSelect').find(:xpath, 'option[2]').select_option
quinnjn
  • 623
  • 7
  • 10
carols10cents
  • 6,943
  • 7
  • 39
  • 56
  • 2
    Would like to add this reference for those researching this in the future: https://gist.github.com/zhengjia/428105 – BenKoshy Apr 24 '16 at 23:40
  • 4
    Great answer! I would like to add that in Rails 5 you can do it in the following way as well: `select('option_name', from: 'select_box')`. Where the values can be: id, name, related label element. You can read more about Capybara and DSL options [here](https://kolosek.com/rails-capybara-setup/). – Nesha Zoric Feb 26 '18 at 12:37
12

another option is to add a method like this

  def select_option(css_selector, value)
    find(:css, css_selector).find(:option, value).select_option
  end
montrealmike
  • 11,433
  • 10
  • 64
  • 86
  • Helpful options `find("select[name='organization_search[role]']").find(:option, text: :Staff).select_option` – pixelearth Mar 03 '20 at 05:44
  • `find(:css, "#search_field").find(:option, "Opp Last Name").select_option`, which is the displayed option text, worked for me, while the value of the option didn't. – codenoob Jun 12 '20 at 02:50
8

To add yet another answer to the pile (because apparently there's so many ways of doing it depending on your setup) - I did it by selecting the literal option element and clicking it

find(".some-selector-for-dropdown option[value='1234']").select_option

It's not very pretty, but it works :/

user2490003
  • 10,706
  • 17
  • 79
  • 155
5

Unfortunately, the most popular answer did not work for me entirely. I had to add .select_option to end of the statement

select("option_name_here", from: "organizationSelect").select_option

without the select_option, no select was being performed

Sam D
  • 51
  • 2
  • 3
  • How come you could call `.select_option`, since the `select` method returns a boolean value? – Ruby Jan 09 '18 at 15:23
3

none of the answers worked for me in 2017 with capybara 2.7. I got "ArgumentError: wrong number of arguments (given 2, expected 0)"

But this did:

find('#organizationSelect').all(:css, 'option').find { |o| o.value == 'option_name_here' }.select_option
bjelli
  • 9,752
  • 4
  • 35
  • 50
1

Here's the most concise way I've found (using capybara 3.3.0 and chromium driver):

all('#id-of-select option')[1].select_option

will select the 2nd option. Increment the index as needed.

pduey
  • 3,706
  • 2
  • 23
  • 31
1

This is by far the most simplest one:

select("month", from: "repeat_on")

The from parameter should be an id as in:

<select id="repeat_on">
    <option value="month">month</option>
    <option value="day">day</option>
</select>
flyingfishcattle
  • 1,817
  • 3
  • 14
  • 25
adriannicolai
  • 11
  • 1
  • 2
0

In Capybara you can use only find with xpath

find(:xpath, "//*[@id='organizationSelect']/option[2]").click

and method click

AlexSh
  • 1,468
  • 15
  • 12
0

I was using simple_form:

When working with Associations:

= f.association :company, collection: Company.ordered, as: :select, include_blank: false
# output HTML
<select class="form__input" name="role[company_id]" id="role_company_id">
  <option value="1">APPLE</option>
  <option value="5">J.P. MORGAN</option>
  <option value="6">JOHNSON &amp; JOHNSON</option>
  <option value="4">KPMG</option>
  <option value="2">MICROSOFT</option>
  <option value="3">WALMART</option>
</select>

this one worked for me:

find('#role_company_id').find(:xpath, 'option[3]').select_option

When working with conventional select:

= f.input :work_type, as: :select, collection: Role.work_types.collect { |key, value| [key.to_s.titleize, value] }, include_blank: false
# output HTML
<select class="form__input" name="role[work_type]" id="role_work_type">
  <option selected="selected" value="in_person">In Person</option>
  <option value="remote">Remote</option>
  <option value="hybrid">Hybrid</option>
</select>

this worked for me:

find_by_id("role_work_type").find("option[value='remote']").click

Hope this helps.

drjorgepolanco
  • 7,479
  • 5
  • 46
  • 47
-4

It is not a direct answer, but you can (if your server permit):

1) Create a model for your Organization; extra: It will be easier to populate your HTML.

2) Create a factory (FactoryGirl) for your model;

3) Create a list (create_list) with the factory;

4) 'pick' (sample) a Organization from the list with:

# Random select
option = Organization.all.sample 

# Select the FIRST(0) by id
option = Organization.all[0] 

# Select the SECOND(1) after some restriction
option = Organization.where(some_attr: some_value)[2]
option = Organization.where("some_attr OP some_value")[2] #OP is "=", "<", ">", so on...