除非指定标记路径,否则为什么 Watir WebDriver 需要正则表达式来查找文本?

Why does Watir WebDriver need regex to find text unless path to tag is specified?

我有一个 table 在使用 Watir WebDriver 查找元素方面很难处理。这是 table:

的屏幕截图

为了选中 "Email: " 旁边的复选框,我首先搜索电子邮件文本,使用 .parent 向上搜索 tr 标签,然后向下搜索 checkbox.

棘手的事情是在屏幕上定位 "Email: " 文本。

注意以下观察结果:

  1. label 标签内的文本在冒号后包含一个 space。 <label for="enabledEmail17">Email: </label>
  2. 这个有效:browser.div(:aria_labelledby, 'ui-id-74').label(:text, 'Email:').present? => true
  3. 这不起作用:browser.label(:text, 'Email:').present? => false
  4. 这不起作用:browser.label(:text, 'Email: ').present? => false
  5. 这有效但非常慢:browser.label(:text, /Email:/).present? => true

问题是我无法使用父 div(:aria_labelledby, 'ui-id-74') 来帮助定位所需的行,因为 ui-id 数字在我的数据库中随每个 "Lessee" 而变化。 (出于同样的原因,我不能在页面上使用复选框 id enabledEmail17 或任何其他带编号的属性。)虽然使用正则表达式会如上所示工作,但 Watir Webdriver 大约需要 2 分钟才能填充出表格(与没有正则表达式的情况相比不到 10 秒)。

那么问题来了,为什么上面的 #2 和 #5 有效而 #3 和 #4 无效?我要补充的是,其他承租人的所有其他 table 都隐藏在该页面的 HTML 中,但鉴于 #5 按预期工作,我认为这不是问题所在。另外,我得到 false 返回;问题不在于我找到了错误的元素。

如有任何帮助,我们将不胜感激。

这里是 HTML 的相关部分:

<div class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-dialog-buttons ui-draggable ui-resizable" tabindex="-1" role="dialog" style="position: absolute; height: auto; width: 600px; top: 59px; left: 497px; display: block; z-index: 102;" aria-describedby="ttDefaultRoleDialog17" aria-labelledby="ui-id-74">

<table class="ui-widget-content po-widget-content fullWidth">
    <tbody><tr>
      <td class="bold ttBrandedCBTD">Branded</td>
      <td class="bold">Information</td>
      <td class="bold">Value</td>
    </tr>
    <tr>
      <td class="ttBrandedCBTD"></td>
      <td><label>Role: </label></td>
      <td>Lessee</td>
    </tr>
    <tr>
      <td class="center ttBrandedCBTD"><input type="checkbox" id="enabledEmail17" class="enableRoleField" data-field-class="aliasEmail"></td>
      <td>
      <span class="required-red required-info-toggle eo-hidden">*</span><label for="enabledEmail17">Email: </label></td>
      <td>
<div id="wwgrp_email17" class="wwgrp text-left align-left">


<div id="wwctrl_email17" class="wwctrl">
<input type="email" name="roleMappings[17].email" maxlength="255" value="" id="email17" class="singleUser role-info aliasEmail addressBook ui-autocomplete-input" data-index="17" data-invalid-email="mapusers.email.valid" autocomplete="off"></div> </div>
      </td>
    </tr>

  </tbody></table>

</div>

问题

观察到的行为是由于页面包含多个具有相同文本的标签。这些行为可以通过简化为的页面看到:

<html>
  <body>
    <label style="display:none;">Email: </label>
    <div aria-labelledby="ui-id-74">
      <label>Email: </label>
    </div>
  </body>
</html>

运行同例:

browser.div(:aria_labelledby, 'ui-id-74').label(:text, 'Email:').present?
#=> true

browser.label(:text, 'Email:').present?
#=> false

browser.label(:text, 'Email: ').present?
#=> false

browser.label(:text, /Email:/).present?
#=> true

此行为是预期的,因为:

  1. 对于第二种情况:Watir returns 第一个匹配元素,在这种情况下,不显示。由于 present? 方法检查元素是否存在且可见,因此需要 false
  2. 对于第三种情况:Watir 规范化被比较文本中的 space。换句话说,Watir 认为标签的文本实际上是 "Email:"。这就是永远找不到该元素的原因。
  3. 对于第四种情况:当将文本与正则表达式进行匹配时,Watir 会检查可见文本。第一个标签没有可见文本,因此无法匹配。结果,您得到了第二个标签。这是一个[当前正在讨论的已知问题]。

解决方案

您需要找到一种方法来区分可见字段和隐藏字段。从 HTML 看来,每个 table 都像对话框一样显示,但一次只显示一个。我会尝试将定位隔离到可见对话框。

尝试:

dialog = browser.divs(:class, 'ui-dialog').find(&:visible?)
dialog.label(:text, 'Email:').present?

看起来对话框可能是由 jQueryUI 生成的,这意味着您可以通过检查样式属性来避免迭代对话框:

dialog = browser.div(:css, 'div.ui-dialog[style*="display: block;"]')
dialog.label(:text, 'Email:').present?

请注意,您可以使用 :label 定位器,而不是从标签迭代到复选框:

dialog.checkbox(:label, 'Email:').present?