1

我正在关注 Railstutorial(第 9 章)“删除链接”的测试第一次通过,但从下一次开始出现某种错误,例如:

Failures:

  1) User pages index delete links as an admin user 
     Failure/Error: sign_in admin
     Capybara::ElementNotFound:
       Unable to find field "Email"
     # ./spec/support/utilities.rb:20:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:38:in `block (5 levels) in <top (required)>'

  2) User pages index delete links as an admin user 
     Failure/Error: sign_in admin
     Capybara::ElementNotFound:
       Unable to find field "Email"
     # ./spec/support/utilities.rb:20:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:38:in `block (5 levels) in <top (required)>'

  3) User pages index delete links as an admin user should be able to delete another user
     Failure/Error: sign_in admin
     Capybara::ElementNotFound:
       Unable to find field "Email"
     # ./spec/support/utilities.rb:20:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:38:in `block (5 levels) in <top (required)>'

Finished in 0.81336 seconds
4 examples, 3 failures

Failed examples:

rspec ./spec/requests/user_pages_spec.rb:48 # User pages index delete links as an admin user 
rspec ./spec/requests/user_pages_spec.rb:42 # User pages index delete links as an admin user 
rspec ./spec/requests/user_pages_spec.rb:43 # User pages index delete links as an admin user should be able to delete another user

Randomized with seed 11884

这是 utilities.rb文件的内容

include ApplicationHelper

def full_title(page_title)
  base_title = "Welcome to Family & Friends"
  if page_title.empty?
    base_title
  else
    " #{base_title} | #{page_title} "
  end
end

def sign_in(user, options={})
  if options[:no_capybara]
    # Sign in when not using Capybara.
    remember_token = User.new_remember_token
    cookies[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
  else
    visit signin_path
    fill_in "Email",    with: user.email
    fill_in "Password", with: user.password
    click_button "Sign in"
  end
end

错误指示的 user_pages_spec.rb 文件的一部分

describe "delete links" do

      it { should_not have_link('delete') }

      describe "as an admin user" do
        let(:admin) { FactoryGirl.create(:admin) }
        before do
          sign_in admin
          visit users_path
        end

        it { should have_link('delete', href: user_path(User.first)) }
        it "should be able to delete another user" do
          expect do
            click_link('delete', match: :first)
          end.to change(User, :count).by(-1)
        end
        it { should_not have_link('delete', href: user_path(admin)) }
      end
    end
  end

session_helper.rb 文件,其中存在 sign_in 的定义

module SessionsHelper

  def sign_in(user)
    remember_token = User.new_remember_token
    cookies.permanent[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
    self.current_user = user
  end

  def signed_in?
    !current_user.nil?
  end

  def current_user=(user)
    @current_user = user
  end

  def current_user
    remember_token = User.encrypt(cookies[:remember_token])
    @current_user ||= User.find_by(remember_token: remember_token)
  end

   def current_user?(user)
    user == current_user
  end

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

  def redirect_back_or(default)
    redirect_to(session[:return_to] || default)
    session.delete(:return_to)
  end

  def store_location
    session[:return_to] = request.url if request.get?
  end
end

我什至尝试过类似帖子中建议的 fill_in "email_id" 但在这种情况下不起作用

谢谢!!

这是 html 为登录而呈现的 new.html.erb 的内容

<% provide(:title, "Sign in") %>
<h2>Sign in</h2>

<div class="row">
  <div class="span6 offset3">
    <%= form_for(:session, url: sessions_path) do |f| %>

      <%= f.label :email %>
      <%= f.text_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
    <% end %>

    <p>New user? <%= link_to "Sign up now!", signup_path %></p>
  </div>
</div>
4

2 回答 2

3

老问题,但我在完成教程时也遇到了这个问题。使测试混乱的是前面示例中的状态泄漏到“作为管理员用户”示例中。

describe "User Pages" do

  subject { page }

    describe "index" do
      let(:user) { FactoryGirl.create(:user) }

        # This is messing up the lower examples
        before(:each) do
          sign_in user
          visit users_path
        end

要查看实际情况,您可以在调用 sign_in 助手之前在 before 块中添加visit signin_paththen 。save_and_open_page

describe "as an admin user" do
  let(:admin) { FactoryGirl.create(:admin) }
    before do
      visit signin_path
      save_and_open_page
      sign_in admin
      visit users_path
    end

当我的浏览器呈现页面时,我发现以前登录的用户从未退出,因此访问登录页面只会将您重定向到该用户的个人资料页面,并且用户个人资料页面上没有电子邮件字段。这就是Capybara报道的原因Unable to find field "Email"

为了解决这个问题,我在实用程序.rb 文件中添加了一个 sign_out 助手。

def sign_out
  first(:link, "Sign Out").click
end

我之前sign_in admin在示例中调用它

describe "as an admin user" do
  let(:admin) { FactoryGirl.create(:admin) }
    before do
      sign_out
      sign_in admin
      visit users_path
    end

在此之后我所有的测试都通过了。

于 2014-04-14T17:50:34.063 回答
2

我也有这个问题。不幸的是,我也无法让建议的 sign_out 函数工作。尽管 save_and_open_page (在安装 gem "launchy" 之后)显示了一个 "Sign Out" 链接,但测试报告它在页面上找不到一个。我最终解决了如下测试:

  1. 我将“删除链接”块完全移出“索引”块。
  2. 我在新的“删除链接”块开始时重新创建了 30 个测试用户
  3. 我将非管理员用户页面上没有删除链接的测试移回“分页”块内的新块。

(当然,还有两个谜团:1)我不知道为什么代码可能会按照书中显示的方式工作。那么为什么不是所有阅读本书的人都有这个问题呢?2) 为什么我的sign_out 函数找不到在带有save_and_open_page 的页面上清楚显示的“退出”链接。有时您只需要继续前进即可继续取得进步。至少它现在有效。)

这是进行这些更改后的代码。它现在通过了所有测试:

  describe "index" do
    let(:user) { FactoryGirl.create(:user) }

    before(:each) do
      sign_in user
      visit users_path
    end

    it { should have_title('All users') }
    it { should have_content('All users') }

    describe "pagination" do

      before(:all) { 30.times { FactoryGirl.create(:user) } }
      after(:all)  { User.delete_all }

      it { should have_selector('div.pagination') }

      it "should list each user" do
        User.paginate(page: 1).each do |user|
          expect(page).to have_selector('li', text: user.name)
        end
      end

      describe "non-admin user should not have delete links" do
        it { should_not have_link('delete', href: user_path(User.first)) }
      end
    end
  end


  # fhj: I could not get this to work as done in the book (i.e. placing this
  # above inside the "index" block). It could not execute sign_in admin
  # because it was already signed in as a non-admin user. I tried the
  # suggestion to create a sign_out helper function, but I could not make
  # that work either. By moving it outside of the block and recreating
  # the 30 test users, I was able to get it to pass the tests.
  # I also created the "non-admin user should not have delete links" block
  # at the end of the "pagination" block above to test for that case properly.
  describe "delete links" do

    before(:all) { 30.times { FactoryGirl.create(:user) } }
    after(:all)  { User.delete_all }

    describe "as an admin user" do
      let(:admin) { FactoryGirl.create(:admin) }
      before do
        sign_in admin
        visit users_path
      end

      it { should have_link('delete', href: user_path(User.first)) }
      it "should be able to delete another user" do
        expect do
          click_link('delete', match: :first)
        end.to change(User, :count).by(-1)
      end
      it { should_not have_link('delete', href: user_path(admin)) }
    end
  end
于 2014-07-21T16:16:56.730 回答