Capybara填写错误的字段

时间:2013-02-14 08:10:13

标签: ruby-on-rails ruby-on-rails-3 rspec capybara integration-testing

奇怪的问题。

我正在尝试使用Capybara和RSpec测试登录,但似乎Capybara填写了错误的字段,因此登录的用户未经过身份验证。

我使用FactoryGirl创建了测试用户:

#factories.rb

FactoryGirl.define do

    #...

    factory :user do
        name "guest"
        password "pwordtest"
        password_confirmation "pwordtest"
    end

end

然后我编写了以下测试(其中有很多“puts”内容用于调试此问题):

#posts_spec.rb

describe "Valid post submission" do

 it "should log in a user and let him make a post" do
  User.destroy_all
  visit '/access' #My Login page
  user = FactoryGirl.create(:user)
  puts "name"
  puts user.name
  fill_in :name, with: "guest" # I did these literally to make sure FactoryGirl wasn't the problem.
  fill_in :password, with: "pwordtest"
  click_on "Log In"
  assert User.count == 1
  puts "authing test"
  current_path.should eq(new_post_path)
 end
#...
end

在我的会话控制器中(更多调试版):

def create
    user = User.find_by_name(params[:name])
    puts "all"
    puts params
    puts "pre-inspect"
    puts user.inspect
    if user && user.authenticate(params[:password])
        session[:user_id] = user.id
      puts "In IF"
        redirect_to new_post_path
    else
        flash.now[:error] = "Invalid password/username combo."
      puts "there"
        render 'new' 
    end
  end

当我尝试运行测试时,出现以下错误:

name
guest
all
{"utf8"=>"✓", "name"=>"pword", "password"=>"", "commit"=>"Log In", "action"=>"create", "controller"=>"sessions"}
pre-inspect
nil
there
authing test
F

Failures:

  1) Posts Valid post submission should log in a user and let him make a post
     Failure/Error: current_path.should eq(new_post_path)

       expected: "/posts/new"
            got: "/sessions"

       (compared using ==)
     # ./spec/requests/posts_spec.rb:28:in `block (3 levels) in <top (required)>'

换句话说,我的调试提示表明FactoryGirl用户很好,但不知何故,Capybara未能将这些值分配给正确的字段,因此params(在调试打印中的“all”之后)被赋值为“pword” “作为名称和”“作为密码,而不是”客人“作为名称和”pword“作为密码。因此,测试用户未经过身份验证,并且未启动会话。这特别奇怪,因为字段肯定是正确命名的:

#sessions/new.html.erb

<div class="center_login">
    <h1>Log In</h1>
    <%= form_tag sessions_path do %>
      <div class="field">
        <%= label_tag :name %>
        <%= text_field_tag :name, params[:name] %><br />
      </div>
      <div class="field">
        <%= label_tag :password %>
        <%= password_field_tag :password %><br />
      </div><br>
      <div class="actions"><%= submit_tag "Log In", class: "btn" %></div>
    <% end %>
</div>

知道发生了什么事吗?另外两个人和我搞乱了一个小时+并且无法理解它。

编辑 - 应该提到的是,当我作为一个真实的人浏览网站时,这一切都完美无缺。就像在,我在名称字段中输入的用户名和我在密码字段中输入的密码对应于数据库中的用户名,我已经登录了。因此,我怀疑一些水豚未能填写正确的东西是错误的。

EDIT 2 - 每个请求下面一个测试的Test.log输出:

