Hai qualche problema a capire perché la pseudo classe: contains () nei selettori CSS funziona in questo modo?

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

Domanda

Sto usando selettori CSS con Selenium e Cucumber. Quando un localizzatore non funziona, lo provo utilizzando la console degli Strumenti per sviluppatori di Chrome. Continuo a incontrare un comportamento che non capisco (come perché fa quello che sta facendo e non quello che ho bisogno che faccia ...). Guarda questi localizzatori:

  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

Nel mio DOM l'elemento che corrisponde alla prima parte di ciascuno di questi localizzatori è lo stesso ...

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

Il problema è che solo i localizzatori # 1 e # 3 sopra corrispondono effettivamente a qualsiasi cosa. Qualcuno sa perché questo è vero. Mi rendo conto che div:contains(foo) corrisponderà non solo al div che in realtà contiene foo, ma anche a tutti i div principali, ma mi sembra che il resto degli elementi del localizzatore dovrebbe ordinarlo in modo che funzioni.

Sto solo cercando informazioni e possibilmente suggerimenti per un modo per assicurarmi che il "my_button" che sto facendo clic sia quello sotto "My Header Title" e non un "my_button" da qualche altra parte nella pagina (e l'unico modo semplice per distinguerli è dall'intestazione in cui si trovano) eliminando la struttura DOM apparentemente in eccesso nel localizzatore in modo da renderlo più facilmente riutilizzabile.

<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>
                  ...
È stato utile?

Soluzione

La solita cosa che faccio quando mi trovo in questo tipo di problemi è guardare le specifiche.

Come probabilmente saprai, non ce n'è nessuno per :contains() nelle specifiche correnti e quindi fai affidamento su funzionalità non documentate e non specificate di un particolare browser / parser. dovrebbe funzionare, ma non è così: ovviamente l'implementazione non era completa. E ora la pseudo-classe è sparita.

Potresti invece utilizzare un XPath ? O tramite metodi Selenium interni o JavaScript . Questo XPath è lo stesso del tuo selettore CSS numero 2:

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

<”EDIT

Dopo che il tuo commento mi ha mostrato che stiamo parlando di Selenium RC e, quindi, Sizzle, ho scavato più a fondo.

Ho preso il tuo esempio HTML, l'ho tolto dagli elementi nascosti e (apparentemente) inutili e mi è rimasto questo:

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

Ho scaricato l ' l'ultimo Sizzle e ho ottenuto l' versione di Sizzle che viene effettivamente utilizzata da Selenium nell'attuale versione .

Si scopre che questi due sono molto diversi.

Ad esempio l'implementazione contains dell'attuale Sizzle:

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

e l'implementazione che Selenium utilizza:

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

Ho provato entrambe le implementazioni sul mio documento di prova, i risultati possono essere visti qui (clicca per ingrandire):

Sizzle attuale: si abbina perfettamente a tutto Risultati di sfrigolio attuali

Selenium's Sizzle - corrisponde a 1 su 4 Selenium's Sizzle Results


I risultati dicono tutto. Selenium utilizza una vecchia versione di Sizzle che è in qualche modo imperfetta nella gestione della pseudo-classe :contains(). L'attuale versione di Sizzle non soffre del bug ed è in grado di trovare bene tutti gli elementi.

Ora puoi eseguire una di queste operazioni:

  1. Segnala un bug di selenio.
  2. Utilizza XPath come soluzione alternativa.
  3. Cambia il file sizzle.js nel tuo pacchetto Selenium.

Altri suggerimenti

#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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top