Capybara / rspec: should GET / PUT tests be in different files?

I am following Ruby on Rails Tutorial and now I need to write tests for authorization code like. making sure users can only edit their profile.

There are two steps to test. One of them is to prevent the user from accessing the edit page of other users' profile. This simple, simple "special" test in capybara.

But I also want to test the PUT action so that the user cannot manually submit a PUT request without going through the edit page. From what I've read, this should be done as a test of the rspec request.

Now my question is, do I need to support them in different categories? (spec / features vs spec / requests)? This is wrong because the two scenarios are closely related. How are tests like this usually done in Rails?

For example,

describe "as wrong user" do
  let(:user) { FactoryGirl.create(:user) }
  let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
  before { sign_in user }

  describe "visiting Users#edit page" do
    before { visit edit_user_path(wrong_user) }
    it { should_not have_selector('title', text: full_title('Edit user')) }
  end

  describe "submitting a PUT request to the Users#update action" do
    before { put user_path(wrong_user) }
    specify { response.should redirect_to(root_path) }
  end
end

      

The second test does not work in capybara 2.x as "put" is no longer supported. It should be a request. And now I need to write a second sign_in method, since the current one uses methods available only for testing functions. Smells like a lot of code duplication.

======== my solution ========

After figuring out how to enter the query test, thanks to Paul Fioravanti,

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

      

I changed all tests to request tests. So I don't need to split them into different files. Paul's solution will also work, although I think it's cleaner.

describe 'authorization' do
  describe 'as un-signed-in user' do
    let(:user) { FactoryGirl.create(:user) }

    describe 'getting user edit page' do
      before { get edit_user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end
  end

  describe 'as wrong user' do
    let(:user) { FactoryGirl.create(:user) }
    let(:wrong_user) { FactoryGirl.create(:user, email: 'wrong@example.com') }

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

    describe 'getting user edit page' do
      before { get edit_user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end
  end
end

      

+3


source to share


2 answers


I ended the arduous process of separating my requests and feature specs after I finished the Rails tutorial and updated my Sample app to Capybara 2.0. Since you say you are still doing this tutorial, I would suggest that you just save the gems that Hartl points out (Capybara 1.1.2), terminate your Sample application, and then return to the queries / function issue as a refactoring exercise. For your reference, however, this is how I ended up writing my "wrong user" specifications:

specs / support / utilities.rb

def sign_in_through_ui(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign In"
end

def sign_in_request(user)
  post session_path(email: user.email, password: user.password)
  cookies[:remember_token] = user.remember_token
end

RSpec::Matchers::define :have_title do |text|
  match do |page|
    Capybara.string(page.body).has_selector?('title', text: text)
  end
end

      

specs / features / authentication_pages_spec.rb

describe "Authentication on UI" do

  subject { page }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before do
        visit root_path
        click_link "Sign In"
        sign_in_through_ui(user)
      end

      context "visiting Users#edit" do
        let(:page_title) { full_title("Edit User") }
        before { visit edit_user_path(wrong_user) }
        it { should_not have_title(page_title) }
      end
    end
  end
end

      

<strong> specs / requests / authentication_requests_spec.rb



describe "Authentication Requests" do

  subject { response }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before { sign_in_request(user) }

      context "PUT Users#update" do
        before { put user_path(wrong_user) }
        it { should redirect_to(root_url) }
      end
    end

  end
end

      

I mainly used the following two links as a reference while trying to figure out how to separate my specs feature

from my specs request

:

Update:

If you don't need a custom RSpec mapper, you can also use the following in the tests above to get the same result on an element title

:

its(:source) { should have_selector('title', text: page_title) }

      

+2


source


According to Jnicklas ( https://github.com/jnicklas/capybara ) you should move all the Capybare specs you have in spec / request to spec / features as spec / will now be used by Capybara 2.x. So this means that once you've moved Capybara's specs to functions, you can remove those specs entirely from the spec / requests directory.

Personally, I completed the Ruby on Rails tutorial without any problem. I used Capybara 2.x and never used spec / features (just "old" specs / requests). For Rspec 2.x support, you need to add require> 'capybara / rspec' <to your spec_helper.rb file. Without this, your tests might fail.

Edit:

I just read the Rspec docs. If you use Capybara in your specs, those specs need to be migrated to specs / functions. If Capybara is not involved, the specifications may simply remain in your request directory.



Specifications https://www.relishapp.com/rspec/rspec-rails/v/2-12-2/docs/feature-specs/feature-spec !

Request specifications https://www.relishapp.com/rspec/rspec-rails/v/2-12-2/docs/request-specs

More information, from Rubydoc: http://rubydoc.info/github/jnicklas/capybara/master#Using_Capybara_with_RSpec

+1


source







All Articles