Skip to content

Instantly share code, notes, and snippets.

@thijsc
Created November 24, 2011 11:08
Embed
What would you like to do?
Select item from chosen js select with Capybara and Selenium
def select_from_chosen(item_text, options)
field = find_field(options[:from])
option_value = page.evaluate_script("$(\"##{field[:id]} option:contains('#{item_text}')\").val()")
page.execute_script("$('##{field[:id]}').val('#{option_value}')")
end
@jgarber
Copy link

jgarber commented Apr 16, 2013

If using @rheaton's snippet with Capybara 2.1, you will need to pass visible: false to find_field since Chosen hides the field.

@simonmorley
Copy link

+1 to @jgarber for this point. Just wasted days of my life looking for a fix:

field = find_field(options[:from], visible: false)

Fixes the failing tests.

@bbuchalter
Copy link

@tjmcewan

I know it's been a long time, but it seems these two statements you added for supporting from a multiple-select,

page.execute_script("value = ['#{option_value}']\; if ($('##{field[:id]}').val()) {$.merge(value, $('##{field[:id]}').val())}")
option_value = page.evaluate_script("value")

seem to break functionality for a single select if there is a default value selected. Thought I would mention it here since this is still an active thread.

@pduey
Copy link

pduey commented Aug 16, 2013

For capybara 2, visible: true is the default, so this doesn't work as is. Changed the first line to:

field = find_field(options[:from], visible: false)

@tinderfields
Copy link

+1 for pduey's comment I also had to add visible: false

@michaelbrawn
Copy link

Here is an updated version of @Macrow 's chosen_select.rb

# Support for multiple selects (just call select_from_chosen as many times as required):
module ChosenSelect
  def select_from_chosen(item_text, options)
    field = find_field(options[:from], visible: false)
    option_value = page.evaluate_script("$(\"##{field[:id]} option:contains('#{item_text}')\").val()")
    page.execute_script("value = ['#{option_value}']\; if ($('##{field[:id]}').val()) {$.merge(value, $('##{field[:id]}').val())}")
    option_value = page.evaluate_script("value")
    page.execute_script("$('##{field[:id]}').val(#{option_value})")
    page.execute_script("$('##{field[:id]}').trigger('chosen:updated')")
  end  
end

RSpec.configure do |config|
  config.include ChosenSelect
end

@arojoal
Copy link

arojoal commented Aug 24, 2014

Thanks @michaelbrawn!!!!

I'm using cucumber-1.3.16 and rspec-3.0.3 and I've got a problem with

RSpec.configure do |config|
  config.include ChosenSelect
end 

When I run cucumber I get a "undefined method `configure' for RSpec:Module (NoMethodError)".

I've replaced it with "World(ChosenSelect)" and it works!!!! this is how the complete module code looks like:

# Support for multiple selects (just call select_from_chosen as many times as required):
module ChosenSelect
  def select_from_chosen(item_text, options)
    field = find_field(options[:from], visible: false)
    option_value = page.evaluate_script("$(\"##{field[:id]} option:contains('#{item_text}')\").val()")
    page.execute_script("value = ['#{option_value}']\; if ($('##{field[:id]}').val()) {$.merge(value, $('##{field[:id]}').val())}")
    option_value = page.evaluate_script("value")
    page.execute_script("$('##{field[:id]}').val(#{option_value})")
    page.execute_script("$('##{field[:id]}').trigger('chosen:updated')")
  end  
end

World(ChosenSelect)

@nTraum
Copy link

nTraum commented Sep 1, 2014

Can confirm this works like a charm. Thanks a lot! 👯

(RSpec 3, Capybara 2.4.1)

@ralphos
Copy link

ralphos commented Oct 14, 2014

Thanking you!!!

@flexybiz
Copy link

When to use last one with Ember.js got a problem: it doens't update binded values. So just add .change() at the end and it will work as expected.

