Возникли проблемы с пониманием того, почему псевдо-класс: contains () в селекторах CSS работает так, как работает? - PullRequest
3 голосов
/ 17 февраля 2012

Я использую селекторы CSS с Selenium и Cucumber.Когда локатор не работает, я проверяю его с помощью консоли Chrome Developer Tools.Я продолжаю сталкиваться с поведением, которое я не понимаю (например, почему оно делает то, что делает, а не то, что мне нужно ...).Пожалуйста, посмотрите на эти локаторы:

  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

В моем DOM элемент, соответствующий первой части каждого из этих локаторов, одинаков ...

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

Проблема в том, что только локаторы # 1& # 3 выше на самом деле будет соответствовать чему угодно.Кто-нибудь знает, почему это так?Я понимаю, что div:contains(foo) будет соответствовать не только div, который на самом деле содержит foo, но и всем родительским divам, но мне кажется, что остальные элементы локатора должны сортировать его так, чтобы он работал.

Я просто искал какую-либо информацию и, возможно, предложения о том, чтобы убедиться, что кнопка my_button, которую я нажимаю, - это та, которая находится под заголовком «My Header Title», а не «my_button» где-то еще на странице (и единственнаяих можно легко отличить по заголовку, под которым они находятся), при этом устраняя, казалось бы, избыточную структуру DOM в локаторе, чтобы сделать ее более вероятной для повторного использования.

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

Ответы [ 2 ]

2 голосов
/ 01 июля 2012

Обычно я сталкиваюсь с такими неприятностями, когда смотрю на спецификацию.

Как вы, вероятно, знаете, в текущей спецификации нет ни одного для :contains(), и поэтому вы полагаетесь на недокументированные, неисследованные функции конкретного браузера / анализатора. Это должно работать, но это не так - очевидно, реализация не была завершена. И теперь псевдокласс ушел.

Не могли бы вы вместо этого пойти на XPath ? Либо внутренними методами Selenium, либо JavaScript . Этот XPath совпадает с вашим селектором CSS номер 2:

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

EDIT

После того, как ваш комментарий показал мне, что мы говорим о Selenium RC и, следовательно, Sizzle, я копнул глубже.

Я взял ваш пример HTML, снял его со скрытых и (казалось бы) ненужных элементов и остался с этим:

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

Я скачал последний Sizzle и получил версию Sizzle, которая фактически используется Selenium в текущем выпуске .

Оказывается, эти два очень разные.

например. contains реализация текущего Sizzle:

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

и реализация Selenium использует:

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

Я попробовал обе реализации в моем тестовом документе, результаты можно увидеть здесь (нажмите, чтобы увеличить):

Current Sizzle - идеально подходит всем Current Sizzle Results

Sizle's Sizzle - соответствует 1 из 4 Selenium's Sizzle Results


Результаты говорят сами за себя. Selenium использует старую версию Sizzle, которая как-то несовершенна в обработке псевдокласса :contains(). Текущая версия Sizzle не страдает от этой ошибки и может хорошо найти все элементы.

Теперь вы можете сделать любой из этих:

  1. Файл ошибки Selenium.
  2. Используйте XPath в качестве обходного пути.
  3. Переключите файл sizzle.js в свой пакет Selenium.
1 голос
/ 16 июля 2019
#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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...