【问题标题】:How can I test the page title with Capybara 2.0?如何使用 Capybara 2.0 测试页面标题?
【发布时间】:2012-11-26 21:34:49
【问题描述】:

尝试测试该页面是否包含<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.

我知道我忽略了令人痛苦的显而易见但无法弄清楚它是什么? &lt;title&gt; 标签不再被视为“选择器”吗?!?或者...?!?

编辑(调试器信息)

如果我按照@shioyama 的巧妙建议进入调试器,很明显 page.body 包含&lt;title&gt;My Title&lt;/title&gt;。包含&lt;h2&gt;Welcome to My Title Project&lt;/h2&gt; 的同一个page.body 并通过!

它似乎在其中找到了&lt;title&gt;...&lt;/title&gt; 标签,但没有找到My Title。但它确实在页面后面的&lt;a href=\"/\" class=\"brand\"&gt;My Title&lt;/a&gt; 和/或&lt;h2&gt;Welcome to The My Title Project&lt;/h2&gt; 中找到My Title

(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 中测试标题的正确方法是什么?

【问题讨论】:

  • 如果您尝试should have_xpath("//title[contains(.,'#{base_title}')]") 会怎样?
  • @shioyama - 这行得通!我仍然有兴趣找出为什么 have_selector 对我工作...
  • 嗯...这个 xpath 正在测试 &lt;title&gt; 标签 包含 文本。也许有空格或换行符使选择器绊倒?我以为它忽略了这些,但我可能是错的。
  • 我已经更新了我的答案,见下文。
  • 好的,看来这是 2.0 的一个已知“问题”...github.com/jnicklas/capybara/issues/844

标签: ruby-on-rails rspec capybara


【解决方案1】:

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

spec/support/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 } 的规范文件中,我可以使用:

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

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

更新 1:

如果您不想创建自定义 RSpec 匹配器,感谢 this StackOverflow answer by user dimuch 我现在知道您可以直接在 page.source(别名为 page.body)上调用 have_selector 来测试不可见的 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") }

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

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

【讨论】:

  • 感谢您的解决方案...我也在测试更新操作,但我收到“NoMethodError: undefined method put”...有什么建议吗? ...谢谢。
  • @railguage48,您可能需要考虑提出一个单独的问题,因为如果没有更多详细信息,我们无法判断您的问题是什么。
  • 根据@Paul Fioravanti Update 2,我将以下内容与 Capybara 2.1(和 RSpec 2.12)一起使用:expect(response.body).to have_title('my title') 这对我来说很好。
  • page.should have_selector('title', text: 'My Title', visible: false) 也可以。事实上,传递visible: false 适用于任何需要匹配隐藏内容的选择器。所以虽然has_title 匹配标题更优雅,但如果您需要匹配其他隐藏内容,请使用visible: false。使用期望语法:expect(response.body).to have_selector('title', text: 'my title', visible: false)
【解决方案2】:

Capybara 2.1 更改了对查询标题元素的支持。因此,使用 have selector in 以这种方式查询 html 文档头部的标题元素将失败“page.should have_selector('title', :text => 'Some text')。据我了解首选方法在 capybara 2.1 中的新 API 是使用“page.should have_title('Some text')”来查询标题元素应该可以工作。

【讨论】:

    【解决方案3】:

    我在将 capybara 从版本 1.x 升级到 > 2.0 时遇到了同样的问题

    问题在于 Capybara 忽略了匹配器中的不可见文本。解决此问题的最简单方法是在查找器上使用:visible =&gt; false 选项。

    例如

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

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

    Capybara.ignore_hidden_elements = false

    【讨论】:

      【解决方案4】:

      我只在使用“shared_examples_for”时遇到了这个问题,可能是因为其他更改。我还注意到,当我放置

      &lt;title&gt;My Title&lt;/title&gt;
      在页面正文中(它不属于并且不会呈现),测试通过了。不是什么好事!

      这行得通:

      it{should have_title("My Title")}

      (水豚 2.1.0, 启动 2.3.0, nokogiri 1.5.9, rspec 2.13)

      【讨论】:

        【解决方案5】:

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

        1. &lt;title&gt; 标记出现在页面上,但文本 My Title 位于页面的其他位置,而不是在标记内。这可以解释为什么其他测试通过了:页面上有一个&lt;title&gt; 标记,所以have_selector('title') 通过,页面上有My Title 文本,所以have_text(base_title) 通过。
        2. &lt;title&gt; 标记包含文本 My Title 以及其他内容,这也可以解释您看到的结果:页面上有一个 &lt;title&gt; 标记所以 have_selector('title') 通过,并且有文本My Title 所以have_text(base_title) 也通过了,但是have_selector 中的text 选项是严格的,因此如果找到不完全等于My Title 的字符串,它将失败。

        您可以使用 xpath 选择器检查这两种可能性中的后者:should have_xpath("//title[contains(.,'#{base_title}')]")。如果通过了,那么您的标题文本周围可能有一些空格或换行符,这会使 have_selector 跳闸(我认为它忽略了这些,但我可能错了)。

        希望对您有所帮助。

        【讨论】:

        • 是的,但是...我可以验证 &lt;title&gt;My Title&lt;/title&gt; 存在于正在测试的页面上,并且已经使用 save_and_open_page 这样做了,所以 之间有 <i>is</i> 文本标签。
        • 我可以删除 base_title 这样它就不会分散注意力,并用 'My Title' 替换它,它仍然不会通过。我可以看到没有不必要的空白(除非由于某些莫名其妙的原因,那里有导致测试失败的控制字符)。我认为这是与 Capybara 2.0 更改有关的语义/语法问题,但我无法弄清楚...
        • 这越来越奇怪了,但我发现如果我用subject { page.body } 替换subject { page },那么所有规范都通过了......这很讽刺,因为&lt;title&gt;... 标签在&lt;head&gt; 中标签而不是&lt;body&gt;!?!或者,我可以用body.should ... 替换should ...,它会通过。到底发生了什么,为什么没有记录?我太大了一个 RSpec 新手,无法将我的头全部包裹起来......
        • page.body 中的 body 不是 HTML 正文(即 &lt;body&gt; 标签中的内容),而是 response 的正文(一个字符串),其中包括完整的 HTML。所以这并不奇怪。 page 本身就是Capybara::Session 的一个实例,所以是完全不同类型的对象。
        • 更新:我现在已经确认我在控制台上面观察到的内容也适用于 Capybara 2.0.1。所以我不知道你的情况是怎么回事,但我建议在你的 Gemfile 中添加 debugger,并在你的测试中添加一行 require 'debugger'; debugger'。然后您可以进行实验,例如p page.has_selector?('title') 等(p = 打印)。
        【解决方案6】:

        我知道这已经有一个公认的答案,但是对于它的价值,您可以用更少的代码行来执行以下操作:

        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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-09-05
          • 2014-05-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多