Come ottenere il nodo genitore in Capybara?


85

Sto lavorando con molti plugin jQuery, che spesso creano elementi DOM senza id o altre proprietà di identificazione, e l'unico modo per ottenerli in Capybara (per fare clic ad esempio) - è ottenere prima il loro vicino (un altro figlio del suo antenato) . Ma non ho trovato da nessuna parte, Capybara supporta queste cose, ad esempio:

find('#some_button').parent.fill_in "Name:", :with => name

?


Inoltre sarà molto utile per me, se dici, Capybara genera clic su elementi con {display: hidden}, e c'è un modo per trovare elementi in qualche ambito, dove display! = Hidden?
sandrew

Questa è una domanda a parte, ma dipende dal driver che stai utilizzando. webrat troverà le cose nascoste felicemente, ma il selenio non è così felice di fare clic su elementi che non puoi vedere.
jamuraa

Risposte:


111

Ho davvero trovato utile la risposta di jamuraa, ma scegliere xpath completo mi ha dato un incubo di una stringa nel mio caso, quindi ho felicemente utilizzato la possibilità di concatenare i find in Capybara, permettendomi di mescolare css e xpath selection. Il tuo esempio sarebbe quindi simile a questo:

find('#some_button').find(:xpath,".//..").fill_in "Name:", :with => name

Aggiornamento Capybara 2.0 : find(:xpath,".//..")molto probabilmente si verificherà un Ambiguous matcherrore. In tal caso, usa first(:xpath,".//..")invece.


Grazie per l'idea, non ci avrei mai pensato! Stavo facendo el.parent per un elemento td che ho trovato con find (: css), ma per qualche motivo non capisco, el.parent stava restituendo # <Capybara :: Document>. el.find (: xpath, ".// ..") d'altra parte restituisce # <Capybara :: Element tag = "tr">, che è ciò di cui avevo bisogno.
Tyler Rick

Un altro modo per trovare ricorsivamente un certo nodo genitore è con il selettore ancestor-or-self di xpath. Check it out stackoverflow.com/questions/1362466/...
vrish88

25
Non è necessario .//..trovare il genitore .., è sufficiente e nemmeno questo è ambiguo.
Eamon Nerbonne

ty! So che questo commento è un po 'in ritardo per la festa, ma l'ho condensato come segue dopo aver letto la modifica e il commento di Eamon: el.first (: xpath,' .. ')
aschyiel

39

Non c'è un modo per farlo con capybara e CSS. Ho usato XPath in passato per raggiungere questo obiettivo, tuttavia, che ha un modo per ottenere l'elemento genitore ed è supportato da Capybara:

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name

2
Quando eseguo una ricerca xpath simile, ottengo un errore Nokogiri che dice che l'espressione non è valida. Ho aggiunto un asterisco davanti alla staffa quadrata aperta nell'espressione per correggere l'espressione:find(:xpath, '//*[@id="some_button"]/..')
Andrew Ferk

35

Ho trovato quanto segue che funziona:

find(:xpath, '..')

Capybara è stato aggiornato per supportare questo.

https://github.com/jnicklas/capybara/pull/505


1
Mi sembra che tu stia rispondendo / completando una risposta precedente qui ("Questo" cosa "non funzionava"?). Sarebbe meglio se fosse una risposta completa e indipendente. Quindi ti consiglio di modificarlo. ;-)
helenov

Posso confermare. Con l'ultimo Capybara 2.14.4, questo è il modo corretto per ottenere il nodo genitore.
fny

10

Se ti sei imbattuto in questo cercando di capire come trovare qualsiasi nodo genitore (come nell'antenato ) (come accennato nel commento di @ vrish88 sulla risposta di @Pascal Lindelauf):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')

5

Questa risposta riguarda come manipolare un elemento fratello che è ciò a cui credo alluda la domanda originale

L'ipotesi della tua domanda funziona con una piccola modifica. Se il campo generato dinamicamente ha questo aspetto e non ha un ID:

<div>
  <input></input>
  <button>Test</button>
</div>

La tua domanda sarebbe quindi:

find('button', text: 'Test').find(:xpath, "..").find('input').set('whatever')

Se l'input generato dinamicamente viene allegato con un elemento id (fai attenzione a questi anche se come in angular, sono soliti cambiare in base all'aggiunta e all'eliminazione di elementi) sarebbe qualcosa del genere:

find('button', text: 'Test').find(:xpath, "..").fill_in('#input_1', with: 'whatever')

Spero che aiuti.


4

Sto usando un approccio diverso trovando prima l'elemento genitore usando il testo all'interno di questo elemento genitore:

find("<parent element>", text: "text within your #some_button").fill_in "Name:", with: name

Forse questo è utile in una situazione simile.


1
Questa è un'ottima opzione. L'ambito delle azioni dell'interfaccia utente su una parte della pagina che contiene un testo particolare è un caso d'uso comune per me.
clemensp

2

Avevo bisogno di trovare un antenato con una classe CSS, sebbene fosse indeterminato se l'antenato di destinazione avesse una o più classi CSS presenti, quindi non ho visto un modo per fare una query xpath deterministica. Ho elaborato questo invece:

def find_ancestor_with_class(field, cssClass)
  ancestor = field
  loop do
    ancestor = ancestor.find(:xpath, '..')
    break if ancestor.nil?

    break if ancestor.has_css? cssClass
  end

  ancestor
end

Attenzione: usalo con parsimonia, potrebbe costarti molto tempo nei test, quindi assicurati che l'antenato sia a pochi salti di distanza.


Speedup: sostituisci la tua seconda pausa con break if ancestor[:class].split(" ").include?(css_class).
hakunin

@hakunin Sono curioso di sapere quanto di un aumento di velocità stai vedendo? Significativo?
kross

Non è possibile eseguire il test ora, ma has_css sembrava richiedere un secondo, mentre l'abbinamento della classe sembrava immediato.
hakunin

Capybara ora ha un ancestor(selector)metodo integrato. Vedi github.com/teamcapybara/capybara/commit/…
Tyler Rick

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.