如何使用capybara DSL测试Select2元素?

我在页面上有一个Select2元素,通过ajax加载结果。 想用capybara / rspec(使用poltergeist驱动程序)测试这个,但是因为Select2元素实际上是作为隐藏字段开始的,然后在处理完结果后填充

    ,没有正常的selectfill_in或者choose帮手会工作。

    我现在拥有的是类似的东西

      it "should have a search field for events" do click_link "Select an Event" # this works as expected within('.select2-container') do # works find('.select2-search input').set(event.description[0,5]) # won't work! find(:xpath, "li[text()='#{event.description}']").click end click_button "Search" page.should have_content("Displaying all 2 photos") end 

    上面的第4行,显然capybara可以找到元素,但值不会改变,Select2永远不会进行ajax调用。 (不能使用普通的fill_in ,因为搜索字段元素没有label,id或name属性)

    我创建了一个可以与Cucumber一起使用的帮助器,它没有sleep所以它比上面的方法更快。 如果您使用Select2提供的createSearchChoice这也适用。

    把它放在features/support/select2_helper.rb

     module Select2Helper def select2(value, attrs) first("#s2id_#{attrs[:from]}").click find(".select2-input").set(value) within ".select2-result" do find("span", text: value).click end end end World(Select2Helper) 

    像这样用它:

     Then(/^I select2 "([^"]*)" from "([^"]*)"$/) do |value, select_name| select2 value, from: select_name end 

    用Rails 4.1.1和Cucumber 1.3.15测试。

    不要挠挠头,这样做会有效

     select "option_name_here", :from => "Id Of Your select field" 

    我尝试了每一个模块和每一个该死的东西,最后只是通过简单的代码行完成了没有任何助手和这样的事情。

    对于页面上的多个select2组件,我创建了以下适用于我的帮助器方法:

     def select2(id, value) page.execute_script %Q{ i = $('#s2id_#{id} .select2-input'); i.trigger('keydown').val('#{value}').trigger('keyup'); } sleep 2 find('div.select2-result-label').click end def remove_all_from_select2(id) page.execute_script %Q{ $('#s2id_#{id} .select2-choices a').click(); } end def remove_from_select2(id, value) page.execute_script %Q{ $('#s2id_#{id} .select2-choices div:contains("#{value}")').closest('li').find('a').click(); } end 

    我能够通过使用page.execute_script手动将所需的值和keyup事件page.execute_script到搜索字段中来解决这个问题。

      it "should have a search field for events" do click_link "Select an Event" page.execute_script("i = $('.select2-container input').first(); i.val('#{event.description[0,4]}').trigger('keyup');"); sleep 2 find('.select2-results li:first-child').click click_button "Search" page.should have_content("Displaying all 2 photos") end 

    对于那些苦苦挣扎Select2 倍数的人

    奇怪的是我发现select_tag有多个:true似乎热衷于为每个条目生成html,如:

     
    value

    而不是

     
    value

    无益地将内容放在跨度之外。

    为了用水豚来测试它我有两种方法:

     # for most select2s def select2_select(value, id) # This methods requires @javascript in the Scenario first("#s2id_#{id}").click find(".select2-input").set(value) within ".select2-result" do if !find("span").text.empty? find("span", text: value).click elsif !find("div").text.empty? find("div", text: value).click else fail 'neither span nor div within this select2, did you get the id of the select2 right?' end end end # for select_tag select2s which are multiple:true def select2_select_multiple(select_these, id) # This methods requires @javascript in the Scenario [select_these].flatten.each do | value | first("#s2id_#{id}").click found = false within("#select2-drop") do all('li.select2-result').each do | result | unless found if result.text == value result.click found = true end end end end end end 

    后者因我的喜好而过于苛刻,所以我尽可能使用第一个,并希望最终取代后者。

    HAML使用:

     = select_tag "some_id", options_for_select(['hello','world']), multiple: true, include_blank: true 

    JS:

     $("#some_id").select2(); 

    灵感来自这个答案和一个Capybara select2帮手,我想出了同一页面上单选和多选的多个select2字段看起来很健壮的东西:

     def select2(value, attrs) s2c = first("#s2id_#{attrs[:from]}") (s2c.first(".select2-choice") || s2c.find(".select2-choices")).click find(:xpath, "//body").all("input.select2-input")[-1].set(value) page.execute_script(%|$("input.select2-input:visible").keyup();|) drop_container = ".select2-results" find(:xpath, "//body").all("#{drop_container} li", text: value)[-1].click end 

    这适用于带有远程数据源的下拉样式select2:

      def select2(value, from:) execute_script("$('##{from}').select2('open')") find(".select2-search__field").set(value) find(".select2-results li", text: /#{value}/).click end 

    from必须是构建select2的常规select标记的ID。

    我有两个远程select2s。 我在第一个中搜索一个字符串,根据找到的结果,第二个字符串被填充。 在尝试了capybara-select2 gem以及此处列出的所有解决方案后,我不得不提出自己的解决方案,因为它们都没有用于搜索。 在我的情况下,我选择的并不重要,所以没有尝试选择具有特定值的结果标签。 希望这有助于我的情况。

     Given(/^I have selected "(.*?)" category$/) do |arg1| page.find(:css, ".select2-choice.select2-default").click page.find(:css, "#s2id_autogen1_search").set "Dip Boya" sleep 2 page.all(:css, '.select2-result-label')[1].click end Given(/^I have selected "(.*?)" variation$/) do |arg1| page.find(:css, ".select2-choice.select2-default").click page.all(:css, '.select2-result-label')[1].click end 

    简单回答:

     page.find('.select2-drop-active .select2-input').set('foo') page.find('.select2-drop-active .select2-input').native.send_keys(:return) 

    嘿,我不确定是否还有人关心,但我也有这个问题,我找到了一个简单的方法来处理它。

    首先,我不会将类添加到每个下拉选择中,而是像全局那样添加:

      class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput def input_html_classes super.push('chosen-select') end end 

    因此,当我开始遇到capybara无法使用select2下拉列表的问题时,我的解决方案是仅在测试环境中使用全局推送:

      class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput unless Rails.env.test? def input_html_classes super.push('chosen-select') end end end 

    我曾经使用capybara-select2gem,但似乎它不再被维护:(

     def select2(id, value) find("##{id} ~ span.select2").click within ".select2-results" do find("li", text: value).click end end 

    这是针对更新版本的select2的解决方案 – 特别是select2-rails(4.0.0)gem:

    将它放在features/support/feature_helpers.rb ,然后将其包含在spec_helper.rb文件中, config.include FeatureHelpersRSpec.configure do |config| config.include FeatureHelpers 。 块。

     module FeatureHelpers def fill_in_select2(container_selector, with: '') page.execute_script %Q{ i = $('#{container_selector} .select2-search__field'); i.trigger('keydown').val('#{with}').trigger('keyup'); } sleep 2 find('.select2-results__option--highlighted').click end end 

    然后像在fill_in中使用fill_in_select2一样使用fill_in ,但是包含具有适当前缀符号的容器元素的类或id。 (例如fill_in_select2 '.actions_list', with: 'bob@testmaster1000.com' )。

    注意 :这会在输入文本后选择下拉列表中的第一个元素。

    在Rails 4.2.5.2,Capybara 2.7.1和Capybara-Webkit 1.11.1中进行了测试

    在花费了更长的时间之后,我终于通过使用xpath选择器构建Brandon McInnis的答案了。

     module Select2Helper def fill_in_select2(container_selector, with: '') page.execute_script %Q{ i = $('#{container_selector} .select2-search__field'); i.trigger('keydown').val('#{with}').trigger('keyup'); } sleep 2 find(:xpath, "//body").all("#{container_selector} li", text: with)[-1].click end end 

    对于select2 4.0与capybara-webkit的组合,我尝试了基于execute_script的解决方案,但它们不起作用,因为capybara无法找到生成的’li’元素。 我终于根据send_keys确定了这个简单的解决方案。 因为我使用远程数据源,所以我添加了一个小睡眠以允许结果显示:

     module Select2Helpers def fill_in_select2(field_name, with: '') field = find("##{field_name}") parent = field.find(:xpath, './/..') ui = parent.find('.select2-search__field') ui.send_keys(with) sleep 0.5 ui.send_keys(:enter) sleep 0.1 end end 

    请注意,您可能需要更新到最新的capybara-webkit(1.14.0)才能使其正常工作。

    https://github.com/goodwill/capybara-select2与js: true指定对我来说很好。 干杯

    这对我来说有用,即使使用select2 AJAX自动完成:

     find('#user_id').sibling('span.select2').click find('.select2-search__field').set('ABCDEF') find('.select2-results li', text: 'ABCDEF').click 

    您可以使用capybara-select-2 gem ,它将为您完成所有工作。 只需将search: true传递给helper选项即可进行Ajax调用:

     select2 'Marriage', from: 'Event', search: true