如何使用 capybara DSL 测试 Select2 元素?
Posted
技术标签:
【中文标题】如何使用 capybara DSL 测试 Select2 元素?【英文标题】:How to test a Select2 element with capybara DSL? 【发布时间】: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 或名称属性)
【问题讨论】:
一个非常令人沮丧的问题 【参考方案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-select2 和 js: true
指定对我来说效果很好。干杯
【讨论】:
我建议迁移到更新的 gem github.com/Hirurg103/capybara_select2,它支持最新版本的 select2gem install capybara-select-2
【参考方案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'
【讨论】:
以上是关于如何使用 capybara DSL 测试 Select2 元素?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Capybara + Selenium 测试响应代码
如何使用rails cucumber,rspec,capybara在视图(dhtml)中测试动态部分?
如何使用 Capybara Rspec Matchers 测试演示者?
问:如何使用 Turnip、capybara 和 Gherkin 测试 ActionMailer Deliver_later