【问题标题】:Feature test with Capybara and Rspec - clicking buttons doesn't redirect to the right route使用 Capybara 和 Rspec 进行功能测试 - 单击按钮不会重定向到正确的路线
【发布时间】:2014-12-10 23:46:58
【问题描述】:

我正在使用 Rspec 3.0 和 capybara 2.4.3。我在 spec/features/ 中制作了一个名为 challenge_users_spec.rb 的功能规范

require "rails_helper"

feature "Challenge users" do
  let!(:challenge) { create(:challenge)}
  let(:user) { create(:user)}

  context "as a registered user" do
    before :each do
      sign_in(user)
    end

    scenario "challenges himself" do

      expect(current_path).to eq root_path
      expect(page).to have_content challenge.name

      click_button 'Accept'

      expect(page).to have_content 'You accepted the challenge!'
      expect(user.accepted_dares.count).to eq 1
    end

    scenario 'challenges other user' do
      expect(current_path).to eq root_path

      click_button 'Challenge others'

      expect(current_path).to eq new_challenge_dare_path(challenge_id: challenge.id)
      expect(page).to have_content 'Challenge with a bet!'
    end
  end
end

在第一种情况下,页面呈现正确的 flash msg 但不更新用户。 在第二种情况下,单击“挑战其他人”后,current_path 设置为“/”而不是“挑战/:id/dares/new”,因此未能达到最后两个预期。 Dares 模型是嵌套路由:

  resources :challenges do
    resources :dares
  end

控制器方法大多是标准的CRUD方法。

这是 Rspec 日志:

Failures:

  1) Challenge users as a registered user challenges himself
     Failure/Error: expect(user.accepted_dares.count).to eq 1

       expected: 1
            got: 0

       (compared using ==)
     # ./spec/features/challenge_users_spec.rb:18:in `block (3 levels) in <top (required)>'

  2) Challenge users as a registered user challenges other user
     Failure/Error: expect(current_path).to eq new_challenge_dare_path(challenge_id: challenge.id)

       expected: "/challenges/2/dares/new"
            got: "/"

       (compared using ==)
     # ./spec/features/challenge_users_spec.rb:26:in `block (3 levels) in <top (required)>'

Finished in 0.91199 seconds (files took 3.62 seconds to load)
2 examples, 2 failures

Failed examples:

rspec ./spec/features/challenge_users_spec.rb:10 # Challenge users as a registered user challenges himself
rspec ./spec/features/challenge_users_spec.rb:21 # Challenge users as a registered user challenges other user

型号:

class Dare < ActiveRecord::Base

  belongs_to :challenge, counter_cache: true
  belongs_to :acceptor, class_name: "User"
  belongs_to :challenger, class_name: "User"

  has_many :votes

  before_save :change_status
  before_save :create_start_date
  before_save :set_proof_array

  def set_proof_array
    if self.utube_link.nil?
      self.utube_link = []
      save!
    end
  end

  def create_start_date
    if status == 'Accepted' && start_date.blank?
      self.start_date = DateTime.now
    end
  end

  def change_status
    if status.blank?
      if self.acceptor_id == self.challenger_id
        self.status = "Accepted"
      else
        self.status = "Pending"
      end
    end
  end
...
end

用户

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :dares, foreign_key: :challenger_id
  has_many :accepted_dares, class_name: "Dare", foreign_key: :acceptor_id
  has_many :challenges, through: :dares
  has_many :votes

  validates :username, presence: true, uniqueness: true, length: { in: 2..50 }

    ....
end

挑战

class Challenge < ActiveRecord::Base

  has_many :dares
  has_many :users, through: :dares, source: :challenges

  validates :name, presence: true, uniqueness: true, length: { in: 5..100 }
  validates :description, presence: true, length: { in: 10..500 }

  include PgSearch
  pg_search_scope :search, against: [:name, :description],
                  using: {tsearch: {prefix: true, dictionary: "english" }}
  ...

end

编辑

我没有提到这一点,但我在我的应用程序中使用了 Turbolinks。 将 js:true 添加到我的测试后,第二个测试通过但第一个仍然抛出错误:

1) Challenge users as a registered user challenges himself
     Failure/Error: expect(user.reload.accepted_dares.count).to eq 1

       expected: 1
            got: 0

       (compared using ==)

【问题讨论】:

  • 您可以添加您的模型进行验证吗?
  • 按要求添加模型

标签: ruby-on-rails rspec capybara


【解决方案1】:

这是两个不相关的问题。

用户模型不更新的原因是它在内存中是一个完全独立的实例,与在后端更改的实例完全不同。您需要强制它从数据库中重新加载:

expect(user.reload.accepted_dares.count).to eq 1

current_path 没有给您预期值的原因是click_button 是一个异步操作。您对current_path 的断言将在单击按钮后立即执行,在新页面有机会加载之前。

Capybara 的许多操作(例如find)会自动等待并重试,直到条件变为真(在find 的情况下,它会等待选择器匹配页面上的某些内容),但是因为current_path 没有'没有任何条件,它会立即返回当前值(Capybara 不知道在调用方法时你期望当前路径是什么)。

更好的测试方法是寻找一些您希望仅在单击按钮并重新加载页面后才会出现在页面上的内容。这迫使 Capybara 在继续之前等待该内容。

在这种情况下,颠倒您拥有的两个断言的顺序应该可以解决问题:

expect(page).to have_content 'Challenge with a bet!'
expect(current_path).to eq new_challenge_dare_path(challenge_id: challenge.id)

【讨论】:

  • 仍然收到相同的错误消息 -> 失败/错误:expect(user.reload.accepted_dares.count).to eq 1 expected: 1 got: 0
  • 通过使用您的提示并添加 js:true 使第二个测试通过。是因为我使用的是 turbolinks 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多