如何在 Capybara 中获取父节点?

Posted

技术标签:

【中文标题】如何在 Capybara 中获取父节点?【英文标题】:How to get parent node in Capybara? 【发布时间】:2011-02-01 11:18:09 【问题描述】:

我正在使用许多 jQuery 插件,这些插件通常创建没有 id 或其他标识属性的 DOM 元素,并且在 Capybara 中获取它们的唯一方法(例如单击) - 是获取它们的邻居(它的另一个孩子先祖)先。但是我没有找到任何地方,例如Capybara是否支持这样的事情:

find('#some_button').parent.fill_in "Name:", :with => name

?

【问题讨论】:

另外,如果你告诉我,Capybara 是否会生成带有 display: hidden 的点击元素,并且有没有办法在某个范围内查找元素,其中 display !=隐藏? 这是一个单独的问题,但这取决于您使用的驱动程序。 webrat 会很高兴找到隐藏的东西,但是 selenium 却不那么乐意点击你看不到的东西。 【参考方案1】:

我真的发现 jamuraa 的回答很有帮助,但是在我的情况下,使用完整的 xpath 给了我一个字符串的噩梦,所以我很高兴地利用在 Capybara 中连接 find 的能力,让我可以混合 css 和 xpath 选择。您的示例将如下所示:

find('#some_button').find(:xpath,".//..").fill_in "Name:", :with => name

Capybara 2.0 更新find(:xpath,".//..") 很可能会导致 Ambiguous match 错误。在这种情况下,请改用first(:xpath,".//..")

【讨论】:

感谢你的想法——我从来没有想过这个!我正在为使用 find(:css) 找到的 td 元素执行 el.parent,但由于某种我不明白的原因,el.parent 正在返回 #<:document>。另一方面,el.find(:xpath,".//..") 返回 #<:element tag="tr">,这正是我所需要的。 另一种递归查找某个父节点的方法是使用 xpath 的祖先或自我选择器。看看***.com/questions/1362466/… 您不需要 .//.. 来查找父级 - 只需 .. 就足够了,而且这也绝不会模棱两可。 泰!我知道这条评论对派对来说有点晚了,但在阅读了编辑和 Eamon 的评论后,我将其浓缩为以下内容:el.first(:xpath, '..')【参考方案2】:

我发现以下确实有效:

find(:xpath, '..')

Capybara 已更新以支持此功能。

https://github.com/jnicklas/capybara/pull/505

【讨论】:

在我看来,您正在回复/完成之前的回答(“这”什么“不起作用”?)。如果它是一个完整且独立的答案会更好。所以我建议你编辑它。 ;-) 可以确认。使用最新的 Capybara 2.14.4,这是获取父节点的正确方法。【参考方案3】:

没有办法用 capybara 和 CSS 做到这一点。不过,我过去曾使用 XPath 来实现此目标,它确实有一种获取父元素的方法,并且受到 Capybara 的支持:

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name

【讨论】:

当我进行类似的 xpath 查找时,我收到一个 Nokogiri 错误,说表达式无效。我在表达式中的开放方括号前面添加了一个星号来修复表达式:find(:xpath, '//*[@id="some_button"]/..')【参考方案4】:

如果您在试图找出如何找到任何父节点(如 ancestor)时偶然发现(如 @vrish88 对 @Pascal Lindelauf 答案的评论中所暗示的那样):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')

【讨论】:

【参考方案5】:

这个答案与如何操作兄弟元素有关,我认为这是原始问题所暗示的

您的问题假设只需稍作调整即可。如果动态生成的字段看起来像这样并且没有id:

<div>
  <input></input>
  <button>Test</button>
</div>

您的查询将是:

find('button', text: 'Test').find(:xpath, "..").find('input').set('whatever')

如果动态生成的输入确实附加了一个 id 元素(请注意这些,尽管在 Angular 中,它们不会根据添加和删除元素而改变),它会是这样的:

find('button', text: 'Test').find(:xpath, "..").fill_in('#input_1', with: 'whatever')

希望对您有所帮助。

【讨论】:

【参考方案6】:

我使用了一种不同的方法,首先使用该父元素中的文本查找父元素:

find("<parent element>", text: "text within your #some_button").fill_in "Name:", with: name

也许这在类似情况下很有用。

【讨论】:

这是一个不错的选择。将 ui 操作限定到包含某些特定文本的页面部分对我来说是一个常见的用例。【参考方案7】:

我需要找到一个具有 css 类的祖先,尽管它不确定目标祖先是否存在一个或多个 css 类,所以我没有看到一种方法来进行确定性 xpath 查询。我解决了这个问题:

def find_ancestor_with_class(field, cssClass)
  ancestor = field
  loop do
    ancestor = ancestor.find(:xpath, '..')
    break if ancestor.nil?

    break if ancestor.has_css? cssClass
  end

  ancestor
end

警告:谨慎使用它,它可能会在测试中花费您大量时间,因此请确保祖先就在几跳之外。

【讨论】:

加速:用break if ancestor[:class].split(" ").include?(css_class)替换你的第二次休息。 @hakunin 我很好奇你看到了多少加速?重要吗? 现在无法测试,但 has_css 似乎需要一秒钟,而匹配类似乎很快。 Capybara 现在有一个内置的ancestor(selector) 方法。见github.com/teamcapybara/capybara/commit/…【参考方案8】:

正如@Tyler Rick Capybara 在评论中提到的,这些天有方法[ ancestor(selector) and sibling(selector)

【讨论】:

【参考方案9】:

在这里

http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base:parent

存在一个父方法;)

【讨论】:

这只会为我返回***文档。不知道是驱动问题还是什么。 阅读文档,看起来这可能意味着“框架”父级,而不是元素父级?

以上是关于如何在 Capybara 中获取父节点?的主要内容,如果未能解决你的问题,请参考以下文章

如何在python django中获取所有父节点但过滤子节点

如何在这样的树结构中获取父节点

jstree中想要选中子节点,父节点就会变成选中状态,需要如何修改。

如果它是使用 XPath 在 Scrapy 中的其他节点的父节点,如何从子节点获取文本

遍历 YAML::Node 时如何获取当前节点的父节点?

使用 SAX 解析器时如何获取父节点?