2012-10-07 6 views
16

Ho un elemento Select2 in una pagina che carica i risultati tramite ajax. Vorresti provare questo con capybara/rspec (usando il driver poltergeist), ma poiché l'elemento Select2 inizia effettivamente come un campo nascosto, e popola uno <ul> una volta che i risultati vengono elaborati, nessuno dei normali aiutanti select, fill_in o choose lavoro.Come testare un elemento Select2 con DSL capybara?

Quello che ho ora è sopra qualcosa come

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 

linea 4, a quanto pare capibara può trovare l'elemento, ma il valore non è cambiato e Select2 mai fa la sua chiamata AJAX. (Non è possibile utilizzare il normale fill_in lì perché l'elemento di campo di ricerca non ha etichetta, id, o attributi nome)

+0

Un problema del tutto frustrante – guero64

risposta

3

sono stato in grado di risolvere questo utilizzando page.execute_script di incidere manualmente il valore necessario e keyup evento nel campo di ricerca.

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 
+0

qui è un metodo capibara di supporto che fa meglio e non come legato alle specifiche etichette dei campi e gli elementi https://gist.github.com/3849340 – sbeam

+2

Questo dovrebbe funzionare, ma ottengo l'errore "Elemento non selezionabile al punto (296, 637). Altro elemento riceverebbe il clic:

" – lafeber

+2

Questo non è quello che vuoi , ha un sonno di 2 secondi. – Jankeesvw

4

per più componenti Select2 sulla tua pagina, ho creato i seguenti metodi di supporto che lavorano per me:

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 
+1

Questo mi ha fatto sulla buona strada. Ho perfezionato il metodo select2 per creare un metodo di query-and-selection generico che funzioni con Select2 3.4 https://gist.github.com/onyxrev/6970632 – onyxrev

0

Risposta semplice:

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

Hey io non sono sicuro che a qualcuno interessa ancora, ma ho avuto anche questo problema e ho trovato un modo semplice per affrontarlo.

Prima di tutto, io non aggiungere la classe ad ogni discesa selezionare, ma piuttosto lo faccio a livello globale in questo modo:

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

Così, quando ho iniziato ad avere problemi con capibara non essere in grado di utilizzare il select2 discesa mio fix era quella di utilizzare solo la spinta globale se non in ambiente di test:

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

ho usato per usare la gemma capibara-select2 ma sembra come se non viene più mantenuta :(

1

Ho due remote select2. Cerco una stringa nella prima e in base al risultato trovato, la seconda viene riempita. Dopo aver provato la gemma di capybara-select2 e tutte le soluzioni elencate qui e là, ho dovuto inventare la mia soluzione perché nessuna di esse ha funzionato per la ricerca. Nel mio caso, ciò che seleziono non è importante, quindi non ho provato a selezionare un'etichetta di risultato con un valore specifico. Spero che questo aiuti qualcuno nella mia situazione.

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 
7

ho creato un aiutante che è possibile utilizzare con cetrioli, non ha un sleep quindi è più veloce rispetto ai metodi di cui sopra. Questo funziona anche se si utilizza il createSearchChoice fornito da Select2.

Metti in 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) 

Utilizzare in questo modo:

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

Testato con Rails 4.1.1 e 1.3.15 cetriolo.

+0

Funziona! Anche per i multiseletti select2! Signore, sono nel tuo debito -_- – xxjjnn

+0

A volte invece di una span c'è un div, quindi ho usato 'find (" span "). Text.empty? ? (trova ("div", text: value) .click): (find ("span", text: value) .click) 'sull'ultima ricerca – xxjjnn

+0

Non funziona per me dato che ho due campi select2. – gamov

2

Per coloro che lottano con Select2 multipla:

Stranamente ho scoperto che select_tag con più: true sembra desideroso di generare codice HTML per ogni voce come:

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

piuttosto che

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

Inserimento non consentito dei contenuti al di fuori dello span.

Al fine di testare con capibara ho due metodi:

# 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 

Quest'ultimo è troppo hacky per i miei gusti, per cui uso il primo, ove possibile, e la speranza di sostituire quest'ultima alla fine.

HAML utilizzato:

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

JS:

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

Devo usare find ('# s2id _ # {id} a'). fare clic per farlo funzionare – gamov

2

Ispirato da questa risposta e uno a Capybara select2 helper mi si avvicinò con quello che sembra robusto per più Select2 settori sia della selezione singola e multi seleziona sulla stessa pagina:

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 
+0

Questa soluzione ha funzionato per me. – krstck

6

Smettere di grattarsi la testa, fare questo e funzionerà

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

Ho provato ogni modulo e ogni cosa maledetta che potevo e alla fine appena fatto questo senza alcun aiuto e cose del genere da una semplice riga di codice.

+1

Sto usando questo e funziona. Ma non penso che testerai i js da select2, quindi non stai effettivamente testando ciò che sta vedendo l'utente finale. Ma questo potrebbe non essere sempre un problema. – Ozgar

0

Questo funziona per me su uno stile di discesa select2 con un'origine dati remota:

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

from deve essere l'ID del normale tag select che il select2 è costruito da.

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

Ecco una soluzione per una versione più recente di select2 - in particolare i Select2-rotaie (4.0.0) gemma:

posto in features/support/feature_helpers.rb, e poi includerlo nel spec_helper.rb file con config.include FeatureHelpers in il tuo blocco 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 

Quindi utilizzare fill_in_select2 proprio come si usa in fill_in Capybara, ma includere la classe o l'ID di un elemento contenitore con il simbolo prefisso appropriato. (ad esempio fill_in_select2 '.actions_list', with: '[email protected]').

Nota: seleziona il primo elemento nel menu a discesa dopo l'immissione del testo.

testato in Rails 4.2.5.2, Capybara 2.7.1, e Capybara-Webkit 1.11.1

0

Dopo aver trascorso più tempo su ciò che mi piacerebbe, ho finalmente funzionato costruendo la risposta di Brandon McInnis usando un selettore 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 
0

Per select2 4.0 in combinazione con capibara-webkit, ho provato le soluzioni execute_script-based, ma non ha funzionato perché capibara non riusciva a trovare l'elemento risultante 'li'. Alla fine ho optato per questa semplice soluzione basata su send_keys. Perché io uso una fonte di dati a distanza, ho aggiunto un piccolo sonno per consentire i risultati di apparire:

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 

Si noti che potrebbe essere necessario aggiornare all'ultima capibara-webkit (1.14.0) per fare questo lavoro.

0

Ecco ciò che funziona per me, anche con select2 AJAX completamento automatico:

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