【问题标题】:Hartl's Ruby on Rails Tutorial test failing (chapter 9)Hartl 的 Ruby on Rails 教程测试失败(第 9 章)
【发布时间】:2013-11-14 21:23:12
【问题描述】:

我正在学习 Hartl 著名的 Ruby on Rails 4 教程。我不是 Rails 新手,但我是测试新手:RSpec、Capybara、FactoryGirl 等。我在第 9 章 (http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-users#sec-successful_edits) 中发现的编辑用户的测试特别有问题。我将首先发布我尝试补救的内容,然后发布相关代码:

  1. 与教程相比,我三次检查了我的代码。一切看起来都不错,但我可能遗漏了一些东西。
  2. 重新启动我的服务器并重置、重新填充并重新设置测试数据库。
  3. 在 FF 中使用 SQLite Manager 扩展检查测试和开发 SQLite 数据库中的用户。

以下是错误:

1) Authentication Signin page with valid information followed by signout 
 Failure/Error: before { click_link "Sign Out" }
 Capybara::ElementNotFound:
   Unable to find link "Sign Out"
 # ./spec/requests/authentication_pages_spec.rb:41:in `block (5 levels) in <top (required)>'

 2) UserPages edit with invalid information 
 Failure/Error: before { click_button "Save changes" }
 Capybara::ElementNotFound:
   Unable to find button "Save changes"
 # ./spec/requests/user_pages_spec.rb:130:in `block (4 levels) in <top (required)>'

3) UserPages edit page 
 Failure/Error: it { should have_title("Edit user") }
   expected #has_title?("Edit user") to return true, got false
 # ./spec/requests/user_pages_spec.rb:125:in `block (4 levels) in <top (required)>'

4) UserPages edit page 
 Failure/Error: it { should have_content("Update your profile") }
   expected #has_content?("Update your profile") to return true, got false
 # ./spec/requests/user_pages_spec.rb:124:in `block (4 levels) in <top (required)>'

5) UserPages edit page 
 Failure/Error: it { should have_link('change', href: 'http://gravatar.com/emails') }
   expected #has_link?("change", {:href=>"http://gravatar.com/emails"}) to return true, got false
 # ./spec/requests/user_pages_spec.rb:126:in `block (4 levels) in <top (required)>'

6) UserPages edit with valid information 
 Failure/Error: fill_in "Name",             with: new_name
 Capybara::ElementNotFound:
   Unable to find field "Name"
 # ./spec/requests/user_pages_spec.rb:138:in `block (4 levels) in <top (required)>'

7) UserPages edit with valid information 
 Failure/Error: fill_in "Name",             with: new_name
 Capybara::ElementNotFound:
   Unable to find field "Name"
 # ./spec/requests/user_pages_spec.rb:138:in `block (4 levels) in <top (required)>'

8) UserPages edit with valid information 
 Failure/Error: fill_in "Name",             with: new_name
 Capybara::ElementNotFound:
   Unable to find field "Name"
 # ./spec/requests/user_pages_spec.rb:138:in `block (4 levels) in <top (required)>'

9) UserPages edit with valid information 
 Failure/Error: fill_in "Name",             with: new_name
 Capybara::ElementNotFound:
   Unable to find field "Name"
 # ./spec/requests/user_pages_spec.rb:138:in `block (4 levels) in <top (required)>'

10) UserPages edit with valid information 
 Failure/Error: fill_in "Name",             with: new_name
 Capybara::ElementNotFound:
   Unable to find field "Name"
 # ./spec/requests/user_pages_spec.rb:138:in `block (4 levels) in <top (required)>'

最初,我认为这是 Capybara 的问题,但我不确定。这是测试代码(在 ./spec/requests/user_pages_spec.rb 中找到):

describe "edit", :js => true do
  let(:user) { FactoryGirl.create(:user) }
  before do
    sign_in user
    visit edit_user_path(user)
  end

  describe "page" do
    it { should have_content("Update your profile") }
    it { should have_title("Edit user") }
    it { should have_link('change', href: 'http://gravatar.com/emails') }
  end

  describe "with invalid information" do
    before { click_button "Save changes" }
    it { should have_content('error') }
  end

  describe "with valid information" do
    let(:new_name)  { "New Name" }
    let(:new_email) { "new@example.com" }
    before do
      fill_in "Name",             with: new_name
      fill_in "Email",            with: new_email
      fill_in "Password",         with: user.password
      fill_in "Confirm Password", with: user.password
      click_button "Save changes"
    end

    it { should have_title(new_name) }
    it { should have_selector('div.alert.alert-success') }
    it { should have_link('Sign Out', href: signout_path) }
    specify { expect(user.reload.name).to  eq new_name }
    specify { expect(user.reload.email).to eq new_email }
  end
