¿Tiene problemas para comprender por qué la pseudoclase: contains () en los selectores de CSS funciona de la manera que lo hace?

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

Pregunta

Estoy usando selectores CSS con Selenium y Cucumber. Cuando un localizador no funciona, lo pruebo usando la consola de Chrome Developer Tools. Sigo encontrando un comportamiento que no entiendo (como por qué hace lo que está haciendo y no lo que necesito que haga ...). Mire estos localizadores:

  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

En mi DOM, el elemento que coincide con la primera parte de cada uno de esos localizadores es el mismo ...

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

El problema es que solo los localizadores n. ° 1 y n. ° 3 anteriores coincidirán con algo. ¿Alguien sabe por qué esto es cierto? Me doy cuenta de que div:contains(foo) coincidirá no solo con el div que realmente contiene foo, sino también con todos los divs principales, pero me parece que el resto de los elementos del localizador deberían ordenarlo para que funcione.

Solo estoy buscando información y posiblemente sugerencias para asegurarme de que el "my_button" en el que estoy haciendo clic es el que está debajo de "My Header Title" y no un "my_button" en otro lugar de la página (y la única forma fácil de distinguirlos es por el encabezado bajo) mientras se elimina la estructura DOM aparentemente excesiva en el localizador para que sea más probable que sea reutilizable.

<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>
                  ...
¿Fue útil?

Solución

Lo habitual que hago cuando me encuentro en este tipo de problemas es mirar las especificaciones.

Como probablemente sepa, no hay ninguno para :contains() en la especificación actual y, por lo tanto, confía en funciones indocumentadas y sin velocidad de un navegador / analizador en particular. debería funcionar, pero no lo hace; obviamente, la implementación no estaba completa. Y ahora la pseudoclase se ha ido.

¿Podría optar por un XPath en su lugar? Ya sea mediante métodos internos de Selenium o JavaScript . Este XPath es el mismo que su selector de CSS número 2:

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

<×EDIT

Después de que tu comentario me mostró que estamos hablando de Selenium RC y, por lo tanto, Sizzle, investigué más profundamente.

Tomé su HTML de ejemplo, lo despojé de los elementos ocultos y (aparentemente) innecesarios, y me quedé con esto:

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

Descargué la más reciente de Sizzle y obtuve la versión de Sizzle que actualmente usa Selenium en la lanzamiento .

Resulta que esos dos son muy diferentes.

Por ejemplo, la implementación contains de Sizzle actual:

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

y la implementación que utiliza Selenium:

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

Probé ambas implementaciones en mi documento de prueba, los resultados se pueden ver aquí (haga clic para ampliar):

Current Sizzle: combina todo perfectamente Resultados actuales de Sizzle

Sizzle de selenio - coincide con 1 de 4 Resultados de selenio sizzle


Los resultados lo dicen todo. Selenium usa una versión antigua de Sizzle que de alguna manera es imperfecta en el manejo de la pseudoclase :contains(). La versión actual de Sizzle no sufre el error y es capaz de encontrar bien todos los elementos.

Ahora, puede hacer cualquiera de estos:

  1. Presentar un error de selenio.
  2. Utilice XPath como solución alternativa.
  3. Cambie el archivo sizzle.js en su paquete de Selenium.

Otros consejos

#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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top