【问题标题】:Capybara not matching radio buttons in rspec test水豚在 rspec 测试中与单选按钮不匹配
【发布时间】:2018-05-29 19:15:12
【问题描述】:

我正在尝试使用 rspec 为 Bootstrap 表单编写测试。我有以下代码:

<div id="published" class="col-sm-auto">
  <div class="custom-control custom-radio custom-control-inline">
    <%= form.radio_button :published, true, checked: page.published?, class: 'custom-control-input' %>
    <%= form.label :published, 'Published', value: true, class: 'custom-control-label' %>
  </div>
  <div class="custom-control custom-radio custom-control-inline">
    <%= form.radio_button :published, false, checked: !page.published?, class: 'custom-control-input' %>
    <%= form.label :published, 'Hidden', value: false, class: 'custom-control-label' %>
  </div>
</div>

生成以下 HTML:

<div id="published" class="col-sm-auto">
  <div class="custom-control custom-radio custom-control-inline">
    <input class="custom-control-input" type="radio" value="true" name="page[published]" id="page_published_true" />
    <label class="custom-control-label" for="page_published_true">Published</label>
  </div>
  <div class="custom-control custom-radio custom-control-inline">
    <input class="custom-control-input" type="radio" value="false" checked="checked" name="page[published]" id="page_published_false" />
    <label class="custom-control-label" for="page_published_false">Hidden</label>
  </div>
</div>

当我运行此测试时,它失败并显示消息

it 'should default to unpublished' do
  expect(page).to have_checked_field('Hidden')
end

给消息expected to find visible field "page[published]" that is checked and not disabled but there were no matches. Also found "", "", which matched the selector but not all filters.

在检查器中查看 HTML,该字段可见且未禁用,并且有一个与文本匹配的标签。我不知道这两个空字符串是关于什么的。

请有人告诉我为什么have_checked_field 不匹配?我真的不热衷于编写使用has_csshas_xpath 来查找具有特定ID 的输入标签的更脆弱的测试——重点是用户应该看到一个标有“隐藏”的字段,它应该被检查,不管幕后发生了什么!

【问题讨论】:

  • 您确定该字段在视口中实际可见吗?您是否在未能确认时捕获屏幕截图和/或 HTML?

标签: ruby rspec capybara


【解决方案1】:

我会 99.9% 向您保证,无线电输入实际上是不可见的,并且已被使用 CSS(可能还有一些 JS)的图像所取代。你可以这样做

expect(page).to have_checked_field('Hidden', visible: false)

或者你可以做一些稍微复杂的事情来验证标签实际上是可见的,比如

expect(page).to have_css('input:checked + label', exact_text: 'Hidden')

如果您要处理大量此类单选按钮,另一种解决方案是编写自定义选择器类型,例如

Capybara.add_selector(:bootstrap_radio) do 
  xpath do |locator|
    XPath.descendant(:input)[XPath.attr(:type) == 'radio'].following_sibling(:label)[XPath.string.n.is(locator)]
  end

  filter(:checked) do |node, value|
    node.sibling('input[type="radio"]', visible: :hidden).checked? == value
  end
end

然后你就可以这样做

expect(page).to have_selector(:bootstrap_radio, 'Hidden', checked: true)

然后如果需要,您可以编写像 have_checked_bootstrap_radio 这样的辅助方法。注意:这段代码是即兴的,所以 XPath/CSS 表达式可能不是 100% 正确,但总体思路是合理的 :)

【讨论】:

  • 谢谢——我还没有检查过这个,但我怀疑这就是 Bootstrap 所做的。今晚我会试一试,如果可以的话,我会把它标记为已接受。 spec_helper.rb 是自定义选择器的最佳位置吗?
  • @JohnY 当使用自定义选择器时,我通常将它们放在它们自己的文件中,然后在 Capybara 被包含在 rails_helper 中之后需要它们,无论是明确地还是通过 spec/support/**/* 包含。只要 Capybara 已经加载,spec_helper 也可以工作。
  • 谢谢——前两种方法有效,但我从自定义选择器中得到了Capybara::ElementNotFound: Unable to find non-visible css "input[type=\"radio\"]" that is a sibling of visible bootstrap_radio "Hidden"。我不确定这是否是因为 Bootstrap 4 将 z-index 设置为 -1 而不是设置 visibility: hidden
  • @JohnY 然后尝试在过滤器中更改为visible: :all 而不是visible: :hidden。也不要忘记接受答案(复选标记),这样问题就会被标记为已回答。
猜你喜欢
  • 1970-01-01
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多