除非指定标记路径,否则为什么 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: " 文本。
注意以下观察结果:
label
标签内的文本在冒号后包含一个 space。 <label for="enabledEmail17">Email: </label>
- 这个有效:
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
问题是我无法使用父 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
此行为是预期的,因为:
- 对于第二种情况:Watir returns 第一个匹配元素,在这种情况下,不显示。由于
present?
方法检查元素是否存在且可见,因此需要 false
。
- 对于第三种情况:Watir 规范化被比较文本中的 space。换句话说,Watir 认为标签的文本实际上是 "Email:"。这就是永远找不到该元素的原因。
- 对于第四种情况:当将文本与正则表达式进行匹配时,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?
我有一个 table 在使用 Watir WebDriver 查找元素方面很难处理。这是 table:
的屏幕截图为了选中 "Email: " 旁边的复选框,我首先搜索电子邮件文本,使用 .parent 向上搜索 tr
标签,然后向下搜索 checkbox
.
棘手的事情是在屏幕上定位 "Email: " 文本。
注意以下观察结果:
label
标签内的文本在冒号后包含一个 space。<label for="enabledEmail17">Email: </label>
- 这个有效:
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
问题是我无法使用父 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
此行为是预期的,因为:
- 对于第二种情况:Watir returns 第一个匹配元素,在这种情况下,不显示。由于
present?
方法检查元素是否存在且可见,因此需要false
。 - 对于第三种情况:Watir 规范化被比较文本中的 space。换句话说,Watir 认为标签的文本实际上是 "Email:"。这就是永远找不到该元素的原因。
- 对于第四种情况:当将文本与正则表达式进行匹配时,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?