Capybara的名字"名称"找不到按钮。属性

时间:2014-03-13 06:49:49

标签: html ruby-on-rails ruby capybara integration-testing

W3C验证的HTML 5网页在登录表单中包含这个工作简单的按钮。

<input data-disable-with="Signing in, please wait&amp;hellip;"
       name="commit" type="submit" value="Sign in" />

我在一个Rails 3.2.17应用程序中编写了一个毫无意义的测试:-)只是为了获得Capybara的支持而且我已经完全陷入谷歌搜索,阅读文档和将源代码读入测试框架,没有任何乐趣 - 尝试通过name(即"commit")找到此按钮失败。

click_button("commit")
find_button("commit")

两者都会产生Capybara::ElementNotFound: Unable to find button "commit"。如果我使用Sign in的可见按钮文本,则找到元素 ,即:

click_button("Sign in")
find_button("Sign in")

...两者都运行良好,因此看起来XML解析器在查找元素时没有任何问题。

click_button的文档说明定位器在&#34; id,text或value&#34;上使用&#34; text&#34;对于这样的input元素没有意义(可见文本取自value属性),但可能与button元素相关。因此,我们可能希望失败,但如果我们通过文档查看代码,则会发现它以与find相同的方式调用find_button。然而,find_button的记录不同;它说它位于&#34; id,name或value&#34;。很遗憾,我们从中知道文档被破坏了因为它说明了两个不同的事情,后者在后端被称为相同的呼叫。

无论哪种方式,都不会按名称找到该元素,这意味着我认为较低级find调用不会搜索name属性。这意味着Capybara(2.2.1,Nokogiri 1.6.1)在这方面相当破碎。怎么没有人注意到?我用谷歌搜索了很长时间,似乎没有出现。我似乎很想念这一点: - )

为什么我不想在按钮中搜索英文文本,你可能会问?因为国际化。这个旧的,Rails 1 - &gt; 2 - &gt; 3升级的应用程序有一些I18n部分和其他静态文本部分。我不想被迫将I18n放入Capybara测试的任何视图中,这样我就可以使用I18n.t()来确保匹配,尽管语言或语言环境文件更新不同。同样,在2014年将硬编码的英文字符串写入我的测试中显然是非常愚蠢的。

这就是为什么我们有名字和身份证等等......理所当然的(在理论上!)标识符是机器读取的,而不是人工读取的。

我可以通过&#34; type = submit&#34;来解决CSS选择的问题。但严重的是,为什么Capybara在其文档说明时没有搜索name属性,为什么文档不同意在两个方法上搜索哪些属性,这些方法调用完全相同的后端实现完全相同参数Δ

TIA:)

6 个答案:

答案 0 :(得分:15)

事实证明,两个调用的文档都是误导性的,因为它们都没有查看列出的属性。显而易见的是,“按钮”的含义显然非常令人困惑,因为这里的几个人似乎认为它只是意味着HTML button元素,但事实并非如此。

如果您查看文档的来源,例如click_button

https://github.com/jnicklas/capybara/blob/a94dfbc4d07dcfe53bbea334f7f47f584737a0c0/lib/capybara/node/actions.rb#L36

...你会看到这只是调用(正如我在别处提到的那样)到find的{​​{1}}类型,后者又传递给Capybara的:button引擎反过来,它最终只是使用标准的内部选择机制来查找事物。它非常优雅;与外部客户端可以添加自己的自定义选择器以使查找更方便的方式相同:

http://rubydoc.info/github/jnicklas/capybara/master/Capybara#add_selector-class_method

...所以Capybara在内部添加了自己的选择器,重要的是,Query

https://github.com/jnicklas/capybara/blob/a94dfbc4d07dcfe53bbea334f7f47f584737a0c0/lib/capybara/selector.rb#L133

它不是由任何特殊情况魔法完成的,只是一些预定义的自定义选择器。因此,如果您一直想知道在Capybara中可以使用哪些自定义选择器,那就是要阅读的文件(它可能也被隐藏在文档中但我自己还没有找到该列表)。

在这里,我们看到按钮代码实际上是调用:button,这是不同存储库中的不同代码块,带有以下文档:

http://rdoc.info/github/jnicklas/xpath/XPath/HTML#button-instance_method

...在编写时略微过时了,因为代码显示了很多被识别的内容,包括XPath::HTML.button类型的input和{ {1}}(即reset而不是button,但当然也包括<input type="button"...>

https://github.com/jnicklas/xpath/blob/59badfa50d645ac64c70fc6a0c2f7fe826999a1f/lib/xpath/html.rb#L22

我们还可以在此代码中看到,finder方法实际上只能通过<button...>...</button>id value 找到 - 即 by“text”和 not by name。

因此,假设XPath按预期运行,虽然从文档中不清楚,我们可以看到Capybara没有正确记录自己,但可能应该将链接转换为XPath API以获取更多信息,以避免当前重复信息以及这可能对维护者和API客户造成的问题。

与此同时,我提出了这个问题:

https://github.com/jnicklas/capybara/issues/1267

答案 1 :(得分:9)

您也可以使用css选择器作为默认的capybara定位器。人们说他们更快。

find('[name=commit]').click

Capybara不会在其查找器中查看name属性:(

答案 2 :(得分:6)

如果需要,可以使用xpath选择器

find(:xpath, "//input[contains(@name, 'commit')]").click()

答案 3 :(得分:2)

如果有人想要,可以通过名称选择器添加(非常容易)找到。为此:

将以下代码添加到test/test_helper.rb(最小的)

Capybara.add_selector(:name) do
  xpath { |name| XPath.descendant[XPath.attr(:name).contains(name)] }
end

使用

现在,在测试中,您可以使用以下选择器:

find(:name, 'part_of_the_name_attribute')

它将找到name属性包含搜索值的每个元素。

实施例

find(:name, 'user')

这将找到元素(元素可以是任何类型):

<select name='user_name'>
<input name='name_of_user'>
<textarea name='some_user_info'>

答案 4 :(得分:0)

您可以使用此选择器在页面上找到RSpec和Capybara的按钮:

expect(page).to have_selector(:link_or_button, "Button text")

答案 5 :(得分:0)

检查您的宝石相关性。 RSpec 3或更高版本适用于gem'rspec-rails','〜&gt; 3.7.1'那么水豚版必须是宝石'capybara','〜&gt; 2.18.0'并且poltergeist应该是宝石'poltergeist','〜&gt; 1.17.0'。