2011-02-01 18 views
70

Estoy trabajando con muchos plugins jQuery, que a menudo crean elementos DOM sin identificación u otras propiedades de identificación, y la única forma de obtenerlos en Capybara (por ejemplo, hacer clic) es obtener a su vecino (otro hijo de su ancestro) primero. Pero no encontré nada, ¿Capibara admite tales cosas, por ejemplo:¿Cómo obtener el nodo principal en Capibara?

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

?

+0

También será muy útil para mí, si lo dices, ¿Carpincho genera clic en elementos con {display: hidden}, y hay una manera de encontrar elementos en algún ámbito, donde display! = Hidden? – sandrew

+0

Esta es una pregunta aparte, pero depende del controlador que esté usando. webrat encontrará las cosas ocultas felizmente, pero el selenio no está contento de hacer clic en los elementos que no puedes ver. – jamuraa

Respuesta

99

realmente me encontré con la respuesta de Jamuraa útiles, pero a su favor completa XPath di una pesadilla de cuerda en mi caso, así que felizmente utilicé la capacidad de concatenar hallazgos en Capibara, permitiéndome mezclar la selección de css y xpath. Su ejemplo sería el siguiente aspecto:

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

Carpincho actualización 2.0: muy probable que resulte en un error Ambiguous match. En ese caso, use first(:xpath,".//..") en su lugar.

+0

Gracias por esa idea - ¡Nunca habria pensado en eso! Estaba haciendo el.parent para un elemento td que encontré con find (: css), pero por alguna razón no entiendo, el.parent devolvió # . el.find (: xpath, ".// ..") por otro lado devuelve # , que es lo que necesitaba. –

+0

Otra forma de encontrar recursivamente un determinado nodo padre es con el selector ancestro-o-propio de xpath. Échale un vistazo http://stackoverflow.com/questions/1362466/xpath-recursive-ancestor-search – vrish88

+0

+1 ¡Gracias por actualizar tu respuesta! –

37

No hay una manera de hacer esto con carpincho y CSS. He usado XPath en el pasado para llevar a cabo este objetivo, sin embargo, que sí tiene una forma de obtener el elemento padre y con el apoyo de Carpincho:

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

Cuando hago un xpath find similar, obtengo un error de Nokogiri que dice que la expresión no es válida. Añadí un asterisco delante del bracket cuadrado abierto en la expresión para corregir la expresión: 'find (: xpath, '// * [@ id =" some_button "]/..')' –

3

estoy usando un enfoque diferente al encontrar el elemento padre por primera vez el texto dentro de este elemento padre:

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

Tal vez esto es útil en una situación similar.

+1

Esta es una gran opción. El alcance de las acciones de la interfaz de usuario a una parte de la página que contiene algún texto en particular es un caso de uso común para mí. – clemensp

21

Esto no funcionaba para mí, con el error:

Ambiguous match, found 2 elements matching xpath ".//.." 

encontré la siguiente que hace el trabajo:

find(:xpath, '..') 

Carpincho ha sido actualizado para soportar esto.

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

+0

Me parece que está respondiendo/completando una respuesta anterior aquí ("¿Esto" qué "no estaba funcionando"?). Sería mejor si fuera una respuesta completa e independiente. Así que te recomiendo que lo edites. ;-) – helenov

+0

Puede confirmar. Con el último Capybara 2.14.4, esta es la forma correcta de obtener el nodo primario. – fny

6

Si me encontré con este tratando de encontrar la manera de encontrar cualquier padre (como en ancestro) nodo (como se insinuó en el comentario de @ vrish88 en la respuesta de @Pascal Lindelauf):

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

Necesitaba encontrar un ancestro con una clase css, aunque era indeterminado si el ancestro objetivo tenía una o más clases CSS presentes, por lo que no vi una forma de hacer una consulta xpath determinista. Trabajé con esto en su lugar:

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 

Advertencia: usar con moderación, que le podría costar mucho tiempo en las pruebas por lo que asegúrese de que el ancestro está a sólo unos saltos de distancia.

+0

Speedup: reemplace su segundo descanso con 'break si ancestro [: clase] .split (" ") .include? (Css_class)'. – hakunin

+0

@hakunin Tengo curiosidad por la velocidad que estás viendo? ¿Significativo? – kross

+0

No se puede probar ahora, pero has_css parece tomar un segundo, mientras que la coincidencia de la clase parecía inmediata. – hakunin

4

esta pregunta se refiere a la forma de manipular un elemento hermano que es lo que yo creo que la pregunta original está aludiendo a

Su pregunta hipótesis que funciona con un pequeño ajuste. Si el campo generado dinámicamente se parece a esto y no tiene un id:

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

Su consulta sería entonces:

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

Si la entrada generada dinámicamente viene adjunto con un elemento de identificación (tenga cuidado con éstos, aunque como en angular, que acostumbran a cambios basados ​​en la adición y eliminación de elementos) que sería algo como esto:

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

Espero que ayude.

Cuestiones relacionadas