【问题标题】:How to test a Select2 element with capybara DSL?如何使用 capybara DSL 测试 Select2 元素?
【发布时间】:2012-09-28 02:18:51
【问题描述】:

我在通过 ajax 加载结果的页面上有一个 Select2 元素。想用 capybara/rspec 测试这个(使用 poltergeist 驱动程序),但由于 Select2 元素实际上是作为隐藏字段开始的,然后在处理结果后填充<ul>,没有正常的select,@ 987654324@ 或 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,因为搜索字段元素没有标签、id 或名称属性)

【问题讨论】:

  • 一个非常令人沮丧的问题

标签: ruby-on-rails capybara capybara-webkit jquery-select2


【解决方案1】:

别挠头了,这样做会奏效的

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

我尝试了每一个模块和每一个该死的东西,最后只用一行简单的代码就做到了,没有任何帮助。

【讨论】:

  • 我正在使用它并且它有效。但我认为您不会从 select2 测试 js,因此您实际上并没有测试最终用户所看到的内容。但这可能并不总是一个问题。
【解决方案2】:

我创建了一个可以与 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 测试。

【讨论】:

  • 有效!即使对于 select2 多选!先生,我欠你的-_-
  • 有时不是span有一个div,所以我在最后一次find时使用了find("span").text.empty? ? (find("div", text: value).click) : (find("span", text: value).click)
  • 受此答案和bit.ly/18yhpb3 的启发,我想出了对于同一页面上的单选和多选的多个 select2 字段来说似乎很健壮的方法:(将代码移动到单独的答案格式化目的)
【解决方案3】:

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

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

【讨论】:

  • 我设法通过游戏完成了我的任务。感谢您指出!
【解决方案4】:

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

  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

【讨论】:

  • 这里有一个 capybara 辅助方法,它可以更好地做到这一点,并且不依赖于特定的字段标签和元素 gist.github.com/3849340
  • 这应该可以,但我收到错误“元素在点 (296, 637) 处不可点击。其他元素将收到点击:
    "
  • 这不是你想要的,它有 2 秒的睡眠时间。
  • 是的,使用其他答案之一,这是一个黑客。我现在的解决方案是不使用 Select2。
  • 这对我也很有效 find('#select_field option:first-child').click
【解决方案5】:

对于您页面上的多个 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

【讨论】:

  • 这让我走上了正轨。我改进了您的 select2 方法,以创建与 Select2 3.4 gist.github.com/onyxrev/6970632 一起使用的通用查询和选择方法
【解决方案6】:

对于那些在 Select2 multiple中苦苦挣扎的人:

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

<div class="select2-result-label">
  <span class="select2-match"></span>
  value
</div>

而不是

<div class="select2-result-label">
  <span class="select2-match">value</span>
</div>

将内容放在跨度之外毫无帮助。

为了用 capybara 测试它,我有两种方法:

# 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();

【讨论】:

  • 我必须使用 find('#s2id_#{id} a').click 才能工作
【解决方案7】:

从这个答案和Capybara select2 helper 的一个答案中得到启发,我想出了对于同一页面上的单选和多选的多个 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

【讨论】:

    【解决方案8】:

    这适用于带有远程数据源的下拉样式 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 的常规选择标签的 ID。

    【讨论】:

      【解决方案9】:

      我有两个远程 select2。我在第一个中搜索一个字符串,根据找到的结果,第二个被填充。 在尝试了 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
      

      【讨论】:

        【解决方案10】:

        https://github.com/goodwill/capybara-select2js: true 指定对我来说效果很好。干杯

        【讨论】:

        【解决方案11】:

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

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

        【讨论】:

          【解决方案12】:

          简单回答:

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

          【讨论】:

            【解决方案13】:

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

            首先,我不会将类添加到每个下拉选择中,而是像这样在全局范围内进行:

                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-select2 gem,但它似乎不再被维护:(

            【讨论】:

              【解决方案14】:
              def select2(id, value)
                find("##{id} ~ span.select2").click
                within ".select2-results" do
                  find("li", text: value).click
                end
              end
              

              【讨论】:

                【解决方案15】:

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

                将其放入features/support/feature_helpers.rb,然后将其包含在spec_helper.rb 文件中,并在RSpec.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
                

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

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

                在 Rails 4.2.5.2、Capybara 2.7.1 和 Capybara-Webkit 1.11.1 中测试

                【讨论】:

                  【解决方案16】:

                  在花费了比我想要的更长的时间之后,我终于通过使用 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
                  

                  【讨论】:

                    【解决方案17】:

                    对于 select2 4.0 与 capybara-webkit 的结合,我尝试了基于 execute_script 的解决方案,但它们不起作用,因为 capybara 找不到生成的 'li' 元素。我最终确定了这个基于 send_keys 的简单解决方案。因为我使用的是远程数据源,所以我加了一个小sleep让结果出现:

                    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) 才能完成这项工作。

                    【讨论】:

                      【解决方案18】:

                      这个助手为我工作(使用占位符):

                        # Add this helper
                        def select2(placeholder, option)
                          find("select[data-placeholder='#{placeholder}'] + .select2").click
                          within '.select2-results' do
                            find('span', text: option).click
                          end
                        end
                      

                      然后这样称呼它:

                      select2 'Placeholder', 'some option'
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2018-07-07
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2017-12-12
                        • 2015-09-04
                        相关资源
                        最近更新 更多