69

I have to write tests for a web site. I am trying to get the selected value of a dropdown box. So far i can get the contents of the dropdown by doing

find_field('restrictions__rating_movies').text

returns - Don't Allow Movies G PG M R13 R15 R16 R18 R RP16 Allow All Movies

I can get the value of the selected object.

find_field('restrictions__rating_movies').value

returns - 1000

This does not help me much though because i am trying to get the text of the selected item from a drop down box.

<select class="" id="restrictions__rating_movies" name="restrictions[][rating_movies]">            
<option value="0">Don't Allow Movies</option>
<option value="100">G</option>
<option value="200">PG</option>
<option value="300">M</option>
<option value="325">R13</option>
<option value="350">R15</option>
<option value="375">R16</option>
<option value="400">R18</option>
<option value="500">R</option>
<option value="600">RP16</option>
<option value="1000" selected="selected">Allow All Movies</option></select>

in this case shown i need to get the value 'Allow All Movies' I have tried many different combinations of the above two examples.

Brandon
  • 1,425
  • 2
  • 16
  • 19

7 Answers7

162

There's a have_select matcher if you use Capybara with Rspec:

expect(page).to have_select(
  'my-select',         # locator
  selected: 'Option 2' # option
) 
Parameters:

Locator (String) (defaults to: nil) — The label, name or id of a select box Options (Hash) using :selected (String, Array) — Options which should be selected

notapatch
  • 6,569
  • 6
  • 41
  • 45
gylaz
  • 13,221
  • 8
  • 52
  • 58
  • this answer does not work for me. I get "ArgumentError Exception: invalid keys :selected" (perhaps its deprecated?). The accepted answer from @brandon does. – Peter P. Jun 22 '15 at 18:01
  • Perhaps you are using an old version of the gem? The source code for capybara shows usage of this: https://github.com/jnicklas/capybara/blob/3ae284460b1af35d40b077bf14f7222c2982c120/lib/capybara/spec/session/has_select_spec.rb#L15 – gylaz Jun 23 '15 at 14:35
  • 11
    Small note for future-explorers: in this example, 'my-select' is the `name` of the select. Might be clear, but I kept trying to use a class tag :P – TCannadySF May 02 '16 at 16:02
  • 2
    `assert page.has_select?('my-select', selected: 'Option 2')` if minitest instead of rspec – kolen Dec 13 '16 at 15:45
  • 1
    This have_select is really slow when there is a lot of options on the list. I have to used `find_field(name).value` to make the assertion completed faster. – Phương Nguyễn Apr 08 '17 at 07:33
  • What is 'Option 2'? Is it the index of the option in dropdown or the text that should be present in the dropdown? – Maruthi Srinivas Jul 04 '19 at 09:41
  • A small note to users: 'Option 2' is the text that is selected in the dropdown. Its not the index of the value in dropdown. – Maruthi Srinivas Jul 04 '19 at 09:48
44
find_field('restrictions__rating_movies').find('option[selected]').text
bluish
  • 26,356
  • 27
  • 122
  • 180
Brandon
  • 1,425
  • 2
  • 16
  • 19
  • 1
    Slight variation that I prefer find_field('restrictions__rating_movies').should have_content('desired string') – Ash Blue Jan 01 '13 at 12:06
  • 2
    @AshBlue That just ensures 'desired string' is contained in the dropdown's list of options, not that it is actually selected. – ckb May 21 '13 at 15:14
  • For my situation it worked better, just posting in-case it helps someone else. – Ash Blue May 21 '13 at 16:45
  • 6
    If the selection of the option was done in javascript, find('option[selected]') may not work. In this case, it may be possible to use capybara's selected? method like this: find('#restrictions_rating_movies').find(:xpath,"./option[contains(.,'Starwars')]").selected? – Les Nightingill May 24 '13 at 22:34
  • 2
    I took @LesNightingill's idea, and ended up doing: `find("#select_name option[value='something']").should be_selected` – Matt Huggins Jul 25 '13 at 22:51
  • 1
    This method will not work if you set the value of the select with Javascript. If that's the case, you want to be using the `has_select?` and `has_no_select?` methods with the `selected` option. See http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers#has_select%3F-instance_method. – Richard Jones Sep 05 '13 at 17:37
  • How to get value of an element in rails minitest ? – Zia Qamar Feb 14 '17 at 06:50
