【问题标题】:Having some trouble understanding why the :contains() pseudo class in CSS selectors works the way it does?难以理解为什么 CSS 选择器中的 :contains() 伪类会以它的方式工作?
【发布时间】:2012-03-09 05:22:37
【问题描述】:

我在 Selenium 和 Cucumber 中使用 CSS 选择器。当定位器不起作用时,我会使用 Chrome 开发者工具的控制台对其进行测试。我不断遇到我不理解的行为(例如为什么它会做它正在做的事情而不是我需要它做的事情......)。请查看这些定位器:

  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) 不仅会匹配实际包含 foo 的 div,还会匹配所有父 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>
                  ...

【问题讨论】:

  • 你能再粘贴一些你的标记吗?包括 div.view_header 的父级 divs 以及 input.my_button 的父级。
  • 它有点大,我还没有想出如何在保持缩进的同时将其粘贴到此处以便可读。有没有办法做到这一点?
  • 我想你可以把它放在这里,我会为你修好它。
  • 好的,我用蛮力进去的
  • 现在这很奇怪......第二个定位符应该匹配。我看不出您的 :contains() 选择器有什么问题(正如您所描述的那样工作),但是如果您使用 + 而不是 ~ 呢?

标签: selenium css-selectors google-chrome-devtools


【解决方案1】:

当我发现自己遇到这种麻烦时,我通常会查看规范。

您可能知道there's none for :contains() in the current spec,因此您依赖于特定浏览器/解析器的未记录、未指定的功能。它应该工作,但它没有 - 显然实现不完整。现在伪类消失了。

你能改用XPath 吗?通过内部 Selenium 方法或JavaScript。此 XPath 与您的 CSS 选择器编号 2 相同:

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

编辑

在您的评论告诉我我们正在谈论 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>

我下载了latest Sizzle,得到了version of Sizzle that is actually used by Selenium in the current release

原来这两个是非常不同的。

例如当前 Sizzle 的 contains 实现:

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

以及 Selenium 使用的实现:

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

我在我的测试文档上尝试了这两种实现,结果可以在这里看到(点击放大):

Current Sizzle - 完美匹配所有

Selenium's Sizzle - 匹配 4 个中的 1 个


结果说明了一切。 Selenium 使用旧版本的 Sizzle,它在处理 :contains() 伪类方面有些不完善。当前的 Sizzle 版本没有 bug 并且能够很好地找到所有元素。

现在,您可以执行以下任何操作:

  1. File a Selenium bug.
  2. 使用 XPath 作为解决方法。
  3. 在 Selenium 包中切换 sizzle.js 文件。

【讨论】:

  • 感谢 XPath 模拟。我继续偶尔遇到 Sizzle 的意外行为。我目前的解决方法是只使用 JavaScript 来更好地控制 DOM 的遍历方式。我认为 W3 的 CSS 选择器规范和选择器引擎 (Sizzle) 的规范之间存在一些混淆点。就引擎而言, :contains() 肯定有文档记录。 Sizzle 的作者可以实现他们想要的任何东西(你或我也可以)。给定的实现是否按预期运行与 W3 规范几乎没有关系。
【解决方案2】:
#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);

【讨论】:

    猜你喜欢
    • 2013-07-05
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多