Ayant une certaine difficulté à comprendre pourquoi le: contient () la pseudo-classe dans les sélecteurs CSS fonctionne comme il le fait?

StackOverflow https://stackoverflow.com/questions/9334539

Question

J'utilise sélecteurs CSS avec Sélénium et concombre. Lorsqu'un localisateur ne fonctionne pas, je le tester à l'aide de la console des outils de développement Chrome. Je continue à rencontrer un comportement que je ne comprends pas (comme dans pourquoi fait-il ce qu'il fait et non ce que je dois à faire ...). S'il vous plaît regarder ces localisateurs:

  1. div.view_header ~ div input.my_button

  2. div:contains(My Header Title) ~ div input.my_button

  3. div:contains(My Header Title) ~ div div div input.my_button

Dans mon DOM l'élément correspondant à la première partie de chacun de ces localisateurs est le même ...

<div class="view_header foo">    My Header Title  </div>

Le problème est que seulement localisateurs # 1 & # 3 ci-dessus fait correspondre à quelque chose. Quelqu'un sait-il pourquoi cela est vrai. Je me rends compte que div:contains(foo) correspondra non seulement la div qui contient en fait foo, mais tous les divs parents aussi bien, mais il me semble que le reste des éléments de localisation doit être triant de telle sorte que cela devrait fonctionner.

Je suis à la recherche d'une idée et peut-être des suggestions pour un moyen de vous assurer que le « my_button » Je suis en cliquant est celui sous « Mon-tête Titre » et non un « my_button » ailleurs sur la page (et le seul moyen facile de les distinguer est par l'en-tête, ils sont moins) tout en éliminant la structure DOM apparemment en excès dans le localisateur de manière à le rendre plus susceptible d'être réutilisable.

<head>
<body class="bp">
  <div style="left: -100em; position: absolute; width: 100em;"></div>
  <input class="refresh_marker" type="text" value="no" style="display:none">
  <div class="container">
    <div id="nav_bar">
    <div id="user_bar">
    <div id="wrapper" style="border-radius: 10px 10px 10px 10px;">
      <div class="content">
        <div class="page_title"> Title </div>
        <div></div>
        <a class="change_tracker_link"> &nbsp; </a>
        <div class="breadcrumb_trail">
        <style type="text/css">
        <div id="dialog_no_new_assoc" class="hide" title="No Associations Selected"></div>
        <div class="organizer_widget root_organizer" title="WorkflowItem" style="">
          <input id="data_classifier" type="hidden" value="Workflow::WorkflowItem">
          <input id="data_id" type="hidden" value="34">
          <input id="data_getter" type="hidden">
          <input id="collection_vertex_id" type="hidden" value="4cb1ecc300fa5f77844b1e87431d0a25390c1c77">
          <input id="view-name" type="hidden" value="EnterPaperInformation">
          <div class="object organizer">
            <div class="clear"></div>
            <div class="interior">
              <form method="POST" enctype="multipart/form-data">
                <input type="hidden" value="4cb1ecc300fa5f77844b1e87431d0a25390c1c77" name="vertex_id">
                <input type="submit" value="Save" style="display: none;" name="submit_form">
                <div class="organizer_header view_header"> My Header Title </div>
                <div class="organizer_widget" title="Citation" style="">
                  <input id="data_classifier" type="hidden" value="Bibliography::Citation">
                  <input id="data_id" type="hidden" value="10">
                  <input id="data_getter" type="hidden" value="citation">
                  <input id="collection_vertex_id" type="hidden" value="5376dcc81102a5d76bf829513b096be8f67e560d">
                  <input id="view-name" type="hidden" value="CitationEntrySummary">
                  <div id="citation" class="object organizer">
                    <div class="clear"></div>
                    <div class="interior">
                      <div id="Citation___id_widget" class="widget_row numeric">
                      <div id="Citation___title_widget" class="widget_row string">
                      <div id="Citation___abbreviated_title_widget" class="widget_row string">
                      <div id="Citation___authors_display_string_widget" class="widget_row string">
                      <div id="Citation___language_widget" class="widget_row choice">
                      <div id="Citation___link_widget" class="widget_row link">
                      <input type="hidden" value="Bibliography::JournalArticle___10" name="check_5376dcc81102a5d76bf829513b096be8f67e560d[]">
                      <input id="ba_citation" class="my_button" type="button" value="Break Associations" name="break_assoc_5376dcc81102a5d76bf829513b096be8f67e560d">
                      <div class="clear"></div>
                      <input type="hidden" value="5376dcc81102a5d76bf829513b096be8f67e560d" name="vertices[]">
                    </div>
                  ...
