How to use capybara to select a select2 drop-down field

4.3k views Asked by At

There is help online for using select2 with capybara (see links below), but no help in particular as far as I have seen for select2 drop-down fields. I have tried all kinds of things, including trying to fill in the field when :js => false (using something along the lines of find(:xpath, "//input[@id='product_manufacturer_id']").set "Test product manufacturer") or variations on the solutions that work on other select2 fields (see links given below). Nothing is working for me so far.

Notes on my configuration:

  • Using select2 version 3
  • Using capybara WebKit
  • This particular field is also using simple form, and is an association (so has f.association...). Particularly, ProductManufacturer instances are in a has_many relationship with products.
  • The select2 drop-down field is supposed to be dynamically populated by ProductManufacturer instances which match the query text (i.e., the text you type into the search field).

In case it is helpful to see how I am implementing the factory:

Here is my factory file:

factory :product do
  name "Test product"
  url { Faker::Name.name.parameterize }
  access_level 1
  product_manufacturer
end

factory :product_manufacturer do
  name "Test product manufacturer"

  factory :product_manufacturer_with_product do
    transient do
      products_count 1
    end

    after(:create) do |product, evaluator|
      create_list(:product,
                   evaluator.products_count,
                   product: product)
    end
  end
end

And then, before the test starts, I run:

@product_manufacturer = create(:product_manufacturer)

My latest attempt: My helper method (which is working for my other select2 fields):

def select2_choose(id, options)
  page.execute_script  "$('#{id}').trigger('keydown').val('{options[:query]}').trigger('keyup');"
  find(".select2-result-label", :text => options[:choose]).click
end

And then how I implement it:

select2_choose( "#s2id_autogen7", 
  :query => @product_manufacturer.name[0...-2], 
  :choose => @product_manufacturer.name)

Which outputs the following error message:

Failure/Error: create_product
Capybara::ElementNotFound:
   Unable to find css ".select2-result-label" with text "Test product manufacturer"

(which basically means that it has found and clicked on the drop-down box, and it has put in the query text, "Test product manufacture". But select2 was not finding the option from the database to find it.)

Note that I have successfully used factory_girl to generate my ProductManufacturer instance object @product_manufacturer, and calling things such as puts @product_manufacturer is successful, returning the instance object: ProductManufacturer:0x007f0145f9cb38>.

Here is a screenshot from right before the test fails: screenshot

Other questions that are related but do not fully solve this issue:

- Selecting select2 drop downs (but not in capybara):

How to select option in drop down using Capybara

Unable to select item in Select2 drop down

- Selecting select2 options in capybara (but not with drop downs):

How to test a Select2 element with capybara DSL? (Note: I successfully used answers from here to select non-drop-down select2 fields)

- selecting select2 drop-down using selenium

Selenium Select2 command for drop-down box

4

There are 4 answers

3
Thomas Walpole On BEST ANSWER

Capybara's field actions (fill_in, set, etc) only work with basic html form fields, not with JS driven widgets since they usually hide the basic fields. The key to working with any JS driven widget in Capybara is to perform the actions a user would have to perform, which in this case is click on the visible element to trigger the dropdown then click on the element you want to select.

As an example, to select "California" from the first select2 dropdown on the example page http://select2.github.io/examples.html it could be done like

first('.select2-container', minimum: 1).click
find('li.select2-results__option[role="treeitem"]', text: 'California').click

If you want to do it by typing in the search term instead of clicking on the result it would be something like

first('.select2-container', minimum: 1).click
find('.select2-dropdown input.select2-search__field').send_keys("California", :enter)

Using execute_script and trigger are bad ideas if you're testing a web app since it bypasses most of the checks on what a user could actually do, they're fine if you're just automating a page

1
RyanQuey On

As it turns out, my problem was simply that I needed to run the factories before loading the page with the forms on so that they could be selectable by select2.

In other words, I was trying to do this:

click_link "New Product"
create(:product_manufacturer)

when I should have been doing this:

create(:product_manufacturer)
click_link "New Product"
0
Luis Zambrano On

click on the dropdown arrow to open the selection choices

find('span.select2-selection__arrow').click

click on the option to select it

find('li.select2-results__option', text: 'Exactly content/text of your search').click

More info on here

0
Hirurg103 On

You may also look at the capybara-select-2 gem which provides select2 helper for Capybara. It works with select2 version 3. Also it supports version 4 (just in case if you upgrade)

select2 'Test product manufacturer', from: 'Product manufacturer'

If you need to search for an option (or make an Ajax call) you can do the following:

select2 'Test product manufacturer', from: 'Product manufacturer', search: true