如何使用Capybara 2.0测试页面标题?

时间:2012-11-26 21:34:50

标签: ruby-on-rails rspec capybara

尝试使用以下内容测试该页面包含<title>My Title</title>

# spec/features/reports_spec.rb
require 'spec_helper'

feature "Archive Management" do
  subject { page }

  describe "Index Page" do
    before(:all) { 10.times { FactoryGirl.create(:randomreport) } }
    after(:all) { Report.delete_all }

    describe "when no search terms present" do
      before { visit reports_path }

      it { should have_selector('title', text: 'My Title') } # <= Fails w/Capybara 2.0
      it { should have_selector('title') }                   # <= passes
      it { should have_text('My Title') }                    # <= passes
      it { should have_selector('h2', text: "Welcome") }     # <= passes
    end
  end
end

错误讯息:

 Failure/Error: it { should have_selector('title', text: base_title) }
 Capybara::ExpectationNotMet:
   expected to find css "title" with text "My Title" but there were no matches. Also found "", which matched the selector but not all filters.

我知道我忽略了痛苦的明显但却无法弄清楚它是什么? <title>代码不再被视为“选择者”吗?!?要么...?!?

编辑(调试器信息)

如果我按照@shioyama的巧妙建议进入调试器,很明显page.body包含<title>My Title</title>。包含<h2>Welcome to My Title Project</h2>并传递的同一页面。

它似乎找到了<title> ... </title>标记,但未找到My Title。但它确实在My Title和/或<a href=\"/\" class=\"brand\">My Title</a>内的页面中找到了<h2>Welcome to The My Title Project</h2>

(rdb:1) p page
#<Capybara::Session>
(rdb:1) p page.body
"<!DOCTYPE html>\n<html>\n<head>\n<title>My Title</title>\n
<meta content='research, report, technology' name='keywords'>\n<meta 
content='Some Project' name='description'>\n<link href=\"/assets/application.css\"
...
</head>\n<body>\n<header class='navbar navbar-fixed-top 
navbar-inverse'>\n<div class='navbar-inner'>\n<div class='container'>\n
<a href=\"/\" class=\"brand\">My Title</a>\n<div class='pull-right'>\n
<ul class='nav'>\n<li><a href=\"/about\">About</a></li>\n<li><a href=\"/help\">Help</a>
</li>\n</ul>\n<form accept-charset=\"UTF-8\" action=\"/reports\" 
class=\"navbar-search\" method=\"get\"><div style=\"margin:0;padding:0;display:inline\">
<input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /></div>\n
<input class=\"search-query\" id=\"query\" name=\"query\" 
placeholder=\"Search\" type=\"text\" />\n</form>\n\n</div>\n</div>\n</div>\n</header>\n\n
<div class='container'>\n<div class='hero-unit center'>\n<h1>My Title</h1>\n
<h2>Welcome to The My Title Project</h2>\n<p>Lorem ipsum dolor sit amet, consectetur 
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
...

我还可以在调试器中尝试找出为什么有have_selector?('title',text:...)失败?

那么,在Capybara 2.0中测试标题的正确方法是什么?

6 个答案:

答案 0 :(得分:35)

当我升级到Capybara 2.0时遇到了同样的问题,并设法通过使用Capybara.string创建以下自定义RSpec匹配器来解决这些问题:

<强>规格/支持/ utilities.rb

RSpec::Matchers::define :have_title do |text|
  match do |page|
    Capybara.string(page.body).has_selector?('title', text: text)
  end
end

现在,在subject { page }的spec文件中,我可以使用:

it { should have_title("My Title") }
it { should_not have_title("My Title") }

顺便说一下,关于这个问题的对话对我这个答案非常有帮助,谢谢!

更新1:

如果您不想创建自定义RSpec匹配器,感谢用户this StackOverflow answerdimuch我现在知道您可以直接在page.source上致电have_selector(别名page.body)来测试不可见的DOM元素:

it "should show the correct title" do
  page.source.should have_selector('title', text: 'My Title')
end

subject { page }

its(:source) { should have_selector('title', text: 'My Title') }

更新2:

从Capybara 2.1开始,内置have_title / has_title?匹配器,在此答案中无需使用自定义RSpec匹配器。此外,更新1中描述的its(:source) { ... }测试似乎在Capybara 2.1下打破;我已按预期确认have_title / has_title?工作,因此如果您计划升级,最好采用以下语法:

subject { page }时:

it { should have_title("My Title") }
it { should_not have_title("My Title") }

expect / it块中使用scenario语法时:

expect(page).to have_title("My Title")
expect(page).to_not have_title("My Title")

答案 1 :(得分:3)

Capybara 2.1改变了对查询标题元素的支持。因此,使用选择器以这种方式查询html doc头部中的title元素将失败“page.should have_selector('title',:text =&gt;'some text')。从我理解的首选在capybara中的方法2.1新的API是使用“page.should have_title('Some text')”来查询title元素应该有效。

答案 2 :(得分:3)

我将capybara从版本1.x升级到&gt;时遇到了同样的问题。 2.0

问题是Capybara在其匹配器中忽略了隐形文本。解决此问题的最简单方法是在finder上使用:visible => false选项。

e.g。

it { should have_selector('title', text: 'My Title', visible: false) }

另一个(全局)选项是设置:

Capybara.ignore_hidden_elements = false

答案 3 :(得分:2)

我在使用'shared_examples_for'时遇到此问题,可能是因为其他更改。我还注意到,当我将

<title>My Title</title>
放在页面主体中(它不属于且不会渲染)时,测试通过了。不是一件好事!

这有效:

it{should have_title("My Title")}

(水豚2.1.0, launchy 2.3.0, nokogiri 1.5.9, rspec 2.13)

答案 4 :(得分:1)

我在这里看到两个可能的问题:

  1. 页面上显示<title>标记,但文字My Title位于页面上的其他位置,而不在标记内。这可以解释为什么其他测试通过:页面上有一个<title>标记,have_selector('title')通过,页面上有My Title文字,have_text(base_title)通过。
  2. <title>标记包含文字My Title以及其他内容,这也可以解释您看到的结果:页面上有<title>标记,因此{{1}传递,并且文本have_selector('title')因此My Title也传递,但have_text(base_title)中的text选项是严格的,因此如果它找到一个字符串,它将失败并不完全等于have_selector
  3. 您可以使用xpath选择器检查后两种可能性:My Title。如果它通过了,那么你的标题文本周围可能会有一些空格或换行符should have_xpath("//title[contains(.,'#{base_title}')]")绊倒(我认为它忽略了那些,但我可能错了)。

    希望有所帮助。

答案 5 :(得分:0)

我知道这已有一个已接受的答案,但是对于它的价值,你可以用更少的代码行完成以下工作:

title = first("head title").native.text
expect(title).to == "What you expect it to match"

这允许访问本机驱动程序元素;此外,由于Capybara 2.0忽略了不可见的文本(标题除浏览器外不可见),您需要这个(或类似的解决方法)来满足这种情况。 (见https://github.com/jnicklas/capybara/issues/863