# Support for multiple selects (just call select_from_chosen as many times as required):
module ChosenSelect
  def select_from_chosen(item_text, options)
    field = find_field(options[:from], visible: false)
    option_value = page.evaluate_script("$(\"##{field[:id]} option:contains('#{item_text}')\").val()")
    page.execute_script("value = ['#{option_value}']\; if ($('##{field[:id]}').val()) {$.merge(value, $('##{field[:id]}').val())}")
    option_value = page.evaluate_script("value")
    page.execute_script("$('##{field[:id]}').val(#{option_value})")
    page.execute_script("$('##{field[:id]}').trigger('chosen:updated')")
    page.execute_script("$('##{field[:id]}').change()")
  end  
end

World(ChosenSelect)

@corporealfunk
Copy link

Without needing to call evaluate_script, this also works with Capybara 2.4.4, Capybara-webkit 1.4.1 and Rspec 3.2.2, using Chosen 1.4.1:

find("#field_id_chosen").trigger("mousedown")
find("#field_id_chosen ul.chosen-results li", :text => "Item Text").trigger("mouseup")

@jonahwh
Copy link

jonahwh commented Mar 31, 2015

For those of you using rails who need to escape javascript when setting option_value the first time.

include ActionView::Helpers::JavaScriptHelper

in the Module/Class where this method lives, and change

option_value = page.evaluate_script("$(\"##{field[:id]} option:contains('#{item_text}')\").val()")

to

option_value = page.evaluate_script("$('##{field[:id]} option:contains(\"#{j item_text}\")').val()")

As an aside, if your select box is prepopulated, and you want to CHANGE the value, you must clear the value of the select box before calling select_from_chosen, or it will attempt to select both values.

@ChunAllen
Copy link

It only works for a single selection of chosen dropdown but not on grouped options chosen select

@osiro
Copy link

osiro commented Aug 24, 2015

Hey guys,

The implementation of @flexybiz above seems to work fine, however if, for whatever reason, I run select_from_chosen two or more times on the same field, this will select multiple options even though my chosen is configured to be a standard select, not a multiple one.

My workaround was creating deselect_from_chosen.

So in case you guys need to deselect fields in your tests, here's how I did it:

  def deselect_from_chosen(field)
    field = find_field(field, visible: false)
    page.execute_script("$('##{field[:id]}').val('').trigger('change').trigger('chosen:updated')")
  end

@thijsc
Copy link
Author

thijsc commented Sep 7, 2015

Funny to find this gist again 4 years later with so much discussion :-). I just needed this again, this one based on the snippet by @corporealfunk works well in Selenium:

def select_from_chosen(item_text, options)
  field = find_field(options[:from], :visible => false)
  find("##{field[:id]}_chosen").click
  find("##{field[:id]}_chosen ul.chosen-results li", :text => item_text).click
end

@idabmat
Copy link

idabmat commented Feb 12, 2016

For deselecting a specific value :

def deselect_from_chosen(item_text, options)
  field = find_field(options[:from], visible: false)
  page.execute_script("$(\"##{field[:id]} option:contains('#{item_text}')\").removeAttr('selected')")
  page.execute_script("$('##{field[:id]}').trigger('chosen:updated')")
end

@brunzino
Copy link

Here's another deselect function that's more in-line with @thejsc's approach. I like this approach because it triggers the change hook.

def deselect_from_chosen(item_text, options)
  field = find_field(options[:from], visible: false)
  find("##{field[:id]}_chosen ul.chosen-choices li.search-choice", :text => item_text).find("a.search-choice-close").click
end

@westonganger
Copy link

westonganger commented Aug 29, 2016

For anyone whos interested in just selecting whichever option is first without having to know the text

def select_first_from_chosen(from)
  field = find_field(from, visible: false)
  find("##{field[:id]}_chosen").click
  first("##{field[:id]}_chosen ul.chosen-results li").click
end

Use like this: select_first_from_chosen('post[name]')

@JeremiahChurch
Copy link

To guarantee an exact match rather than a partial match aka - find 'OR' and not match 'MORE'
replace
the line

find("##{field[:id]}_chosen ul.chosen-results li", text: item_text).click

with

find("##{field[:id]}_chosen ul.chosen-results li", text: /\A#{Regexp.quote(item_text)}\z/).click

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment