Comment obtenir le nœud parent à Capybara?

85

Je travaille avec de nombreux plugins jQuery, qui créent souvent des éléments DOM sans identifiant ou autres propriétés d'identification, et le seul moyen de les obtenir dans Capybara (pour cliquer par exemple) - est d'obtenir d'abord leur voisin (un autre enfant de son ancêtre) . Mais je n'ai trouvé nulle part, est-ce que Capybara prend en charge de telles choses par exemple:

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

?

Sandrew
la source
Cela me sera également très utile, si vous le dites, Capybara génère-t-il des clics sur des éléments avec {display: hidden}, et y a-t-il un moyen de trouver des éléments dans une certaine portée, où display! = Hidden?
sandrew
C'est une question distincte, mais cela dépend du pilote que vous utilisez. webrat trouvera les choses cachées avec bonheur, mais le sélénium n'est pas aussi heureux de cliquer sur des éléments que vous ne pouvez pas voir.
jamuraa

Réponses:

111

J'ai vraiment trouvé la réponse de jamuraa utile, mais opter pour un xpath complet m'a donné un cauchemar d'une chaîne dans mon cas, alors j'ai utilisé avec plaisir la capacité de concaténer les find dans Capybara, me permettant de mélanger la sélection css et xpath. Votre exemple ressemblerait alors à ceci:

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

Mise à jour Capybara 2.0 : find(:xpath,".//..")entraînera très probablement une Ambiguous matcherreur. Dans ce cas, utilisez à la first(:xpath,".//..")place.

Pascal Lindelauf
la source
Merci pour cette idée - je n'aurais jamais pensé à ça! Je faisais el.parent pour un élément td que j'ai trouvé avec find (: css), mais pour une raison que je ne comprends pas, el.parent retournait # <Capybara :: Document>. el.find (: xpath, ".// ..") d'autre part renvoie # <Capybara :: Element tag = "tr">, ce dont j'avais besoin.
Tyler Rick
Une autre façon de trouver récursivement un certain nœud parent consiste à utiliser le sélecteur ancêtre ou soi de xpath. Découvrez stackoverflow.com/questions/1362466/…
vrish88
25
Vous n'avez pas besoin .//..de trouver le parent - cela ..suffit, et ce n'est jamais non plus ambigu.
Eamon Nerbonne
ty! Je sais que ce commentaire est un peu en retard à la fête, mais je l'ai condensé à ce qui suit après avoir lu la modification et le commentaire d'Eamon: el.first (: xpath, '..')
aschyiel
39

Il n'y a pas moyen de faire cela avec capybara et CSS. J'ai cependant utilisé XPath dans le passé pour atteindre cet objectif, qui a un moyen d'obtenir l'élément parent et est pris en charge par Capybara:

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name
jamuraa
la source
2
Lorsque je fais une recherche xpath similaire, j'obtiens une erreur Nokogiri indiquant que l'expression n'est pas valide. J'ai ajouté un astérisque devant le crochet carré ouvert dans l'expression pour corriger l'expression:find(:xpath, '//*[@id="some_button"]/..')
Andrew Ferk
35

J'ai trouvé ce qui suit qui fonctionne:

find(:xpath, '..')

Capybara a été mis à jour pour prendre en charge cela.

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

B Sept
la source
1
Il me semble que vous répondez / complétez une réponse précédente ici ("Ce" ce qui "ne fonctionnait pas"?). Ce serait mieux si c'était une réponse complète et indépendante. Je vous recommande donc de le modifier. ;-)
helenov
Peut confirmer. Avec la dernière version de Capybara 2.14.4, c'est la bonne façon d'obtenir le nœud parent.
fny
10

Si vous êtes tombé sur ceci en essayant de trouver un nœud parent (comme dans l' ancêtre ) (comme indiqué dans le commentaire de @ vrish88 sur la réponse de @Pascal Lindelauf):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')
Ben Alavi
la source
5

Cette réponse concerne la manière de manipuler un élément frère, ce à quoi je pense que la question originale fait allusion

Votre hypothèse de question fonctionne avec une modification mineure. Si le champ généré dynamiquement ressemble à ceci et n'a pas d'identifiant:

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

Votre requête serait alors:

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

Si l'entrée générée dynamiquement est jointe avec un élément id (soyez prudent avec ceux-ci bien que comme en angulaire, ils ne changeront pas en fonction de l'ajout et de la suppression d'éléments), ce serait quelque chose comme ceci:

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

J'espère que ça t'as aidé.

T. Slater
la source
4

J'utilise une approche différente en recherchant d'abord l'élément parent en utilisant le texte dans cet élément parent:

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

Peut-être que cela est utile dans une situation similaire.

Harm de Wit
la source
1
C'est une excellente option. Étendre les actions de l'interface utilisateur à une partie de la page qui contient un texte particulier est un cas d'utilisation courant pour moi.
clemensp
2

J'avais besoin de trouver un ancêtre avec une classe css, même s'il était indéterminé si l'ancêtre cible avait une ou plusieurs classes css présentes, donc je ne voyais pas de moyen de faire une requête xpath déterministe. J'ai travaillé ceci à la place:

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

Attention: utilisez-le avec parcimonie, cela pourrait vous coûter beaucoup de temps dans les tests alors assurez-vous que l'ancêtre n'est qu'à quelques sauts.

Kross
la source
Speedup: remplacez votre deuxième pause par break if ancestor[:class].split(" ").include?(css_class).
hakunin
@hakunin Je suis curieux de savoir à quel point vous voyez une accélération? Important?
kross
Impossible de tester maintenant, mais has_css a semblé prendre une seconde, alors que la correspondance avec la classe semblait immédiate.
hakunin
Capybara a maintenant une ancestor(selector)méthode intégrée. Voir github.com/teamcapybara/capybara/commit/…
Tyler Rick
-5

C'est ici

http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base:parent

Il y a une méthode parent présente;)

Dmitriy Konovalov
la source
5
Cela ne renvoie que le document de premier niveau pour moi. Je ne sais pas si c'est un problème de pilote ou quoi.
Nerdmaster
En lisant la documentation, il semble que cela pourrait signifier le parent "frame", plutôt que l'élément parent?
Nick le