2

我在 Michael Hartl 的 Ruby on Rails 3 教程(本书的早期 Kindle 版本,而不是在线版本)的第 9 章结束时遇到了失败的集成测试 (users_spec.rb)。我一直在寻找一段时间,但到目前为止我发现的建议都没有对我有用。我下载了第一版和第二版教程的源代码,它们运行良好,所以看起来我的应用程序配置有问题,但作为一个rails新手,感觉就像大海捞针所以欢迎任何帮助。

错误消息: ActionController::RoutingError: No route matches [GET] "/signout"

users_spec.rb 包含这个

    ...
       describe "success" do
          it "should sign a user in and out" do
             user = FactoryGirl.create(:user)
             visit signin_path
             fill_in :email, :with => user.email
             fill_in :password, :with => user.password
             click_button
             controller.should be_signed_in
             click_link "Sign out"
             controller.should_not be_signed_in
          end
       end
    ...

我的 application.html.erb 看起来像这样

    <!DOCTYPE html>
    <html>
    <head>
      <title><%= @title %></title>
      <%= javascript_include_tag 'default' %>
      <%= csrf_meta_tags %>
      <%= render 'layouts/stylesheets' %>
    </head>
    <body>
      <div class='container'>
        <%= render 'layouts/header' %>
        <section class = "round">
          <% flash.each do |key, value| %>
            <div class="flash <%= key %>"><%= value %></div>
          <% end %>
          <%= yield %>
        </section>
        <%= render 'layouts/footer' %>
        <%= debug(params) if Rails.env.development? %>
      </div>
    </body>
    </html>

我的 application_controller.rb 看起来像这样

    class ApplicationController < ActionController::Base
      protect_from_forgery
      include SessionsHelper
    end

我的 application.js 看起来像这样

    // This is a manifest file that'll be compiled into application.js, which will include all the files
    // listed below.
    //
    // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
    // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
    //
    // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
    // the compiled file.
    //
    // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
    // GO AFTER THE REQUIRES BELOW.
    //
    //= require jquery
    //= require jquery_ujs
    //= require_tree .

_header.html.erb 文件包含这个

    ...
      <% if signed_in? %>
      <li><%= link_to "Sign out", signout_path, :method => :delete %></li>
      <% else %>
    ...

我的 routes.rb 包含这个

    ...
      get "sessions/new"

      resources :users
      resources :sessions, :only =>[:new, :create, :destroy]

      match '/contact', :to => 'pages#contact'
      match '/about', :to => 'pages#about'
      match '/help', :to => 'pages#help'
      match '/signup', to: 'users#new'

      match '/signin', to: 'sessions#new'
      match '/signout', to: 'sessions#destroy', via: :delete

      root :to => 'pages#home'
    ...

我的 session_controller.rb 包含这个

    ...
      def destroy
        sign_out
        redirect_to root_path
      end
    ...

session_helper.rb 包含这个

    ...
      def sign_out
        cookies.delete(:remember_token)
        @current_user = nil
      end
    ...

这是我执行 rake 路由时得到的

    sessions_new GET    /sessions/new(.:format)   sessions#new
           users GET    /users(.:format)          users#index
                 POST   /users(.:format)          users#create
        new_user GET    /users/new(.:format)      users#new
       edit_user GET    /users/:id/edit(.:format) users#edit
            user GET    /users/:id(.:format)      users#show
                 PUT    /users/:id(.:format)      users#update
                 DELETE /users/:id(.:format)      users#destroy
        sessions POST   /sessions(.:format)       sessions#create
     new_session GET    /sessions/new(.:format)   sessions#new
         session DELETE /sessions/:id(.:format)   sessions#destroy
         contact        /contact(.:format)        pages#contact
           about        /about(.:format)          pages#about
            help        /help(.:format)           pages#help
          signup        /signup(.:format)         users#new
          signin        /signin(.:format)         sessions#new
         signout DELETE /signout(.:format)        sessions#destroy

我的 gemfile 看起来像这样

    source 'https://rubygems.org'

    gem 'rails', '3.2.8'

    gem 'pg'
    gem 'gravatar_image_tag'
    gem 'jquery-rails'

    group :development do
      gem 'rspec-rails'
      gem 'annotate'
    end

    group :test do
      gem 'rspec'
      gem 'webrat'
      gem 'spork'
      gem 'factory_girl_rails'
    end

