Как протестировать элемент Select2 с помощью capybara DSL?
У меня есть элемент Select2 на странице, которая загружает результаты через ajax. Хотелось бы проверить это с помощью capybara/rspec (используя драйвер poltergeist), но так как элемент Select2 фактически запускается как скрытое поле, а затем заполняет результаты <ul>
после обработки, ни один из обычных select
, fill_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
там, потому что элемент поля поиска не имеет атрибутов метки, идентификатора или имени)
Ответы
Ответ 1
Я создал помощника, который вы можете использовать с Cucumber, он не имеет sleep
, поэтому он быстрее, чем методы выше. Это также работает, если вы используете createSearchChoice
, предоставленный Select2.
Поместите его в 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.
Ответ 2
Прекратите царапать голову, сделайте это, и она будет работать
select "option_name_here", :from => "Id Of Your select field"
Я пробовал каждый модуль и каждую чертову вещь, которую я мог, и, наконец, просто сделал это без какого-либо помощника и таких вещей простой строкой кода.
Ответ 3
Для нескольких компонентов 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
Ответ 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
Ответ 5
Для тех, кто борется с Select2 multiple:
Странно я обнаружил, что select_tag с несколькими: true, похоже, стремится генерировать 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();
Ответ 6
Вдохновленный этим ответом и один в 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
Ответ 7
У меня есть два удаленных select2s. Я ищу строку в первой и, согласно найденному результату, второй заполняется.
После того, как вы попробовали камень capybara-select2 и все перечисленные здесь решения, мне пришлось придумать собственное решение, потому что ни один из них не работал для поиска.
В моем случае то, что я выбираю, не важно, поэтому не пыталось выбрать метку результата с определенным значением. Надеюсь, это поможет кому-то в моей ситуации.
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
Ответ 8
Простой ответ:
page.find('.select2-drop-active .select2-input').set('foo')
page.find('.select2-drop-active .select2-input').native.send_keys(:return)
Ответ 9
Эй, я не уверен, что кто-то по-прежнему заботится, но у меня тоже была эта проблема, и я нашел простой способ справиться с этим.
Во-первых, я не добавляю класс к каждому раскрывающемуся элементу, но я делаю его глобально следующим образом:
class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input_html_classes
super.push('chosen-select')
end
end
Итак, когда у меня возникли проблемы с capybara, которые не могли использовать раскрывающееся меню select2, мое исправление состояло в том, чтобы использовать глобальный push, если не в тестовой среде:
class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput
unless Rails.env.test?
def input_html_classes
super.push('chosen-select')
end
end
end
Я использовал камень capybara-select2, но кажется, что он больше не поддерживается: (
Ответ 10
Это работает для меня по выпадающему стилю 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
должен быть идентификатором регулярного тега select, из которого сделан select2.
Ответ 11
def select2(id, value)
find("##{id} ~ span.select2").click
within ".select2-results" do
find("li", text: value).click
end
end
Ответ 12
Здесь решение для более новой версии select2 - в частности, жемчуг select2-rails (4.0.0):
Поместите его в features/support/feature_helpers.rb
, а затем добавьте его в свой spec_helper.rb
файл с config.include FeatureHelpers
в блок RSpec.configure do |config|
.
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_select2
так же, как вы использовали бы fill_in
в Capybara, но включите класс или идентификатор элемента контейнера с соответствующим символом префикса. (например, fill_in_select2 '.actions_list', with: '[email protected]'
).
Примечание: это выбирает первый элемент в выпадающем меню после ввода текста.
Протестировано в Rails 4.2.5.2, Capybara 2.7.1 и Capybara-Webkit 1.11.1
Ответ 13
Проведя больше на этом, чем хотелось бы, я, наконец, получил его работу, построив ответ Брэндона Макинниса, используя селектор xpath.
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
Ответ 14
Для 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), чтобы сделать эту работу.
Ответ 15
https://github.com/goodwill/capybara-select2 с js: true
, указанным для меня отлично. Приветствия