Haben Sie Probleme zu verstehen, warum die Pseudoklasse: enthält () in CSS-Selektoren so funktioniert, wie sie funktioniert?

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

Frage

Ich verwende CSS-Selektoren mit Selen und Gurke. Wenn ein Locator nicht funktioniert, teste ich ihn mit der Konsole der Chrome Developer Tools. Ich stoße immer wieder auf ein Verhalten, das ich nicht verstehe (wie zum Beispiel, warum es das tut, was es tut und nicht, wofür ich es brauche ...). Bitte schauen Sie sich diese Locators an:

  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

    In meinem DOM ist das Element, das mit dem ersten Teil jedes dieser Locators übereinstimmt, dasselbe ...

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

    Das Problem ist, dass nur die oben genannten Locators Nr. 1 und Nr. 3 tatsächlich mit irgendetwas übereinstimmen. Weiß jemand, warum das so ist? Mir ist klar, dass div:contains(foo) nicht nur mit dem Div übereinstimmt, das tatsächlich foo enthält, sondern auch mit allen übergeordneten Divs, aber es scheint mir, dass der Rest der Locator-Elemente es aussortieren sollte, damit es funktioniert.

    Ich suche nur nach Einsichten und möglicherweise nach Vorschlägen, um sicherzustellen, dass der 'my_button', auf den ich klicke, der unter 'My Header Title' ist und nicht ein 'my_button' irgendwo anders auf der Seite (und Die einzige einfache Möglichkeit, sie zu unterscheiden, besteht in der Überschrift, unter der sie sich befinden. Gleichzeitig wird die scheinbar überschüssige DOM-Struktur im Locator entfernt, um die Wahrscheinlichkeit zu erhöhen, dass sie wiederverwendbar ist.

    <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>
                      ...
    

War es hilfreich?

Lösung

Wenn ich mich in solchen Schwierigkeiten befinde, schaue ich mir normalerweise die Spezifikation an.

Wie Sie wahrscheinlich wissen, gibt es in der aktuellen Spezifikation keine für :contains() und deshalb verlassen Sie sich auf undokumentierte, nicht spezifizierte Funktionen eines bestimmten Browsers / Parsers. Es sollte funktionieren, aber es funktioniert nicht - offensichtlich war die Implementierung nicht abgeschlossen. Und jetzt ist die Pseudoklasse weg.

Könnten Sie stattdessen einen XPath wählen? Entweder mit internen Selenium-Methoden oder JavaScript . Dieser XPath entspricht Ihrer CSS-Auswahlnummer 2:

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


EDIT

Nachdem Ihr Kommentar mir gezeigt hat, dass es sich um Selenium RC und damit um Sizzle handelt, habe ich tiefer gegraben.

Ich habe Ihr Beispiel-HTML genommen, es aus den versteckten und (scheinbar) unnötigen Elementen entfernt und folgendes hinterlassen:

<!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>


Ich habe das neueste Sizzle heruntergeladen und das Version von Sizzle, die derzeit von Selenium verwendet wird Release .

Es stellt sich heraus, dass diese beiden sehr unterschiedlich sind.

z. die contains-Implementierung des aktuellen Sizzle:

return ~( elem.textContent || elem.innerText || getText( elem ) ).indexOf( match[3] );

und die Implementierung, die Selenium verwendet:

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

Ich habe beide Implementierungen in meinem Testdokument ausprobiert. Die Ergebnisse sind hier zu sehen (zum Vergrößern klicken):

Current Sizzle - passt perfekt zu allen Aktuelle Sizzle-Ergebnisse

Selen's Sizzle - entspricht 1 von 4 Selenium Sizzle Results


Die Ergebnisse sagen alles. Selenium verwendet eine alte Version von Sizzle, die im Umgang mit :contains()-Pseudoklassen irgendwie unvollkommen ist. Die aktuelle Sizzle-Version leidet nicht unter dem Fehler und kann alle Elemente gut finden.

Jetzt können Sie Folgendes tun:

  1. Einen Selenium-Fehler melden.
  2. Verwenden Sie XPath als Problemumgehung.
  3. Wechseln Sie die sizzle.js-Datei in Ihrem Selenium-Paket.

Andere Tipps

#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);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top