水豚歧义决议

如何解决水豚的歧义? 出于某种原因,我需要在页面中具有相同值的链接,但是由于出现错误,我无法创buildtesting

Failure/Error: click_link("#tag1") Capybara::Ambiguous: Ambiguous match, found 2 elements matching link "#tag1" 

我无法避免的原因是因为devise。 我正在尝试重新创buildTwitter页面的右侧的推文/标签和页面左侧的标签。 因此,同一页面上出现相同的链接页面是不可避免的。

我的解决scheme是

 first(:link, link).click 

代替

 click_link(link) 

水豚的这种行为是故意的,我相信它不应该像大多数其他答案中所build议的那样被固定。

2.0之前的水豚的版本返回了第一个元素,而不是提出exception,但水豚后来的维护者认为这是一个坏主意,最好提高它。 决定在很多情况下返回第一个元素导致返回不是开发人员想要返回的元素。

最高的答案在这里推荐使用firstall而不是find但是:

  1. allfirst不要等到有这样的定位器的元素会出现在页面上,虽然find
  2. all(...).firstfirst将不会保护你的情况,将来有这样的定位器的另一个元素可能会出现在页面上,因此你可能会发现不正确的元素

所以build议select另一个较不明确的定位符 :例如,通过id,class或其他css / xpath定位符select元素,以便只有一个元素将匹配它。


作为一个说明这里有一些定位器,我通常认为有用的时候解决歧义:

  • find('ul > li:first-child')

    它比first('ul > li')更有用,因为它会等到第一个li出现在页面上。

  • click_link('Create Account', match: :first)

    它比first(:link, 'Create Account').click它将等待至less一个创build帐户链接将出现在页面上。 不过,我相信最好select不出现在页面上的唯一定位符两次。

  • fill_in('Password', with: 'secret', exact: true)

    exact: true告诉水豚只能find确切的匹配,即没有find“密码确认”

上面的解决scheme很好,但对于那些好奇的你也可以使用下面的语法。

 click_link(link_name, match: :first) 

您可以在这里find更多信息:

http://taimoorchangaizpucitian.wordpress.com/2013/09/06/capybara-click-link-different-cases-and-solutions/

新答案:

你可以尝试类似的东西

 all('a').select {|elt| elt.text == "#tag1" }.first.click 

可能有办法做到这一点,使更好地使用可用的水豚语法 – 沿all("a[text='#tag1']").first.click但我all("a[text='#tag1']").first.click正确的语法,我无法find适当的文档。 这就是说,开始时有一个奇怪的情况,有两个具有相同idclass和text的<a>标签。 有没有机会他们是不同的divs的孩子,因为你可以在DOM的适当的部分做你的find 。 (这将有助于看到你的HTML源代码)。


老回答:(我认为'#tag1'意思是这个元素的id是“tag1”)

你想点击哪个链接? 如果是第一个(或者没关系),你可以做

 find('#tag1').click 

否则,你可以做

 all('#tag1')[1].click 

点击第二个。

你可以确保你find使用match的第一个:

 find('.selector', match: :first).click 

但重要的是, 你可能不想这样做 ,因为它会导致脆弱的testing ,忽略重复输出的代码异味,这反过来导致错误的肯定 ,当它们应该失败时继续工作,因为你删除了一个匹配元素,但testing愉快地find了另一个。

更好的select是在以下内容中使用:

 within('#sidebar') do find('.selector).click end 

这可以确保您find了期望find的元素,同时仍然利用了Capybara的自动等待和自动重试function(如果使用find('.selector').click ,则会丢失它),并且使它更明确的意图是什么。

为了补充现有的知识体系:

对于JStesting,Capybara必须保持两个线程(一个用于RSpec,一个用于Rails)和第二个进程(浏览器)同步。 它通过在大多数匹配器和节点查找方法中等待(达到configuration的最大等待时间)来完成此操作。

水豚也有方法,不要等待,主要Node#all 。 使用它们就像告诉你的规格,你希望他们间歇性地失败。

接受的答案build议page.first('selector') 。 这是不可取的,至less对于JS规范来说,因为Node#first使用Node#all

也就是说,如果你像这样configurationCapybara, Node#first Node#first等待:

 # rails_helper.rb Capybara.wait_on_first_by_default = true 

这个选项是在Capybara 2.5.0中添加的,默认为false。

正如Andrei所说,你应该改用

 find('selector', match: :first) 

或者改变你的select器。 无论configuration还是驱动程序,它们都能正常工作。

为了进一步复杂化,在老版本的水豚中(或启用了configuration选项), #find会高兴地忽略不明确性,并返回第一个匹配的select器。 这也不是很好,因为它使你的规格不那么明确,我想是为什么不再是默认行为。 我将会忽略具体细节,因为上面已经讨论过了。

更多资源:

由于这篇文章 ,你可以通过“匹配”选项修复它:

 Capybara.configure do |config| config.match = :prefer_exact end 

为了避免在黄瓜模棱两可的错误。

解决scheme1

 first("#tag1").click 

解决scheme2

 Cucumber features/filename.feature --guess