end

我添加到初始描述块:js =&gt; true,因为我认为这是 Capybara 问题并且页面加载太快,但是,添加该哈希导致 FF 浏览器打开,我可以观察发生了什么... FactoryGirl 已成功创建用户,但在尝试登录时收到无效的电子邮件或密码错误。因此无法登录,因此编辑表单的所有测试均失败。这是相关的 FactoryGirl 代码:

./spec/utilities.rb 中的sign_in() 助手:

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

./spec/factories.rb:

FactoryGirl.define do
  factory :user do
    sequence(:name)  { |n| "Person #{n}" }
    sequence(:email) { |n| "person_#{n}@example.com"}
    password "foobar"
    password_confirmation "foobar"

    factory :admin do
      admin true
    end
  end
end

我正确安装了 gem,而且 FactoryGirl 似乎可以在其他测试中正常工作,这是 gemfile:

group :test do
  gem 'selenium-webdriver', '2.35.1'
  gem 'capybara', '2.1.0'
  gem 'growl', '1.0.3'
  gem 'factory_girl_rails', '4.2.1'
end

就像我说的,我查看了 SQLite 开发和测试数据库,但在测试数据库中没有看到任何用户。 FactoryGirl 是否只是临时为测试创建一个用户,然后在完成后回滚?什么可能导致我看到的登录失败?还是我还缺少其他东西?

如果有人问,以下是相关观点:

edit.html.erb:

<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="span6 offset3">
    <%= form_for(@user) do |f| %>
    <%= render 'shared/error_messages' %>

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

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

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

    <%= f.label :password_confirmation, "Confirm Password" %>
    <%= f.password_field :password_confirmation %>

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

  <%= gravatar_for @user %>
  <a href="http://gravatar.com/emails">change</a>
</div>

以及在application.html.erb中渲染的_header.html.erb

<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="navbar-inner">
    <div class="container">
      <%= link_to "sample app", root_path, id: "logo" %>
      <nav>
        <ul class="nav pull-right">
          <li><%= link_to "Home", root_path %></li>
          <li><%= link_to "Help", help_path %></li>
          <% if signed_in? %>
            <li><%= link_to "Users", users_path %></li>
            <li id="fat-menu" class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                Account <b class="caret"></b>
              </a>
              <ul class="dropdown-menu">
                <li><%= link_to "Profile", current_user %></li>
                <li><%= link_to "Settings", edit_user_path(current_user) %></li>
                <li class="divider"></li>
                <li>
                  <%= link_to "Sign Out", signout_path, method: "delete" %>
                </li>
              </ul>
            </li>
          <% else %>
            <li><%= link_to "Sign In", signin_path %></li>
          <% end %>
        </ul>
      </nav>
    </div>
  </div>
</header>

【问题讨论】:

  • #1 规范错误在哪里?我假设那是登录有问题的那个?错误 2-11 很可能是由它引起的,所以如果我们能看到/修复它,其他错误可能会到位。
  • 是的,如果在 context/describe 块内的 before 块中完成,FactoryGirl 会为特定测试或测试块创建用户。一旦完成,工厂就会被摧毁。
  • 对不起,我应该说,错误1与同一个测试无关,但可能是由同一个问题引起的:1)身份验证登录页面具有有效信息,后跟注销失败/错误:之前{ click_link "Sign Out" } Capybara::ElementNotFound: Unable to find link "Sign Out" # ./spec/requests/authentication_pages_spec.rb:41:in `block (5 levels) in '跨度>
  • 不用担心。我没有看到用户登录时出现错误。您在哪里看到这个问题?
  • 当我通过命令行运行我的所有测试时,一旦它到达describe 'edit' 块,它就会启动firefox,我可以看到它做了什么(因为我添加了哈希:js => true )。我实时观看它尝试使用 FG 生成的用户登录并收到“无效的电子邮件或密码”错误。

标签: ruby-on-rails rspec capybara factory-bot


【解决方案1】:

您遇到的第一个错误很可能是因为您需要将 describe "followed by signout" 嵌套在 describe "after saving the user" 中,如下所示:

 describe "after saving the user" do
        before { click_button submit }
        let(:user) { User.find_by(email: 'user@example.com') }

        it { should have_link('Sign out') }
        it { should have_title(user.name) }
        it { should have_selector('div.alert.alert-success', text: 'Welcome') }
        describe "followed by signout" do #Notice that this describe is inside the other one
            before { click_link "Sign out" }
            it { should have_link('Sign in') }
        end
end

我知道这只是部分答案,但很难一次解决所有问题。解决此问题后,再次运行测试并告诉我保留哪些错误代码。我会尝试进一步帮助你。

(至少如果这解决了你的第一个问题,它可能是别的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多