Était-ce utile?

La solution

La chose habituelle que je fais quand je me trouve dans ce genre de problème est de regarder la spécification.

Comme vous le savez sans doute, il n'y en a pas pour :contains() dans la spécification actuelle et donc vous comptez sur les caractéristiques non documentées, unspeced d'un navigateur particulier / analyseur. Il devrait le travail, mais il ne fonctionne pas - de toute évidence la mise en œuvre n'a pas été complète. Et maintenant, la pseudo-classe est parti.

Pourriez-vous un XPath à la place? Soit par des méthodes Selenium internes ou JavaScript . Ce XPath est le même que votre numéro de sélecteur CSS 2:

//div[contains(text(),'My Header Title')]/following-sibling::div//input[contains(@class,'my_button')]

EDIT

Après votre commentaire m'a montré que nous parlons Selenium RC et, par conséquent, Sizzle, je creusé plus profondément.

Je l'ai pris, dépouillé votre exemple HTML à partir des éléments inutiles cachés et (apparemment), et a été laissé avec ceci:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <script src="sizzle.js" type="text/javascript"></script>
</head>

<body class="bp">
  <div class="container">
    <div id="nav_bar">
    <div id="user_bar">
    <div id="wrapper" style="border-radius: 10px 10px 10px 10px;">
      <div class="content">
        <div class="breadcrumb_trail">
        <div class="organizer_widget root_organizer" title="WorkflowItem" style="">
          <div class="object organizer">
            <div class="interior">
              <form method="POST" enctype="multipart/form-data">
                <div class="organizer_header view_header">    My Header Title  </div>
                <div class="organizer_widget" title="Citation" style="">
                  <div id="citation" class="object organizer">
                    <div class="clear"></div>
                    <div class="interior">
                      <div id="Citation___id_widget" class="widget_row numeric">
                      <div id="Citation___title_widget" class="widget_row string">
                      <div id="Citation___abbreviated_title_widget" class="widget_row string">
                      <div id="Citation___authors_display_string_widget" class="widget_row string">
                      <div id="Citation___language_widget" class="widget_row choice">
                      <div id="Citation___link_widget" class="widget_row link">
                      <input id="ba_citation" class="my_button" type="button" value="Break Associations" name="break_assoc_5376dcc81102a5d76bf829513b096be8f67e560d" />
                      <div class="clear"></div>
                      </div></div></div></div></div></div>
                    </div>
                  </div>
                </div>
              </form>
            </div>
          </div>
        </div>
        </div>
      </div>
    </div>
    </div>
    </div>
  </div>
</body>

</html>

J'ai téléchargé le dernière Sizzle et j'ai obtenu le return ~( elem.textContent || elem.innerText || getText( elem ) ).indexOf( match[3] );

et les utilisations de la mise en œuvre Sélénium:

return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;

J'ai essayé deux implémentations sur mon document de test, les résultats peuvent être vus ici (cliquez pour agrandir):

Courant Sizzle - correspond parfaitement tous Les résultats actuels Sizzle

Sizzle de Sélénium - Matches 1 sur 4 Sizzle de sélénium Résultats


Les résultats disent tout. Sélénium utilise une ancienne version de Sizzle qui est en quelque sorte imparfaite dans le traitement de :contains() pseudo-classe. La version actuelle Sizzle ne souffre pas du bogue et est en mesure de trouver tous les éléments bien.

Maintenant, vous pouvez faire l'une de ces:

  1. fichier un bug Sélénium.
  2. Utilisez XPath comme solution de contournement.
  3. Mettez le fichier sizzle.js dans votre package Sélénium.

Autres conseils

#Selenium #Webdriver handle only HTML elements but with using java script executor It's possible to handle #pseudo elements in selenium #webdriver. 

Ex: :after , :before etc

String script = "return window.getComputedStyle(document.querySelector('Enter root classname here'),':after / :before').getPropertyValue('content')";
Thread.sleep(3000);
JavascriptExecutor js = (JavascriptExecutor) driver;
String content = (String) js.executeScript(script);
System.out.println(content);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top