Como obter o nó pai em Capivara?


86

Estou trabalhando com muitos plug-ins jQuery, que geralmente criam elementos DOM sem id ou outras propriedades de identificação, e a única maneira de obtê-los na Capivara (por exemplo, clicando) - é obter seu vizinho (outro filho de seu ancestral) primeiro . Mas eu não encontrei em nenhum lugar, Capivara suporta tais coisas, por exemplo:

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

?


Também será muito útil para mim, se você disser, a Capivara gera cliques em elementos com {display: hidden}, e há uma maneira de encontrar elementos em algum escopo, onde display! = Hidden?
Sandrew

Esta é uma pergunta separada, mas depende do driver que você está usando. webrat encontrará alegremente coisas escondidas, mas selênio não fica tão feliz em clicar em itens que você não pode ver.
jamuraa 01 de

Respostas:


111

Eu realmente achei a resposta de Jamuraa útil, mas ir para o xpath completo me deu um pesadelo de uma string no meu caso, então eu felizmente usei a habilidade de concatenar find's em Capybara, me permitindo misturar seleção de css e xpath. Seu exemplo ficaria assim:

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

Atualização do Capybara 2.0 : find(:xpath,".//..")provavelmente resultará em um Ambiguous matcherro. Nesse caso, use first(:xpath,".//..").


Obrigado por essa ideia - nunca teria pensado nisso! Eu estava fazendo el.parent para um elemento td que encontrei com find (: css), mas por algum motivo que não entendo, el.parent estava retornando # <Capybara :: Document>. el.find (: xpath, ".// ..") por outro lado, retorna # <Capybara :: Element tag = "tr">, que é o que eu precisava.
Tyler Rick

Outra maneira de encontrar recursivamente um certo nó pai é com o seletor ancestor-or-self do xpath. Confira stackoverflow.com/questions/1362466/…
vrish88

25
Você não precisa .//..encontrar o pai - ..basta, e isso também nunca é ambíguo.
Eamon Nerbonne

ty! Eu sei que este comentário está um pouco atrasado para a festa, mas condensado no seguinte depois de ler a edição, e o comentário de Eamon: el.first (: xpath, '..')
aschyiel

39

Não há como fazer isso com capivara e CSS. Eu usei XPath no passado para atingir esse objetivo, que tem uma maneira de obter o elemento pai e é compatível com Capivara:

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

2
Quando faço um xpath find semelhante, recebo um erro de Nokogiri dizendo que a expressão é inválida. Eu adicionei um asterisco na frente do freio quadrado aberto na expressão para corrigir a expressão:find(:xpath, '//*[@id="some_button"]/..')
Andrew Ferk

35

Eu descobri o seguinte que funciona:

find(:xpath, '..')

Capivara foi atualizado para suportar isso.

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


1
Parece-me que você está respondendo / completando uma resposta anterior aqui ("Este" o que "não estava funcionando"?). Seria melhor se fosse uma resposta completa e independente. Então, eu recomendo que você edite. ;-)
helenov

Pode confirmar. Com o Capybara 2.14.4 mais recente, esta é a maneira correta de obter o nó pai.
fny

10

Se você se deparou com isso tentando descobrir como encontrar qualquer nó pai (como no ancestral ) (como sugerido no comentário de @ vrish88 na resposta de @Pascal Lindelauf):

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

5

Esta resposta refere-se a como manipular um elemento irmão, ao qual acredito que a pergunta original está se referindo

Sua hipótese de pergunta funciona com um pequeno ajuste. Se o campo gerado dinamicamente se parecer com este e não tiver um id:

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

Sua consulta seria:

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

Se a entrada gerada dinamicamente vier anexada com um elemento id (tenha cuidado com eles, embora como no angular, eles costumam mudar com base na adição e exclusão de elementos), seria algo assim:

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

Espero que ajude.


4

Estou usando uma abordagem diferente, encontrando primeiro o elemento pai usando o texto dentro deste elemento pai:

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

Talvez isso seja útil em uma situação semelhante.


1
Esta é uma ótima opção. Definir o escopo das ações da interface do usuário para uma parte da página que contém algum texto específico é um caso de uso comum para mim.
clemensp

2

Eu precisava encontrar um ancestral com uma classe css, embora fosse indeterminado se o ancestral de destino tinha uma ou mais classes css presentes, então não vi uma maneira de fazer uma consulta xpath determinística. Em vez disso, trabalhei nisso:

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

Aviso: use com moderação, pois pode custar muito tempo nos testes, então certifique-se de que o ancestral está a apenas alguns saltos de distância.


Aceleração: substitua seu segundo intervalo por break if ancestor[:class].split(" ").include?(css_class).
hakunin

@hakunin Estou curioso para saber o quanto de aceleração você está vendo? Significativo?
Kross

Não é possível testar agora, mas has_css pareceu demorar um segundo, enquanto a correspondência com a classe parecia imediata.
hakunin de

Capivara agora tem um ancestor(selector)método integrado. Veja github.com/teamcapybara/capybara/commit/…
Tyler Rick

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.