Connecting to database specified by database.yml
  [1m[36m (0.4ms)[0m  [1mbegin transaction[0m
Started GET "/posts/new" for 127.0.0.1 at 2013-02-14 07:29:55 -0800
Processing by PostsController#new as HTML
Redirected to http://www.example.com/
Filter chain halted as :authorize rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2013-02-14 07:29:55 -0800
Processing by StaticsController#resume as HTML
  Rendered statics/_stars.html.erb (1.0ms)
  Rendered statics/_stars.html.erb (0.4ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_stars.html.erb (0.3ms)
  Rendered statics/_skills.html.erb (14.9ms)
  Rendered statics/_collapse_start.html.erb (0.6ms)
  Rendered statics/_collapse_start.html.erb (0.1ms)
  Rendered statics/_collapse_start.html.erb (0.1ms)
  Rendered statics/_collapse_start.html.erb (0.1ms)
  Rendered statics/_collapse_start.html.erb (0.1ms)
  Rendered statics/resume.html.erb within layouts/application (68.4ms)
  Rendered layouts/_shim.html.erb (0.2ms)
  Rendered layouts/_header.html.erb (1.0ms)
Completed 200 OK in 163ms (Views: 162.3ms | ActiveRecord: 0.0ms)
  [1m[35mUser Load (12.1ms)[0m  SELECT "users".* FROM "users" 
Started GET "/access" for 127.0.0.1 at 2013-02-14 07:29:55 -0800
Processing by SessionsController#new as HTML
  Rendered sessions/new.html.erb within layouts/application (1.2ms)
  Rendered layouts/_shim.html.erb (0.0ms)
  Rendered layouts/_header.html.erb (0.5ms)
Completed 200 OK in 32ms (Views: 32.1ms | ActiveRecord: 0.0ms)
  [1m[36m (0.1ms)[0m  [1mSAVEPOINT active_record_1[0m
  [1m[35mUser Exists (0.1ms)[0m  SELECT 1 AS one FROM "users" WHERE LOWER("users"."name") = LOWER('guest') LIMIT 1
Binary data inserted for `string` type on column `password_digest`
  [1m[36mSQL (30.0ms)[0m  [1mINSERT INTO "users" ("created_at", "name", "password_digest", "updated_at") VALUES (?, ?, ?, ?)[0m  [["created_at", Thu, 14 Feb 2013 15:29:55 UTC +00:00], ["name", "guest"], ["password_digest", "$2a$10$Y9NfnYjForrfufZOaqgQj.BdcHYLh.tkYomCVfHiJ4McbWMem445e"], ["updated_at", Thu, 14 Feb 2013 15:29:55 UTC +00:00]]
  [1m[35m (0.1ms)[0m  RELEASE SAVEPOINT active_record_1
Started POST "/sessions" for 127.0.0.1 at 2013-02-14 07:29:55 -0800
Processing by SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "name"=>"pword", "password"=>"[FILTERED]", "commit"=>"Log In"}
  [1m[36mUser Load (0.1ms)[0m  [1mSELECT "users".* FROM "users" WHERE "users"."name" = 'pword' LIMIT 1[0m
  Rendered sessions/new.html.erb within layouts/application (0.7ms)
  Rendered layouts/_shim.html.erb (0.0ms)
  Rendered layouts/_header.html.erb (0.5ms)
Completed 200 OK in 21ms (Views: 2.7ms | ActiveRecord: 0.1ms)
  [1m[35m (0.1ms)[0m  SELECT COUNT(*) FROM "users" 
  [1m[36m (0.5ms)[0m  [1mrollback transaction[0m

正如您所看到的,从底部传递给会话控制器6ish行的“参数”包括名称“pword”(以及过滤的,可能是空的密码),这很奇怪/令人沮丧。

编辑3 - 在我的测试组中使用最新版本的Capybara。在这篇新帖子中,我在另一个控制器的规范中遇到了一个基本相同的问题。也就是说,我告诉Capybara用“A”填写字段1,用“B”填写3,用“C”填写3,并且来自该控制器的参数将显示1填充“B”,2填充“C” “并且3空了,就好像Capybara将之前的每个字段填写到我告诉它的那个或其他东西。

编辑4 - 根据Dave S的建议,我拍摄了登录过程的截图(以及发布过程,如编辑2中所述,具有相同的错误)。

正在发生两件不同的事情!在登录页面中,它看起来像(因为密码被阻止),它实际上填写了正确的信息(name == guest,密码==五颗星,这与密码(和访客)的字符数相同) ),但是如果我保存一个页面而不是屏幕截图并点击进入,它会转到会话和错误,就像测试人员一样。

在我保存的页面/发布页面的屏幕截图中,Capybara肯定填写了错误的字段。名称字段填充了我所说的内容,内容字段为空。我认为这是因为我为登录创建了新的唯一ID,而不是发布,我会看到如果我这样做会发生什么。我也会在密码时将密码更改为与“访客”不同的密码,然后再回报。

编辑5 - 新截图:

enter image description here

enter image description here

这两个视图的代码,让我们了解这里可能会有什么不同。 (我还更改了上面的工厂代码,以便从屏幕截图中的(正确的)密码长度中理解。

# new posts _form.html.erb
<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, id: "post_name" %>
  </div>
  <div class="field text-area">
    <%= f.label :content %><br />
    <%= f.text_area(:content, :size => '50x20', id: "post_content") %>
  </div>

    <div class="actions btn-group">
      <%= f.submit 'Post It', class: "btn" %>
    </div>

<% end %>

登录:

# login (new.html.erb in sessions)

<div class="center_login">
    <h1>Log In</h1>
    <%= form_tag sessions_path do %>
      <div class="field">
        <%= label_tag :name %>
        <%= text_field_tag :name, params[:name], id: "sessions_name" %><br /> 
        # The above name change seemed to possibly fix it. The weird thing, though, is that
        # a similar change in the posts form above did NOT fix that problem.
      </div>
      <div class="field">
        <%= label_tag :password %>
        <%= password_field_tag :password %><br />
      </div><br>
      <div class="actions"><%= submit_tag "Log In", class: "btn" %></div>
    <% end %>
</div>

现在(登录名为seesions_name),登录工作100%。参数是正确的,等等。但发布没有,因为(尽管我做了基本相同的改变),Capybara仍然填补了错误的领域。这是否会使问题更清楚?我很难过。

编辑6 - 可以找到完整的回购here

2 个答案:

答案 0 :(得分:0)

我在测试我的应用程序的登录功能时遇到了类似的问题:我手动登录时工作正常,但使用Capybara进行测试时登录失败。

你似乎遇到了一些我没有的问题,即Capybara填写错误的字段。我不确定那是什么原因,但你可能遇到了不止一个问题。经过调试,我发现我的问题是由于一个有缺陷的用户工厂造成的。

我的意思是:

要求'digest / sha1'

FactoryGirl.define do
  factory :user do
    login      'hitchcock'
    fname      'Alfred'
    lname      'Hitchcock'
    email      'alfred.hitchcock@example.com'
    password   Digest::SHA1.new << 'MacGuffin'
  end
end

设置密码的字段不正确。这是正确的版本:

    password   (Digest::SHA1.new << 'MacGuffin').to_s

类User的“password”字段实际上包含密码摘要,而不是密码,但我正在使用旧数据库。在任何情况下,我都错误地计算了密码的摘要,忘记了to_s方法,这导致我的测试用例使用用户名'hitchcock'和密码'MacGuffin'进行登录尝试失败。

现在,看着你的工厂,在我看来你可能会遇到类似的问题。您的迁移文件20130206234907_create_users.rb如下所示:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :password_digest
      t.timestamps
    end
  end
end

表示您正在存储密码的摘要,而不是密码本身,这是正确的。但是,文件factories.rb中的用户工厂是:

factory :user do
  name "guest"
  password "pwordtest"
  password_confirmation "pwordtest"
end

您的工厂没有为其创建的用户指定password_digest字段,因此当您在posts_spec.rb中通过命令创建用户时

user = FactoryGirl.create(:user)

我想知道是否在数据库中创建了一个用户,或者是否是,password_digest字段将是什么?请记住,在运行测试时,首先会清除测试数据库的内容,因此如果您的测试代码未在数据库中创建有效用户,则您的登录测试将无法正常工作。

答案 1 :(得分:0)

我遇到了这个问题:使用fill_in时填充了错误的字段。

解决方案是遵循文档并使用字符串代替匹配符号:

我替换了这个:

fill_in :email, with: email
fill_in :password, with: password

使用:

fill_in "Email", with: email
fill_in "Password", with: password

然后它按预期工作

文档:https://github.com/jnicklas/capybara#using-capybara-with-rspec