运行 bundler install 时,我将其作为输出:

    Using rake (0.9.2.2)
    Using i18n (0.6.1)
    Using multi_json (1.3.6)
    Using activesupport (3.2.8)
    Using builder (3.0.4)
    Using activemodel (3.2.8)
    Using erubis (2.7.0)
    Using journey (1.0.4)
    Using rack (1.4.1)
    Using rack-cache (1.2)
    Using rack-test (0.6.2)
    Using hike (1.2.1)
    Using tilt (1.3.3)
    Using sprockets (2.1.3)
    Using actionpack (3.2.8)
    Using mime-types (1.19)
    Using polyglot (0.3.3)
    Using treetop (1.4.11)
    Using mail (2.4.4)
    Using actionmailer (3.2.8)
    Using arel (3.0.2)
    Using tzinfo (0.3.33)
    Using activerecord (3.2.8)
    Using activeresource (3.2.8)
    Using annotate (2.5.0)
    Using diff-lcs (1.1.3)
    Using factory_girl (4.1.0)
    Using rack-ssl (1.3.2)
    Using json (1.7.5)
    Using rdoc (3.12)
    Using thor (0.16.0)
    Using railties (3.2.8)
    Using factory_girl_rails (4.1.0)
    Using gravatar_image_tag (1.1.3)
    Using jquery-rails (2.1.3)
    Using nokogiri (1.5.5)
    Using pg (0.14.1)
    Using bundler (1.2.0)
    Using rails (3.2.8)
    Using rspec-core (2.11.1)
    Using rspec-expectations (2.11.3)
    Using rspec-mocks (2.11.3)
    Using rspec (2.11.0)
    Using rspec-rails (2.11.4)
    Using spork (0.9.2)
    Using webrat (0.7.3)

可能有趣的是,当通过 rails 运行我的应用程序时,它也失败了,所以这不仅仅是 webrat 或失败的集成问题。在 firbug 中查看 html 源代码时,它表明我希望显示的 javascript 不存在

    <script type="text/javascript" src="/assets/jquery.js?body=1">
    <script type="text/javascript" src="/assets/jquery_ujs.js?body=1">

签到状态

单击“退出”时,这是结果 退出失败

4

2 回答 2

0

执行摘要

您使用的是webrat而不是capybara,这可以解释为什么我在下面描述的问题出现了。改变:

gem 'webrat'

gem 'capybara'

在您的 Gemfile 中,删除请求的 javascript 点击处理程序应该可以正常工作。

有关所涉及问题的更深入讨论,请参阅下面的原始答案。

原始答案

这是一个棘手的问题。在我看来,问题在于您的测试没有打开 javascript。

一些背景知识:Rails 使用一个名为jquery-ujs的脚本适配器来执行各种操作,例如强制确认对话框(“您确定吗?”当您尝试删除记录时收到的消息)并从超链接发出非 GET 请求(所以您可以单击“删除”链接,您的浏览器将发送删除请求)。

在您的 routes.rb 中,您有:

signout DELETE /signout(.:format)        sessions#destroy

这就是说:当一个 DELETE 请求到达 URL/signout时,将用户注销。但是,默认情况下,当您单击页面上指向 URL 的链接时/signout,您的浏览器将发送 GET 请求,而不是 DELETE 请求。

当您method: destroy在对此处的调用中包含该选项时link_to

link_to "Sign out", signout_path, :method => :delete

它的作用是告诉 Rails 为data-method="delete"视图中链接的属性添加一个属性(检查实际呈现的 HTML 以确保这是真的)。这个属性就像一个标志:它告诉 jquery-ujs 添加一个单击处理程序,它将对该元素的任何单击从 GET 转换为 DELETE。有关更多详细信息,请参阅这篇文章。另请注意,Hartl 在脚注中提到了这一点。

但是如果在这种情况下没有启用 javascript 会发生什么?好吧,没有添加最后一次点击处理程序,并且您的浏览器将该链接视为/signout页面上的任何其他链接,因此当您单击它时,您会向该 URL 发送 GET 请求。但是 Rails 没有任何 GET 请求的路径/signout,因此它会吐出错误:

ActionController::RoutingError: No route matches [GET] “/signout”

这就是这里出现问题的原因。

现在对于解决方案,我相信您应该能够在测试js: true中添加一个启用 javascript 的选项,如下所示:

it "should sign a user in and out", js: true do
  ...
end

如果您使用的是 Selenium,默认的 javascript 驱动程序,这实际上会打开一个浏览器窗口——要在没有窗口的情况下运行 js 测试,请将 capybara -webkit gem 添加到您的 Gemfile 并使用Capybara.javascript_driver = :webkit. 有关在 Rspec 请求规范中使用 javascript 的详细信息,请参阅此 Railscast中有关测试 javascript 的部分。

于 2012-11-08T21:37:16.397 回答
0

我刚刚注意到您正在使用 webrat:

    group :test do
      gem 'rspec'
      gem 'webrat'
      gem 'spork'
      gem 'factory_girl_rails'
    end

仍然使用 webrat 的该教程的最后一个版本是 3.0,您引用的测试版本来自这里,这意味着您正在尝试遵循较旧的 3.0 教程,而不使用经过测试可以使用的Gemfile

虽然capybara 在处理方面可能存在问题data-method: :delete,因为行为将在下一个主要版本中更改,但这不是您面临的问题。

于 2012-11-09T03:09:11.450 回答