15

Very simple way to get value of selected option is:

find("#restrictions__rating_movies").value

This will return selected select option value.

Vijay Chouhan
  • 4,613
  • 5
  • 29
  • 35
  • 1
    After trying a lot of variations, this is the one that worked for me. I ended up doing: `find("select#my-select").value.should eq('test_value')`. I like your approach because (to me) it is simpler and easier to read - which means I'm more likely to remember what it's doing and remember how to do it again later. Thanks! – jvillian Sep 03 '14 at 20:24
  • 1
    +1 This seems to fit most naturally with the RSpec expect syntax expect(find("select#my-select").value).to eq 'test_value' – DazBaldwin Oct 03 '14 at 13:16
  • 1
    This is also the only option that works with most drivers (selenium, poltergeist, webkit) – steel Sep 14 '15 at 21:35
  • This is my favorite answer for readability and you can see exactly what is going on without an unneeded abstraction. – yoyodunno Jan 13 '17 at 20:25
  • 1
    The question is to get the text from the box, not the value of the select. – Andrey Aug 25 '21 at 01:18
4

If you only need to assert if a field is selected with a given option, the straightforward answer is

#Find a select box by (label) name or id and assert the given text is selected
When /^select box "([^"]*)" is selected with "([^"]*)"$/ do |dropdown, selected_text|    
  assert page.has_select?(dropdown, selected: selected_text)
end

Source: http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers#has_select%3F-instance_method

But the title of your question is "Get select value for dropdown". And I've run into a similar problem where I would like not only to assert the selection, but also retrieve the text and value of the selected field. I've found no straight way on API. The easiest way I've found was: #all("option").find &:selected?

When /^ select box "([^"]*)" is selected with "([^"]*)"$/ do |dropdown, selected_text|
  sb = find_field(dropdown)
  sb_selected = sb.all("option").find &:selected?
  msg = "Selected: #{sb_selected.text.inspect} - value:#{sb_selected.value.inspect}"
  assert page.has_select?(dropdown, selected: selected_text), msg
end

This gives me a more comprehensive error message when the assertion fails.

If there's multiple selections you can use #select in place of #find, as in #all("option").select &:selected?. It will return an Array.

This answer doesn't rely on the 'option[selected]' trick as the previous ones, so it works even if the selection is done by Javascript (which was the reason why the previous answers didn't work for me at all).

Tested on:

capybara (2.2.1)
capybara-webkit (1.1.0)
cucumber (1.3.14)
cucumber-rails (1.4.0)
3

If you want to find the current selected text, without assuming what it might be so that you can just compare it to an expectation, the following works even if the selection was made by JS (so that there is no 'option[selected]').

First I find the value of the select, then I find the text of the option with that value:

  def selected(selector)
    value = find(selector).value
    text = find(selector).find("option[value='#{value}']").text
  end
Adam
  • 81
  • 4
0

Create a simple function to return the text given a select element (dropdown):

def get_dropdown_selected_item_text(dropdown)
  value = dropdown.value
  return dropdown.all(:css, "option").select {|opt| opt.value == value} .first.text
end
Steven Solomon
  • 301
  • 1
  • 3
  • 14
-1

Would something like this work?

within("//select[@id='restrictions__rating_movies']") do
  find_field("//option[@selected='selected']").text
end
Frost
  • 11,121
  • 3
  • 37
  • 44
  • That did not work. Here is the error Selenium::WebDriver::Error::InvalidSelectorError: The given selector .////select[@id = 'restrictions__rating_movies'] is either invalid or does not result in a WebElement. The following error occurred: [InvalidSelectorError] Unable to locate an element with the xpath expression .////select[@id = 'restrictions__rating_movies'] because of the following error: [Exception... "The expression is not a legal expression." – Brandon Jul 16 '12 at 14:23
  • How about `find("//select option[@selected='selected']")` then? – Frost Jul 16 '12 at 14:28
  • i think you need to pass the `xpath` specifier, eg. `within(:xpath, 'blah blah') – zetetic Jul 16 '12 at 19:00