Ruby-on-rails Capybara 和 Rspec:一起使用 inside() 和 have_selector() 的正确方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9898150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 03:08:06  来源:igfitidea点击:

Capybara and Rspec: correct way to use within() and have_selector() together?

ruby-on-railsrubyrspeccapybara

提问by salernost

I use rspec 2.6.0 and Capybara 1.1.1 for acceptance testing.
With a view like the following:

我使用 rspec 2.6.0 和 Capybara 1.1.1 进行验收测试。
具有如下视图:

<tr >
  <td>Team 3 Name</td>
  <td>true</td>
  <td><a href="/teams/3">Show</a></td>
  <td><a href="/teams/3/edit">Edit</a></td>
  <td><a href="/teams/3">Deactivate</a></td>
</tr>
<tr >
  <td>Team 4 Name</td>
  <td>true</td>
  <td><a href="/teams/4">Show</a></td>
  <td><a href="/teams/4/edit">Edit</a></td>
  <td><a href="/teams/4">Deactivate</a></td>
</tr>

I want to write an acceptance test that states: "Team 3 does NOT have the 'Deactivate' link." I expect the following to fail:

我想编写一个验收测试,声明:“第 3 团队没有‘停用’链接。” 我希望以下内容失败:

within('tr', :text => 'Team 3 Name') do |ref|
  page.should_not have_selector('a', :text => 'Deactivate')
end

But it passes. To further test what is going on, I wrote the absurd:

但它过去了。为了进一步测试发生了什么,我写了荒谬的:

lock = false
within('tr', :text => 'Team 3 Name') do |ref|
  page.should have_selector('a', :text => 'Deactivate')
  page.should_not have_selector('a', :text => 'Deactivate')
  lock = true
end
lock.should be_true

Which passes as well.

这也通过了。

I am assuming from this that the scope the have_selector() call is using is not limited by the within() block, but I am not sure why this is. The capybara documentation uses this pattern and does not seem to mention any gotchas. What is the correct way to use within to limit the scope of my select? Thank you. /Salernost

我由此假设 have_selector() 调用使用的范围不受 inside() 块的限制,但我不确定这是为什么。capybara 文档使用这种模式并且似乎没有提到任何问题。使用内限制我选择范围的正确方法是什么?谢谢你。/萨勒诺斯特

回答by Mark Berry

Still learning Capybara myself, but have you tried have_linkinstead of have_selector? Also I don't think you need |ref|. For example:

还在学习水豚自己,但你有没有尝试过have_link的,而不是have_selector?另外我认为你不需要|ref|. 例如:

lock = false
within('tr', :text => 'Team 3 Name') do # omit |ref|
  page.should have_link('Deactivate')
  page.should_not have_link('Deactivate')
  lock = true
end
lock.should be_true



Update October 13, 20122012 年 10 月 13 日更新

Having come a little further with Capybara, I see several potential issues here:

使用 Capybara 更进一步,我在这里看到了几个潜在的问题:

  • withinmay silently ignore the textfield. You'll notice that the examples only show CSS or XPath finders without additional arguments.
  • If withindoes use text, it may not work here because you are asking it to look at the <tr>, but the text is in the <td>.
  • It's quite possible that the pagesubject still targets the entire page even if you are in a withinblock. The withinexamples are mostly about using fill_inor click. The exception is the example under Beware the XPath // trap.
  • within可能会默默地忽略该text字段。您会注意到这些示例仅显示 CSS 或 XPath 查找器,而没有其他参数。
  • 如果within确实使用text,它可能在这里不起作用,因为您要求它查看<tr>,但文本在<td>.
  • page即使您在一个within块中,该主题也很有可能仍以整个页面为目标。这些within示例主要是关于使用fill_inor 的click。例外是Beware the XPath // trap下的示例。

As for creating a withinblock, you can either give your table rows unique ids and search for them using CSS, or you may be able to write a specific XPath targeting the first matching row.

至于创建within块,您可以为表格行指定唯一 ID 并使用 CSS 搜索它们,或者您可以编写针对第一个匹配行的特定 XPath。

The problem with the latter is that you want use the withinon the <tr>, but the text you are using for your targeting is inside a <td>subelement. So for example, this XPath should find the table cell containing the text Team 3 Namebut then you are only working withinthat first cell, not the whole row.

后者的问题是您想在within上使用<tr>,但是您用于定位的文本位于<td>子元素内。因此,例如,此 XPath 应该找到包含文本的表格单元格,Team 3 Name但您只处理within第一个单元格,而不是整行。

within(:xpath, "//tr/td[normalize-space(text())='Team 3 Name'") do

There are ways to "back up" to a parent element using XPath but I don't know how to do it and I've read that it's not good practice. I think your best bet here might be to just generate ids so your rows start like this:

有很多方法可以使用 XPath 来“备份”到父元素,但我不知道该怎么做,而且我读到这不是一个好习惯。我认为你最好的选择可能是只生成 id,这样你的行就这样开始了:

<tr id="team_3">

then target them with a simple

然后用一个简单的目标

within("tr#team_3")

回答by supremebeing7

I would also recommend Mark Berry's final approach he mentioned of adding id's to each of your table elements.

我还推荐Mark Berry提到的将 id 添加到每个表元素的最终方法。

<tr id="team_3">

then target with

然后瞄准

within("tr#team_3")

Capybara has given me issues when selecting by xpath in that it doesn't seem to work consistently, especially with CI services.

Capybara 在通过 xpath 进行选择时给我带来了问题,因为它似乎无法始终如一地工作,尤其是使用 CI 服务时。

I also want to note on the same answer this section:

我还想在本节的同一个答案中注明:

It's quite possible that the page subject still targets the entire page even if you are in a within block. The within examples are mostly about using fill_in or click. The exception is the example under Beware the XPath // trap.

即使您在块内,页面主题也很有可能仍以整个页面为目标。内部示例主要是关于使用 fill_in 或 click。例外是注意 XPath // 陷阱下的示例。

This may have been the case in an older version, but in the current version of Capybara, calling pageinside of a withinblock only inspects the part of the page targeted. So, using Mark's above example:

在旧版本中可能是这种情况,但在当前版本的 Capybara 中,pagewithin块内部调用仅检查目标页面的部分。所以,使用 Mark 上面的例子:

within("tr#team_3") do
  expect(page).to have_content 'Team 3 Name'
  # => true
  expect(page).to have_content 'Team 4 Name'
  # => false
end

回答by Anton Styagun

have_selectorseems to ignore :textand :contentoptions. I had to use something like this instead:

have_selector似乎忽略:text:content选项。我不得不使用这样的东西:

within 'a' do
  page.should have_content 'Deactivate'
end

回答by Philippe Perret

The solution is to not use withinmethod:

解决方法是不使用within方法:

expect(page).to have_css('tr#team_3') do
  without_tag('a', text: 'Deactivate')
end